diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2014-06-11 13:29:05 +0000 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2014-06-11 13:29:05 +0000 |
commit | 7043c30e0e55bbbfacdddf97619b6bae96d20ddb (patch) | |
tree | ece3254350b3ba01ba3135caed2364cc7ca7804c /libs | |
parent | bbb44cf245c11bc0c1d59e836007c9e8c3bfa209 (diff) |
build: introduce luci-base
Merges libs/core, libs/ipkg, libs/web, libs/sys, libs/sgi-cgi, libs/sgi-uhttpd,
modules/admin-core, themes/base and protcols/core into modules/base and renames
luci-lib-core to luci-base.
Diffstat (limited to 'libs')
110 files changed, 0 insertions, 16863 deletions
diff --git a/libs/core/Makefile b/libs/core/Makefile deleted file mode 100644 index f7fac7740e..0000000000 --- a/libs/core/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../../build/config.mk -include ../../build/module.mk diff --git a/libs/core/luasrc/ccache.lua b/libs/core/luasrc/ccache.lua deleted file mode 100644 index 56ccbc3efe..0000000000 --- a/libs/core/luasrc/ccache.lua +++ /dev/null @@ -1,87 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -Copyright 2008 Steven Barth <steven@midlink.org> -Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ -]]-- - -local io = require "io" -local fs = require "nixio.fs" -local util = require "luci.util" -local nixio = require "nixio" -local debug = require "debug" -local string = require "string" -local package = require "package" - -local type, loadfile = type, loadfile - - -module "luci.ccache" - -function cache_ondemand(...) - if debug.getinfo(1, 'S').source ~= "=?" then - cache_enable(...) - end -end - -function cache_enable(cachepath, mode) - cachepath = cachepath or "/tmp/luci-modulecache" - mode = mode or "r--r--r--" - - local loader = package.loaders[2] - local uid = nixio.getuid() - - if not fs.stat(cachepath) then - fs.mkdir(cachepath) - end - - local function _encode_filename(name) - local encoded = "" - for i=1, #name do - encoded = encoded .. ("%2X" % string.byte(name, i)) - end - return encoded - end - - local function _load_sane(file) - local stat = fs.stat(file) - if stat and stat.uid == uid and stat.modestr == mode then - return loadfile(file) - end - end - - local function _write_sane(file, func) - if nixio.getuid() == uid then - local fp = io.open(file, "w") - if fp then - fp:write(util.get_bytecode(func)) - fp:close() - fs.chmod(file, mode) - end - end - end - - package.loaders[2] = function(mod) - local encoded = cachepath .. "/" .. _encode_filename(mod) - local modcons = _load_sane(encoded) - - if modcons then - return modcons - end - - -- No cachefile - modcons = loader(mod) - if type(modcons) == "function" then - _write_sane(encoded, modcons) - end - return modcons - end -end diff --git a/libs/core/luasrc/debug.lua b/libs/core/luasrc/debug.lua deleted file mode 100644 index 8ff1bb6981..0000000000 --- a/libs/core/luasrc/debug.lua +++ /dev/null @@ -1,37 +0,0 @@ -local debug = require "debug" -local io = require "io" -local collectgarbage, floor = collectgarbage, math.floor - -module "luci.debug" -__file__ = debug.getinfo(1, 'S').source:sub(2) - --- Enables the memory tracer with given flags and returns a function to disable the tracer again -function trap_memtrace(flags, dest) - flags = flags or "clr" - local tracefile = io.open(dest or "/tmp/memtrace", "w") - local peak = 0 - - local function trap(what, line) - local info = debug.getinfo(2, "Sn") - local size = floor(collectgarbage("count")) - if size > peak then - peak = size - end - if tracefile then - tracefile:write( - "[", what, "] ", info.source, ":", (line or "?"), "\t", - (info.namewhat or ""), "\t", - (info.name or ""), "\t", - size, " (", peak, ")\n" - ) - end - end - - debug.sethook(trap, flags) - - return function() - debug.sethook() - tracefile:close() - end -end - diff --git a/libs/core/luasrc/fs.lua b/libs/core/luasrc/fs.lua deleted file mode 100644 index a81ff675d4..0000000000 --- a/libs/core/luasrc/fs.lua +++ /dev/null @@ -1,244 +0,0 @@ ---[[ -LuCI - Filesystem tools - -Description: -A module offering often needed filesystem manipulation functions - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local io = require "io" -local os = require "os" -local ltn12 = require "luci.ltn12" -local fs = require "nixio.fs" -local nutil = require "nixio.util" - -local type = type - ---- LuCI filesystem library. -module "luci.fs" - ---- Test for file access permission on given path. --- @class function --- @name access --- @param str String value containing the path --- @return Number containing the return code, 0 on sucess or nil on error --- @return String containing the error description (if any) --- @return Number containing the os specific errno (if any) -access = fs.access - ---- Evaluate given shell glob pattern and return a table containing all matching --- file and directory entries. --- @class function --- @name glob --- @param filename String containing the path of the file to read --- @return Table containing file and directory entries or nil if no matches --- @return String containing the error description (if no matches) --- @return Number containing the os specific errno (if no matches) -function glob(...) - local iter, code, msg = fs.glob(...) - if iter then - return nutil.consume(iter) - else - return nil, code, msg - end -end - ---- Checks wheather the given path exists and points to a regular file. --- @param filename String containing the path of the file to test --- @return Boolean indicating wheather given path points to regular file -function isfile(filename) - return fs.stat(filename, "type") == "reg" -end - ---- Checks wheather the given path exists and points to a directory. --- @param dirname String containing the path of the directory to test --- @return Boolean indicating wheather given path points to directory -function isdirectory(dirname) - return fs.stat(dirname, "type") == "dir" -end - ---- Read the whole content of the given file into memory. --- @param filename String containing the path of the file to read --- @return String containing the file contents or nil on error --- @return String containing the error message on error -readfile = fs.readfile - ---- Write the contents of given string to given file. --- @param filename String containing the path of the file to read --- @param data String containing the data to write --- @return Boolean containing true on success or nil on error --- @return String containing the error message on error -writefile = fs.writefile - ---- Copies a file. --- @param source Source file --- @param dest Destination --- @return Boolean containing true on success or nil on error -copy = fs.datacopy - ---- Renames a file. --- @param source Source file --- @param dest Destination --- @return Boolean containing true on success or nil on error -rename = fs.move - ---- Get the last modification time of given file path in Unix epoch format. --- @param path String containing the path of the file or directory to read --- @return Number containing the epoch time or nil on error --- @return String containing the error description (if any) --- @return Number containing the os specific errno (if any) -function mtime(path) - return fs.stat(path, "mtime") -end - ---- Set the last modification time of given file path in Unix epoch format. --- @param path String containing the path of the file or directory to read --- @param mtime Last modification timestamp --- @param atime Last accessed timestamp --- @return 0 in case of success nil on error --- @return String containing the error description (if any) --- @return Number containing the os specific errno (if any) -function utime(path, mtime, atime) - return fs.utimes(path, atime, mtime) -end - ---- Return the last element - usually the filename - from the given path with --- the directory component stripped. --- @class function --- @name basename --- @param path String containing the path to strip --- @return String containing the base name of given path --- @see dirname -basename = fs.basename - ---- Return the directory component of the given path with the last element --- stripped of. --- @class function --- @name dirname --- @param path String containing the path to strip --- @return String containing the directory component of given path --- @see basename -dirname = fs.dirname - ---- Return a table containing all entries of the specified directory. --- @class function --- @name dir --- @param path String containing the path of the directory to scan --- @return Table containing file and directory entries or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -function dir(...) - local iter, code, msg = fs.dir(...) - if iter then - local t = nutil.consume(iter) - t[#t+1] = "." - t[#t+1] = ".." - return t - else - return nil, code, msg - end -end - ---- Create a new directory, recursively on demand. --- @param path String with the name or path of the directory to create --- @param recursive Create multiple directory levels (optional, default is true) --- @return Number with the return code, 0 on sucess or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -function mkdir(path, recursive) - return recursive and fs.mkdirr(path) or fs.mkdir(path) -end - ---- Remove the given empty directory. --- @class function --- @name rmdir --- @param path String containing the path of the directory to remove --- @return Number with the return code, 0 on sucess or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -rmdir = fs.rmdir - -local stat_tr = { - reg = "regular", - dir = "directory", - lnk = "link", - chr = "character device", - blk = "block device", - fifo = "fifo", - sock = "socket" -} ---- Get information about given file or directory. --- @class function --- @name stat --- @param path String containing the path of the directory to query --- @return Table containing file or directory properties or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -function stat(path, key) - local data, code, msg = fs.stat(path) - if data then - data.mode = data.modestr - data.type = stat_tr[data.type] or "?" - end - return key and data and data[key] or data, code, msg -end - ---- Set permissions on given file or directory. --- @class function --- @name chmod --- @param path String containing the path of the directory --- @param perm String containing the permissions to set ([ugoa][+-][rwx]) --- @return Number with the return code, 0 on sucess or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -chmod = fs.chmod - ---- Create a hard- or symlink from given file (or directory) to specified target --- file (or directory) path. --- @class function --- @name link --- @param path1 String containing the source path to link --- @param path2 String containing the destination path for the link --- @param symlink Boolean indicating wheather to create a symlink (optional) --- @return Number with the return code, 0 on sucess or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -function link(src, dest, sym) - return sym and fs.symlink(src, dest) or fs.link(src, dest) -end - ---- Remove the given file. --- @class function --- @name unlink --- @param path String containing the path of the file to remove --- @return Number with the return code, 0 on sucess or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -unlink = fs.unlink - ---- Retrieve target of given symlink. --- @class function --- @name readlink --- @param path String containing the path of the symlink to read --- @return String containing the link target or nil on error --- @return String containing the error description on error --- @return Number containing the os specific errno on error -readlink = fs.readlink diff --git a/libs/core/luasrc/init.lua b/libs/core/luasrc/init.lua deleted file mode 100644 index 4d66e86734..0000000000 --- a/libs/core/luasrc/init.lua +++ /dev/null @@ -1,39 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -Description: -Main class - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local require = require - --- Make sure that bitlib is loaded -if not _G.bit then - _G.bit = require "bit" -end - -module "luci" - -local v = require "luci.version" - -__version__ = v.luciversion or "trunk" -__appname__ = v.luciname or "LuCI" diff --git a/libs/core/luasrc/ip.lua b/libs/core/luasrc/ip.lua deleted file mode 100644 index 60ca090135..0000000000 --- a/libs/core/luasrc/ip.lua +++ /dev/null @@ -1,673 +0,0 @@ ---[[ - -LuCI ip calculation libarary -(c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> -(c) 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI IP calculation library. -module( "luci.ip", package.seeall ) - -require "nixio" -local bit = nixio.bit -local util = require "luci.util" - ---- Boolean; true if system is little endian -LITTLE_ENDIAN = not util.bigendian() - ---- Boolean; true if system is big endian -BIG_ENDIAN = not LITTLE_ENDIAN - ---- Specifier for IPv4 address family -FAMILY_INET4 = 0x04 - ---- Specifier for IPv6 address family -FAMILY_INET6 = 0x06 - - -local function __bless(x) - return setmetatable( x, { - __index = luci.ip.cidr, - __add = luci.ip.cidr.add, - __sub = luci.ip.cidr.sub, - __lt = luci.ip.cidr.lower, - __eq = luci.ip.cidr.equal, - __le = - function(...) - return luci.ip.cidr.equal(...) or luci.ip.cidr.lower(...) - end - } ) -end - -local function __array16( x, family ) - local list - - if type(x) == "number" then - list = { bit.rshift(x, 16), bit.band(x, 0xFFFF) } - - elseif type(x) == "string" then - if x:find(":") then x = IPv6(x) else x = IPv4(x) end - if x then - assert( x[1] == family, "Can't mix IPv4 and IPv6 addresses" ) - list = { unpack(x[2]) } - end - - elseif type(x) == "table" and type(x[2]) == "table" then - assert( x[1] == family, "Can't mix IPv4 and IPv6 addresses" ) - list = { unpack(x[2]) } - - elseif type(x) == "table" then - list = { unpack(x) } - end - - assert( list, "Invalid operand" ) - - return list -end - -local function __mask16(bits) - return bit.lshift( bit.rshift( 0xFFFF, 16 - bits % 16 ), 16 - bits % 16 ) -end - -local function __not16(bits) - return bit.band( bit.bnot( __mask16(bits) ), 0xFFFF ) -end - -local function __maxlen(family) - return ( family == FAMILY_INET4 ) and 32 or 128 -end - -local function __sublen(family) - return ( family == FAMILY_INET4 ) and 30 or 127 -end - - ---- Convert given short value to network byte order on little endian hosts --- @param x Unsigned integer value between 0x0000 and 0xFFFF --- @return Byte-swapped value --- @see htonl --- @see ntohs -function htons(x) - if LITTLE_ENDIAN then - return bit.bor( - bit.rshift( x, 8 ), - bit.band( bit.lshift( x, 8 ), 0xFF00 ) - ) - else - return x - end -end - ---- Convert given long value to network byte order on little endian hosts --- @param x Unsigned integer value between 0x00000000 and 0xFFFFFFFF --- @return Byte-swapped value --- @see htons --- @see ntohl -function htonl(x) - if LITTLE_ENDIAN then - return bit.bor( - bit.lshift( htons( bit.band( x, 0xFFFF ) ), 16 ), - htons( bit.rshift( x, 16 ) ) - ) - else - return x - end -end - ---- Convert given short value to host byte order on little endian hosts --- @class function --- @name ntohs --- @param x Unsigned integer value between 0x0000 and 0xFFFF --- @return Byte-swapped value --- @see htonl --- @see ntohs -ntohs = htons - ---- Convert given short value to host byte order on little endian hosts --- @class function --- @name ntohl --- @param x Unsigned integer value between 0x00000000 and 0xFFFFFFFF --- @return Byte-swapped value --- @see htons --- @see ntohl -ntohl = htonl - - ---- Parse given IPv4 address in dotted quad or CIDR notation. If an optional --- netmask is given as second argument and the IP address is encoded in CIDR --- notation then the netmask parameter takes precedence. If neither a CIDR --- encoded prefix nor a netmask parameter is given, then a prefix length of --- 32 bit is assumed. --- @param address IPv4 address in dotted quad or CIDR notation --- @param netmask IPv4 netmask in dotted quad notation (optional) --- @return luci.ip.cidr instance or nil if given address was invalid --- @see IPv6 --- @see Hex -function IPv4(address, netmask) - address = address or "0.0.0.0/0" - - local obj = __bless({ FAMILY_INET4 }) - - local data = {} - local prefix = address:match("/(.+)") - address = address:gsub("/.+","") - address = address:gsub("^%[(.*)%]$", "%1"):upper():gsub("^::FFFF:", "") - - if netmask then - prefix = obj:prefix(netmask) - elseif prefix then - prefix = tonumber(prefix) - if not prefix or prefix < 0 or prefix > 32 then return nil end - else - prefix = 32 - end - - local b1, b2, b3, b4 = address:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$") - - b1 = tonumber(b1) - b2 = tonumber(b2) - b3 = tonumber(b3) - b4 = tonumber(b4) - - if b1 and b1 <= 255 and - b2 and b2 <= 255 and - b3 and b3 <= 255 and - b4 and b4 <= 255 and - prefix - then - table.insert(obj, { b1 * 256 + b2, b3 * 256 + b4 }) - table.insert(obj, prefix) - return obj - end -end - ---- Parse given IPv6 address in full, compressed, mixed or CIDR notation. --- If an optional netmask is given as second argument and the IP address is --- encoded in CIDR notation then the netmask parameter takes precedence. --- If neither a CIDR encoded prefix nor a netmask parameter is given, then a --- prefix length of 128 bit is assumed. --- @param address IPv6 address in full/compressed/mixed or CIDR notation --- @param netmask IPv6 netmask in full/compressed/mixed notation (optional) --- @return luci.ip.cidr instance or nil if given address was invalid --- @see IPv4 --- @see Hex -function IPv6(address, netmask) - address = address or "::/0" - - local obj = __bless({ FAMILY_INET6 }) - - local data = {} - local prefix = address:match("/(.+)") - address = address:gsub("/.+","") - address = address:gsub("^%[(.*)%]$", "%1") - - if netmask then - prefix = obj:prefix(netmask) - elseif prefix then - prefix = tonumber(prefix) - if not prefix or prefix < 0 or prefix > 128 then return nil end - else - prefix = 128 - end - - local borderl = address:sub(1, 1) == ":" and 2 or 1 - local borderh, zeroh, chunk, block, i - - if #address > 45 then return nil end - - repeat - borderh = address:find(":", borderl, true) - if not borderh then break end - - block = tonumber(address:sub(borderl, borderh - 1), 16) - if block and block <= 0xFFFF then - data[#data+1] = block - else - if zeroh or borderh - borderl > 1 then return nil end - zeroh = #data + 1 - end - - borderl = borderh + 1 - until #data == 7 - - chunk = address:sub(borderl) - if #chunk > 0 and #chunk <= 4 then - block = tonumber(chunk, 16) - if not block or block > 0xFFFF then return nil end - - data[#data+1] = block - elseif #chunk > 4 then - if #data == 7 or #chunk > 15 then return nil end - borderl = 1 - for i=1, 4 do - borderh = chunk:find(".", borderl, true) - if not borderh and i < 4 then return nil end - borderh = borderh and borderh - 1 - - block = tonumber(chunk:sub(borderl, borderh)) - if not block or block > 255 then return nil end - - if i == 1 or i == 3 then - data[#data+1] = block * 256 - else - data[#data] = data[#data] + block - end - - borderl = borderh and borderh + 2 - end - end - - if zeroh then - if #data == 8 then return nil end - while #data < 8 do - table.insert(data, zeroh, 0) - end - end - - if #data == 8 and prefix then - table.insert(obj, data) - table.insert(obj, prefix) - return obj - end -end - ---- Transform given hex-encoded value to luci.ip.cidr instance of specified --- address family. --- @param hex String containing hex encoded value --- @param prefix Prefix length of CIDR instance (optional, default is 32/128) --- @param family Address family, either luci.ip.FAMILY_INET4 or FAMILY_INET6 --- @param swap Bool indicating whether to swap byteorder on low endian host --- @return luci.ip.cidr instance or nil if given value was invalid --- @see IPv4 --- @see IPv6 -function Hex( hex, prefix, family, swap ) - family = ( family ~= nil ) and family or FAMILY_INET4 - swap = ( swap == nil ) and true or swap - prefix = prefix or __maxlen(family) - - local len = __maxlen(family) - local tmp = "" - local data = { } - local i - - for i = 1, (len/4) - #hex do tmp = tmp .. '0' end - - if swap and LITTLE_ENDIAN then - for i = #hex, 1, -2 do tmp = tmp .. hex:sub( i - 1, i ) end - else - tmp = tmp .. hex - end - - hex = tmp - - for i = 1, ( len / 4 ), 4 do - local n = tonumber( hex:sub( i, i+3 ), 16 ) - if n then - data[#data+1] = n - else - return nil - end - end - - return __bless({ family, data, prefix }) -end - - ---- LuCI IP Library / CIDR instances --- @class module --- @cstyle instance --- @name luci.ip.cidr -cidr = util.class() - ---- Test whether the instance is a IPv4 address. --- @return Boolean indicating a IPv4 address type --- @see cidr.is6 -function cidr.is4( self ) - return self[1] == FAMILY_INET4 -end - ---- Test whether this instance is an IPv4 RFC1918 private address --- @return Boolean indicating whether this instance is an RFC1918 address -function cidr.is4rfc1918( self ) - if self[1] == FAMILY_INET4 then - return ((self[2][1] >= 0x0A00) and (self[2][1] <= 0x0AFF)) or - ((self[2][1] >= 0xAC10) and (self[2][1] <= 0xAC1F)) or - (self[2][1] == 0xC0A8) - end - return false -end - ---- Test whether this instance is an IPv4 link-local address (Zeroconf) --- @return Boolean indicating whether this instance is IPv4 link-local -function cidr.is4linklocal( self ) - if self[1] == FAMILY_INET4 then - return (self[2][1] == 0xA9FE) - end - return false -end - ---- Test whether the instance is a IPv6 address. --- @return Boolean indicating a IPv6 address type --- @see cidr.is4 -function cidr.is6( self ) - return self[1] == FAMILY_INET6 -end - ---- Test whether this instance is an IPv6 link-local address --- @return Boolean indicating whether this instance is IPv6 link-local -function cidr.is6linklocal( self ) - if self[1] == FAMILY_INET6 then - return (self[2][1] >= 0xFE80) and (self[2][1] <= 0xFEBF) - end - return false -end - ---- Return a corresponding string representation of the instance. --- If the prefix length is lower then the maximum possible prefix length for the --- corresponding address type then the address is returned in CIDR notation, --- otherwise the prefix will be left out. -function cidr.string( self ) - local str - if self:is4() then - str = string.format( - "%d.%d.%d.%d", - bit.rshift(self[2][1], 8), bit.band(self[2][1], 0xFF), - bit.rshift(self[2][2], 8), bit.band(self[2][2], 0xFF) - ) - if self[3] < 32 then - str = str .. "/" .. self[3] - end - elseif self:is6() then - str = string.format( "%X:%X:%X:%X:%X:%X:%X:%X", unpack(self[2]) ) - if self[3] < 128 then - str = str .. "/" .. self[3] - end - end - return str -end - ---- Test whether the value of the instance is lower then the given address. --- This function will throw an exception if the given address has a different --- family than this instance. --- @param addr A luci.ip.cidr instance to compare against --- @return Boolean indicating whether this instance is lower --- @see cidr.higher --- @see cidr.equal -function cidr.lower( self, addr ) - assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" ) - local i - for i = 1, #self[2] do - if self[2][i] ~= addr[2][i] then - return self[2][i] < addr[2][i] - end - end - return false -end - ---- Test whether the value of the instance is higher then the given address. --- This function will throw an exception if the given address has a different --- family than this instance. --- @param addr A luci.ip.cidr instance to compare against --- @return Boolean indicating whether this instance is higher --- @see cidr.lower --- @see cidr.equal -function cidr.higher( self, addr ) - assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" ) - local i - for i = 1, #self[2] do - if self[2][i] ~= addr[2][i] then - return self[2][i] > addr[2][i] - end - end - return false -end - ---- Test whether the value of the instance is equal to the given address. --- This function will throw an exception if the given address is a different --- family than this instance. --- @param addr A luci.ip.cidr instance to compare against --- @return Boolean indicating whether this instance is equal --- @see cidr.lower --- @see cidr.higher -function cidr.equal( self, addr ) - assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" ) - local i - for i = 1, #self[2] do - if self[2][i] ~= addr[2][i] then - return false - end - end - return true -end - ---- Return the prefix length of this CIDR instance. --- @param mask Override instance prefix with given netmask (optional) --- @return Prefix length in bit -function cidr.prefix( self, mask ) - local prefix = self[3] - - if mask then - prefix = 0 - - local stop = false - local obj = type(mask) ~= "table" - and ( self:is4() and IPv4(mask) or IPv6(mask) ) or mask - - if not obj then return nil end - - local _, word - for _, word in ipairs(obj[2]) do - if word == 0xFFFF then - prefix = prefix + 16 - else - local bitmask = bit.lshift(1, 15) - while bit.band(word, bitmask) == bitmask do - prefix = prefix + 1 - bitmask = bit.lshift(1, 15 - (prefix % 16)) - end - - break - end - end - end - - return prefix -end - ---- Return a corresponding CIDR representing the network address of this --- instance. --- @param bits Override prefix length of this instance (optional) --- @return CIDR instance containing the network address --- @see cidr.host --- @see cidr.broadcast --- @see cidr.mask -function cidr.network( self, bits ) - local data = { } - bits = bits or self[3] - - local i - for i = 1, math.floor( bits / 16 ) do - data[#data+1] = self[2][i] - end - - if #data < #self[2] then - data[#data+1] = bit.band( self[2][1+#data], __mask16(bits) ) - - for i = #data + 1, #self[2] do - data[#data+1] = 0 - end - end - - return __bless({ self[1], data, __maxlen(self[1]) }) -end - ---- Return a corresponding CIDR representing the host address of this --- instance. This is intended to extract the host address from larger subnet. --- @return CIDR instance containing the network address --- @see cidr.network --- @see cidr.broadcast --- @see cidr.mask -function cidr.host( self ) - return __bless({ self[1], self[2], __maxlen(self[1]) }) -end - ---- Return a corresponding CIDR representing the netmask of this instance. --- @param bits Override prefix length of this instance (optional) --- @return CIDR instance containing the netmask --- @see cidr.network --- @see cidr.host --- @see cidr.broadcast -function cidr.mask( self, bits ) - local data = { } - bits = bits or self[3] - - for i = 1, math.floor( bits / 16 ) do - data[#data+1] = 0xFFFF - end - - if #data < #self[2] then - data[#data+1] = __mask16(bits) - - for i = #data + 1, #self[2] do - data[#data+1] = 0 - end - end - - return __bless({ self[1], data, __maxlen(self[1]) }) -end - ---- Return CIDR containing the broadcast address of this instance. --- @return CIDR instance containing the netmask, always nil for IPv6 --- @see cidr.network --- @see cidr.host --- @see cidr.mask -function cidr.broadcast( self ) - -- IPv6 has no broadcast addresses (XXX: assert() instead?) - if self[1] == FAMILY_INET4 then - local data = { unpack(self[2]) } - local offset = math.floor( self[3] / 16 ) + 1 - - if offset <= #data then - data[offset] = bit.bor( data[offset], __not16(self[3]) ) - for i = offset + 1, #data do data[i] = 0xFFFF end - - return __bless({ self[1], data, __maxlen(self[1]) }) - end - end -end - ---- Test whether this instance fully contains the given CIDR instance. --- @param addr CIDR instance to test against --- @return Boolean indicating whether this instance contains the given CIDR -function cidr.contains( self, addr ) - assert( self[1] == addr[1], "Can't compare IPv4 and IPv6 addresses" ) - - if self:prefix() <= addr:prefix() then - return self:network() == addr:network(self:prefix()) - end - - return false -end - ---- Add specified amount of hosts to this instance. --- @param amount Number of hosts to add to this instance --- @param inplace Boolen indicating whether to alter values inplace (optional) --- @return CIDR representing the new address or nil on overflow error --- @see cidr.sub -function cidr.add( self, amount, inplace ) - local pos - local data = { unpack(self[2]) } - local shorts = __array16( amount, self[1] ) - - for pos = #data, 1, -1 do - local add = ( #shorts > 0 ) and table.remove( shorts, #shorts ) or 0 - if ( data[pos] + add ) > 0xFFFF then - data[pos] = ( data[pos] + add ) % 0xFFFF - if pos > 1 then - data[pos-1] = data[pos-1] + ( add - data[pos] ) - else - return nil - end - else - data[pos] = data[pos] + add - end - end - - if inplace then - self[2] = data - return self - else - return __bless({ self[1], data, self[3] }) - end -end - ---- Substract specified amount of hosts from this instance. --- @param amount Number of hosts to substract from this instance --- @param inplace Boolen indicating whether to alter values inplace (optional) --- @return CIDR representing the new address or nil on underflow error --- @see cidr.add -function cidr.sub( self, amount, inplace ) - local pos - local data = { unpack(self[2]) } - local shorts = __array16( amount, self[1] ) - - for pos = #data, 1, -1 do - local sub = ( #shorts > 0 ) and table.remove( shorts, #shorts ) or 0 - if ( data[pos] - sub ) < 0 then - data[pos] = ( sub - data[pos] ) % 0xFFFF - if pos > 1 then - data[pos-1] = data[pos-1] - ( sub + data[pos] ) - else - return nil - end - else - data[pos] = data[pos] - sub - end - end - - if inplace then - self[2] = data - return self - else - return __bless({ self[1], data, self[3] }) - end -end - ---- Return CIDR containing the lowest available host address within this subnet. --- @return CIDR containing the host address, nil if subnet is too small --- @see cidr.maxhost -function cidr.minhost( self ) - if self[3] <= __sublen(self[1]) then - -- 1st is Network Address in IPv4 and Subnet-Router Anycast Adresse in IPv6 - return self:network():add(1, true) - end -end - ---- Return CIDR containing the highest available host address within the subnet. --- @return CIDR containing the host address, nil if subnet is too small --- @see cidr.minhost -function cidr.maxhost( self ) - if self[3] <= __sublen(self[1]) then - local i - local data = { unpack(self[2]) } - local offset = math.floor( self[3] / 16 ) + 1 - - data[offset] = bit.bor( data[offset], __not16(self[3]) ) - for i = offset + 1, #data do data[i] = 0xFFFF end - data = __bless({ self[1], data, __maxlen(self[1]) }) - - -- Last address in reserved for Broadcast Address in IPv4 - if data[1] == FAMILY_INET4 then data:sub(1, true) end - - return data - end -end diff --git a/libs/core/luasrc/ltn12.lua b/libs/core/luasrc/ltn12.lua deleted file mode 100644 index 9371290c61..0000000000 --- a/libs/core/luasrc/ltn12.lua +++ /dev/null @@ -1,391 +0,0 @@ ---[[ -LuaSocket 2.0.2 license -Copyright � 2004-2007 Diego Nehab - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -]]-- ---[[ - Changes made by LuCI project: - * Renamed to luci.ltn12 to avoid collisions with luasocket - * Added inline documentation -]]-- ------------------------------------------------------------------------------ --- LTN12 - Filters, sources, sinks and pumps. --- LuaSocket toolkit. --- Author: Diego Nehab --- RCS ID: $Id$ ------------------------------------------------------------------------------ - ------------------------------------------------------------------------------ --- Declare module ------------------------------------------------------------------------------ -local string = require("string") -local table = require("table") -local base = _G - ---- Diego Nehab's LTN12 - Filters, sources, sinks and pumps. --- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts -module("luci.ltn12") - -filter = {} -source = {} -sink = {} -pump = {} - --- 2048 seems to be better in windows... -BLOCKSIZE = 2048 -_VERSION = "LTN12 1.0.1" - ------------------------------------------------------------------------------ --- Filter stuff ------------------------------------------------------------------------------ - ---- LTN12 Filter constructors --- @class module --- @name luci.ltn12.filter - ---- Return a high level filter that cycles a low-level filter --- by passing it each chunk and updating a context between calls. --- @param low Low-level filter --- @param ctx Context --- @param extra Extra argument passed to the low-level filter --- @return LTN12 filter -function filter.cycle(low, ctx, extra) - base.assert(low) - return function(chunk) - local ret - ret, ctx = low(ctx, chunk, extra) - return ret - end -end - ---- Chain a bunch of filters together. --- (thanks to Wim Couwenberg) --- @param ... filters to be chained --- @return LTN12 filter -function filter.chain(...) - local n = table.getn(arg) - local top, index = 1, 1 - local retry = "" - return function(chunk) - retry = chunk and retry - while true do - if index == top then - chunk = arg[index](chunk) - if chunk == "" or top == n then return chunk - elseif chunk then index = index + 1 - else - top = top+1 - index = top - end - else - chunk = arg[index](chunk or "") - if chunk == "" then - index = index - 1 - chunk = retry - elseif chunk then - if index == n then return chunk - else index = index + 1 end - else base.error("filter returned inappropriate nil") end - end - end - end -end - ------------------------------------------------------------------------------ --- Source stuff ------------------------------------------------------------------------------ - ---- LTN12 Source constructors --- @class module --- @name luci.ltn12.source - --- create an empty source -local function empty() - return nil -end - ---- Create an empty source. --- @return LTN12 source -function source.empty() - return empty -end - ---- Return a source that just outputs an error. --- @param err Error object --- @return LTN12 source -function source.error(err) - return function() - return nil, err - end -end - ---- Create a file source. --- @param handle File handle ready for reading --- @param io_err IO error object --- @return LTN12 source -function source.file(handle, io_err) - if handle then - return function() - local chunk = handle:read(BLOCKSIZE) - if not chunk then handle:close() end - return chunk - end - else return source.error(io_err or "unable to open file") end -end - ---- Turn a fancy source into a simple source. --- @param src fancy source --- @return LTN12 source -function source.simplify(src) - base.assert(src) - return function() - local chunk, err_or_new = src() - src = err_or_new or src - if not chunk then return nil, err_or_new - else return chunk end - end -end - ---- Create a string source. --- @param s Data --- @return LTN12 source -function source.string(s) - if s then - local i = 1 - return function() - local chunk = string.sub(s, i, i+BLOCKSIZE-1) - i = i + BLOCKSIZE - if chunk ~= "" then return chunk - else return nil end - end - else return source.empty() end -end - ---- Creates rewindable source. --- @param src LTN12 source to be made rewindable --- @return LTN12 source -function source.rewind(src) - base.assert(src) - local t = {} - return function(chunk) - if not chunk then - chunk = table.remove(t) - if not chunk then return src() - else return chunk end - else - t[#t+1] = chunk - end - end -end - ---- Chain a source and a filter together. --- @param src LTN12 source --- @param f LTN12 filter --- @return LTN12 source -function source.chain(src, f) - base.assert(src and f) - local last_in, last_out = "", "" - local state = "feeding" - local err - return function() - if not last_out then - base.error('source is empty!', 2) - end - while true do - if state == "feeding" then - last_in, err = src() - if err then return nil, err end - last_out = f(last_in) - if not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - elseif last_out ~= "" then - state = "eating" - if last_in then last_in = "" end - return last_out - end - else - last_out = f(last_in) - if last_out == "" then - if last_in == "" then - state = "feeding" - else - base.error('filter returned ""') - end - elseif not last_out then - if last_in then - base.error('filter returned inappropriate nil') - else - return nil - end - else - return last_out - end - end - end - end -end - ---- Create a source that produces contents of several sources. --- Sources will be used one after the other, as if they were concatenated --- (thanks to Wim Couwenberg) --- @param ... LTN12 sources --- @return LTN12 source -function source.cat(...) - local src = table.remove(arg, 1) - return function() - while src do - local chunk, err = src() - if chunk then return chunk end - if err then return nil, err end - src = table.remove(arg, 1) - end - end -end - ------------------------------------------------------------------------------ --- Sink stuff ------------------------------------------------------------------------------ - ---- LTN12 sink constructors --- @class module --- @name luci.ltn12.sink - ---- Create a sink that stores into a table. --- @param t output table to store into --- @return LTN12 sink -function sink.table(t) - t = t or {} - local f = function(chunk, err) - if chunk then t[#t+1] = chunk end - return 1 - end - return f, t -end - ---- Turn a fancy sink into a simple sink. --- @param snk fancy sink --- @return LTN12 sink -function sink.simplify(snk) - base.assert(snk) - return function(chunk, err) - local ret, err_or_new = snk(chunk, err) - if not ret then return nil, err_or_new end - snk = err_or_new or snk - return 1 - end -end - ---- Create a file sink. --- @param handle file handle to write to --- @param io_err IO error --- @return LTN12 sink -function sink.file(handle, io_err) - if handle then - return function(chunk, err) - if not chunk then - handle:close() - return 1 - else return handle:write(chunk) end - end - else return sink.error(io_err or "unable to open file") end -end - --- creates a sink that discards data -local function null() - return 1 -end - ---- Create a sink that discards data. --- @return LTN12 sink -function sink.null() - return null -end - ---- Create a sink that just returns an error. --- @param err Error object --- @return LTN12 sink -function sink.error(err) - return function() - return nil, err - end -end - ---- Chain a sink with a filter. --- @param f LTN12 filter --- @param snk LTN12 sink --- @return LTN12 sink -function sink.chain(f, snk) - base.assert(f and snk) - return function(chunk, err) - if chunk ~= "" then - local filtered = f(chunk) - local done = chunk and "" - while true do - local ret, snkerr = snk(filtered, err) - if not ret then return nil, snkerr end - if filtered == done then return 1 end - filtered = f(done) - end - else return 1 end - end -end - ------------------------------------------------------------------------------ --- Pump stuff ------------------------------------------------------------------------------ - ---- LTN12 pump functions --- @class module --- @name luci.ltn12.pump - ---- Pump one chunk from the source to the sink. --- @param src LTN12 source --- @param snk LTN12 sink --- @return Chunk of data or nil if an error occured --- @return Error object -function pump.step(src, snk) - local chunk, src_err = src() - local ret, snk_err = snk(chunk, src_err) - if chunk and ret then return 1 - else return nil, src_err or snk_err end -end - ---- Pump all data from a source to a sink, using a step function. --- @param src LTN12 source --- @param snk LTN12 sink --- @param step step function (optional) --- @return 1 if the operation succeeded otherwise nil --- @return Error object -function pump.all(src, snk, step) - base.assert(src and snk) - step = step or pump.step - while true do - local ret, err = step(src, snk) - if not ret then - if err then return nil, err - else return 1 end - end - end -end - diff --git a/libs/core/luasrc/model/firewall.lua b/libs/core/luasrc/model/firewall.lua deleted file mode 100644 index a9f6fdb7fc..0000000000 --- a/libs/core/luasrc/model/firewall.lua +++ /dev/null @@ -1,582 +0,0 @@ ---[[ -LuCI - Firewall model - -Copyright 2009 Jo-Philipp Wich <xm@subsignal.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local type, pairs, ipairs, table, luci, math - = type, pairs, ipairs, table, luci, math - -local tpl = require "luci.template.parser" -local utl = require "luci.util" -local uci = require "luci.model.uci" - -module "luci.model.firewall" - - -local uci_r, uci_s - -function _valid_id(x) - return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$")) -end - -function _get(c, s, o) - return uci_r:get(c, s, o) -end - -function _set(c, s, o, v) - if v ~= nil then - if type(v) == "boolean" then v = v and "1" or "0" end - return uci_r:set(c, s, o, v) - else - return uci_r:delete(c, s, o) - end -end - - -function init(cursor) - uci_r = cursor or uci_r or uci.cursor() - uci_s = uci_r:substate() - - return _M -end - -function save(self, ...) - uci_r:save(...) - uci_r:load(...) -end - -function commit(self, ...) - uci_r:commit(...) - uci_r:load(...) -end - -function get_defaults() - return defaults() -end - -function new_zone(self) - local name = "newzone" - local count = 1 - - while self:get_zone(name) do - count = count + 1 - name = "newzone%d" % count - end - - return self:add_zone(name) -end - -function add_zone(self, n) - if _valid_id(n) and not self:get_zone(n) then - local d = defaults() - local z = uci_r:section("firewall", "zone", nil, { - name = n, - network = " ", - input = d:input() or "DROP", - forward = d:forward() or "DROP", - output = d:output() or "DROP" - }) - - return z and zone(z) - end -end - -function get_zone(self, n) - if uci_r:get("firewall", n) == "zone" then - return zone(n) - else - local z - uci_r:foreach("firewall", "zone", - function(s) - if n and s.name == n then - z = s['.name'] - return false - end - end) - return z and zone(z) - end -end - -function get_zones(self) - local zones = { } - local znl = { } - - uci_r:foreach("firewall", "zone", - function(s) - if s.name then - znl[s.name] = zone(s['.name']) - end - end) - - local z - for z in utl.kspairs(znl) do - zones[#zones+1] = znl[z] - end - - return zones -end - -function get_zone_by_network(self, net) - local z - - uci_r:foreach("firewall", "zone", - function(s) - if s.name and net then - local n - for n in utl.imatch(s.network or s.name) do - if n == net then - z = s['.name'] - return false - end - end - end - end) - - return z and zone(z) -end - -function del_zone(self, n) - local r = false - - if uci_r:get("firewall", n) == "zone" then - local z = uci_r:get("firewall", n, "name") - r = uci_r:delete("firewall", n) - n = z - else - uci_r:foreach("firewall", "zone", - function(s) - if n and s.name == n then - r = uci_r:delete("firewall", s['.name']) - return false - end - end) - end - - if r then - uci_r:foreach("firewall", "rule", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - - uci_r:foreach("firewall", "redirect", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - end - - return r -end - -function rename_zone(self, old, new) - local r = false - - if _valid_id(new) and not self:get_zone(new) then - uci_r:foreach("firewall", "zone", - function(s) - if old and s.name == old then - if not s.network then - uci_r:set("firewall", s['.name'], "network", old) - end - uci_r:set("firewall", s['.name'], "name", new) - r = true - return false - end - end) - - if r then - uci_r:foreach("firewall", "rule", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - - uci_r:foreach("firewall", "redirect", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - end - end - - return r -end - -function del_network(self, net) - local z - if net then - for _, z in ipairs(self:get_zones()) do - z:del_network(net) - end - end -end - - -defaults = utl.class() -function defaults.__init__(self) - uci_r:foreach("firewall", "defaults", - function(s) - self.sid = s['.name'] - return false - end) - - self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { }) -end - -function defaults.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function defaults.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function defaults.syn_flood(self) - return (self:get("syn_flood") == "1") -end - -function defaults.drop_invalid(self) - return (self:get("drop_invalid") == "1") -end - -function defaults.input(self) - return self:get("input") or "DROP" -end - -function defaults.forward(self) - return self:get("forward") or "DROP" -end - -function defaults.output(self) - return self:get("output") or "DROP" -end - - -zone = utl.class() -function zone.__init__(self, z) - if uci_r:get("firewall", z) == "zone" then - self.sid = z - self.data = uci_r:get_all("firewall", z) - else - uci_r:foreach("firewall", "zone", - function(s) - if s.name == z then - self.sid = s['.name'] - self.data = s - return false - end - end) - end -end - -function zone.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function zone.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function zone.masq(self) - return (self:get("masq") == "1") -end - -function zone.name(self) - return self:get("name") -end - -function zone.network(self) - return self:get("network") -end - -function zone.input(self) - return self:get("input") or defaults():input() or "DROP" -end - -function zone.forward(self) - return self:get("forward") or defaults():forward() or "DROP" -end - -function zone.output(self) - return self:get("output") or defaults():output() or "DROP" -end - -function zone.add_network(self, net) - if uci_r:get("network", net) == "interface" then - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - if n ~= net then - nets[#nets+1] = n - end - end - - nets[#nets+1] = net - - _M:del_network(net) - self:set("network", table.concat(nets, " ")) - end -end - -function zone.del_network(self, net) - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - if n ~= net then - nets[#nets+1] = n - end - end - - if #nets > 0 then - self:set("network", table.concat(nets, " ")) - else - self:set("network", " ") - end -end - -function zone.get_networks(self) - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - nets[#nets+1] = n - end - - return nets -end - -function zone.clear_networks(self) - self:set("network", " ") -end - -function zone.get_forwardings_by(self, what) - local name = self:name() - local forwards = { } - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src and s.dest and s[what] == name then - forwards[#forwards+1] = forwarding(s['.name']) - end - end) - - return forwards -end - -function zone.add_forwarding_to(self, dest) - local exist, forward - - for _, forward in ipairs(self:get_forwardings_by('src')) do - if forward:dest() == dest then - exist = true - break - end - end - - if not exist and dest ~= self:name() and _valid_id(dest) then - local s = uci_r:section("firewall", "forwarding", nil, { - src = self:name(), - dest = dest - }) - - return s and forwarding(s) - end -end - -function zone.add_forwarding_from(self, src) - local exist, forward - - for _, forward in ipairs(self:get_forwardings_by('dest')) do - if forward:src() == src then - exist = true - break - end - end - - if not exist and src ~= self:name() and _valid_id(src) then - local s = uci_r:section("firewall", "forwarding", nil, { - src = src, - dest = self:name() - }) - - return s and forwarding(s) - end -end - -function zone.del_forwardings_by(self, what) - local name = self:name() - - uci_r:delete_all("firewall", "forwarding", - function(s) - return (s.src and s.dest and s[what] == name) - end) -end - -function zone.add_redirect(self, options) - options = options or { } - options.src = self:name() - - local s = uci_r:section("firewall", "redirect", nil, options) - return s and redirect(s) -end - -function zone.add_rule(self, options) - options = options or { } - options.src = self:name() - - local s = uci_r:section("firewall", "rule", nil, options) - return s and rule(s) -end - -function zone.get_color(self) - if self and self:name() == "lan" then - return "#90f090" - elseif self and self:name() == "wan" then - return "#f09090" - elseif self then - math.randomseed(tpl.hash(self:name())) - - local r = math.random(128) - local g = math.random(128) - local min = 0 - local max = 128 - - if ( r + g ) < 128 then - min = 128 - r - g - else - max = 255 - r - g - end - - local b = min + math.floor( math.random() * ( max - min ) ) - - return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b } - else - return "#eeeeee" - end -end - - -forwarding = utl.class() -function forwarding.__init__(self, f) - self.sid = f -end - -function forwarding.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function forwarding.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function forwarding.src_zone(self) - return zone(self:src()) -end - -function forwarding.dest_zone(self) - return zone(self:dest()) -end - - -rule = utl.class() -function rule.__init__(self, f) - self.sid = f -end - -function rule.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function rule.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function rule.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function rule.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function rule.src_zone(self) - return zone(self:src()) -end - -function rule.dest_zone(self) - return zone(self:dest()) -end - - -redirect = utl.class() -function redirect.__init__(self, f) - self.sid = f -end - -function redirect.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function redirect.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function redirect.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function redirect.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function redirect.src_zone(self) - return zone(self:src()) -end - -function redirect.dest_zone(self) - return zone(self:dest()) -end diff --git a/libs/core/luasrc/model/network.lua b/libs/core/luasrc/model/network.lua deleted file mode 100644 index a409621f8e..0000000000 --- a/libs/core/luasrc/model/network.lua +++ /dev/null @@ -1,1584 +0,0 @@ ---[[ -LuCI - Network model - -Copyright 2009-2010 Jo-Philipp Wich <xm@subsignal.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local type, next, pairs, ipairs, loadfile, table - = type, next, pairs, ipairs, loadfile, table - -local tonumber, tostring, math = tonumber, tostring, math - -local require = require - -local bus = require "ubus" -local nxo = require "nixio" -local nfs = require "nixio.fs" -local ipc = require "luci.ip" -local sys = require "luci.sys" -local utl = require "luci.util" -local dsp = require "luci.dispatcher" -local uci = require "luci.model.uci" -local lng = require "luci.i18n" - -module "luci.model.network" - - -IFACE_PATTERNS_VIRTUAL = { } -IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^lo$" } -IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" } - - -protocol = utl.class() - -local _protocols = { } - -local _interfaces, _bridge, _switch, _tunnel -local _ubus, _ubusnetcache, _ubusdevcache, _ubuswificache -local _uci_real, _uci_state - -function _filter(c, s, o, r) - local val = _uci_real:get(c, s, o) - if val then - local l = { } - if type(val) == "string" then - for val in val:gmatch("%S+") do - if val ~= r then - l[#l+1] = val - end - end - if #l > 0 then - _uci_real:set(c, s, o, table.concat(l, " ")) - else - _uci_real:delete(c, s, o) - end - elseif type(val) == "table" then - for _, val in ipairs(val) do - if val ~= r then - l[#l+1] = val - end - end - if #l > 0 then - _uci_real:set(c, s, o, l) - else - _uci_real:delete(c, s, o) - end - end - end -end - -function _append(c, s, o, a) - local val = _uci_real:get(c, s, o) or "" - if type(val) == "string" then - local l = { } - for val in val:gmatch("%S+") do - if val ~= a then - l[#l+1] = val - end - end - l[#l+1] = a - _uci_real:set(c, s, o, table.concat(l, " ")) - elseif type(val) == "table" then - local l = { } - for _, val in ipairs(val) do - if val ~= a then - l[#l+1] = val - end - end - l[#l+1] = a - _uci_real:set(c, s, o, l) - end -end - -function _stror(s1, s2) - if not s1 or #s1 == 0 then - return s2 and #s2 > 0 and s2 - else - return s1 - end -end - -function _get(c, s, o) - return _uci_real:get(c, s, o) -end - -function _set(c, s, o, v) - if v ~= nil then - if type(v) == "boolean" then v = v and "1" or "0" end - return _uci_real:set(c, s, o, v) - else - return _uci_real:delete(c, s, o) - end -end - -function _wifi_iface(x) - local _, p - for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do - if x:match(p) then - return true - end - end - return false -end - -function _wifi_state(key, val, field) - if not next(_ubuswificache) then - _ubuswificache = _ubus:call("network.wireless", "status", {}) or {} - end - - local radio, radiostate - for radio, radiostate in pairs(_ubuswificache) do - local ifc, ifcstate - for ifc, ifcstate in pairs(radiostate.interfaces) do - if ifcstate[key] == val then - return ifcstate[field] - end - end - end -end - -function _wifi_lookup(ifn) - -- got a radio#.network# pseudo iface, locate the corresponding section - local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$") - if radio and ifnidx then - local sid = nil - local num = 0 - - ifnidx = tonumber(ifnidx) - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device == radio then - num = num + 1 - if num == ifnidx then - sid = s['.name'] - return false - end - end - end) - - return sid - - -- looks like wifi, try to locate the section via state vars - elseif _wifi_iface(ifn) then - local sid = _wifi_state("ifname", ifn, "section") - if not sid then - _uci_state:foreach("wireless", "wifi-iface", - function(s) - if s.ifname == ifn then - sid = s['.name'] - return false - end - end) - end - - return sid - end -end - -function _iface_virtual(x) - local _, p - for _, p in ipairs(IFACE_PATTERNS_VIRTUAL) do - if x:match(p) then - return true - end - end - return false -end - -function _iface_ignore(x) - local _, p - for _, p in ipairs(IFACE_PATTERNS_IGNORE) do - if x:match(p) then - return true - end - end - return _iface_virtual(x) -end - - -function init(cursor) - _uci_real = cursor or _uci_real or uci.cursor() - _uci_state = _uci_real:substate() - - _interfaces = { } - _bridge = { } - _switch = { } - _tunnel = { } - - _ubus = bus.connect() - _ubusnetcache = { } - _ubusdevcache = { } - _ubuswificache = { } - - -- read interface information - local n, i - for n, i in ipairs(nxo.getifaddrs()) do - local name = i.name:match("[^:]+") - local prnt = name:match("^([^%.]+)%.") - - if _iface_virtual(name) then - _tunnel[name] = true - end - - if _tunnel[name] or not _iface_ignore(name) then - _interfaces[name] = _interfaces[name] or { - idx = i.ifindex or n, - name = name, - rawname = i.name, - flags = { }, - ipaddrs = { }, - ip6addrs = { } - } - - if prnt then - _switch[name] = true - _switch[prnt] = true - end - - if i.family == "packet" then - _interfaces[name].flags = i.flags - _interfaces[name].stats = i.data - _interfaces[name].macaddr = i.addr - elseif i.family == "inet" then - _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask) - elseif i.family == "inet6" then - _interfaces[name].ip6addrs[#_interfaces[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask) - end - end - end - - -- read bridge informaton - local b, l - for l in utl.execi("brctl show") do - if not l:match("STP") then - local r = utl.split(l, "%s+", nil, true) - if #r == 4 then - b = { - name = r[1], - id = r[2], - stp = r[3] == "yes", - ifnames = { _interfaces[r[4]] } - } - if b.ifnames[1] then - b.ifnames[1].bridge = b - end - _bridge[r[1]] = b - elseif b then - b.ifnames[#b.ifnames+1] = _interfaces[r[2]] - b.ifnames[#b.ifnames].bridge = b - end - end - end - - return _M -end - -function save(self, ...) - _uci_real:save(...) - _uci_real:load(...) -end - -function commit(self, ...) - _uci_real:commit(...) - _uci_real:load(...) -end - -function ifnameof(self, x) - if utl.instanceof(x, interface) then - return x:name() - elseif utl.instanceof(x, protocol) then - return x:ifname() - elseif type(x) == "string" then - return x:match("^[^:]+") - end -end - -function get_protocol(self, protoname, netname) - local v = _protocols[protoname] - if v then - return v(netname or "__dummy__") - end -end - -function get_protocols(self) - local p = { } - local _, v - for _, v in ipairs(_protocols) do - p[#p+1] = v("__dummy__") - end - return p -end - -function register_protocol(self, protoname) - local proto = utl.class(protocol) - - function proto.__init__(self, name) - self.sid = name - end - - function proto.proto(self) - return protoname - end - - _protocols[#_protocols+1] = proto - _protocols[protoname] = proto - - return proto -end - -function register_pattern_virtual(self, pat) - IFACE_PATTERNS_VIRTUAL[#IFACE_PATTERNS_VIRTUAL+1] = pat -end - - -function has_ipv6(self) - return nfs.access("/proc/net/ipv6_route") -end - -function add_network(self, n, options) - local oldnet = self:get_network(n) - if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not oldnet then - if _uci_real:section("network", "interface", n, options) then - return network(n) - end - elseif oldnet and oldnet:is_empty() then - if options then - local k, v - for k, v in pairs(options) do - oldnet:set(k, v) - end - end - return oldnet - end -end - -function get_network(self, n) - if n and _uci_real:get("network", n) == "interface" then - return network(n) - end -end - -function get_networks(self) - local nets = { } - local nls = { } - - _uci_real:foreach("network", "interface", - function(s) - nls[s['.name']] = network(s['.name']) - end) - - local n - for n in utl.kspairs(nls) do - nets[#nets+1] = nls[n] - end - - return nets -end - -function del_network(self, n) - local r = _uci_real:delete("network", n) - if r then - _uci_real:delete_all("network", "alias", - function(s) return (s.interface == n) end) - - _uci_real:delete_all("network", "route", - function(s) return (s.interface == n) end) - - _uci_real:delete_all("network", "route6", - function(s) return (s.interface == n) end) - - _uci_real:foreach("wireless", "wifi-iface", - function(s) - local net - local rest = { } - for net in utl.imatch(s.network) do - if net ~= n then - rest[#rest+1] = net - end - end - if #rest > 0 then - _uci_real:set("wireless", s['.name'], "network", - table.concat(rest, " ")) - else - _uci_real:delete("wireless", s['.name'], "network") - end - end) - end - return r -end - -function rename_network(self, old, new) - local r - if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then - r = _uci_real:section("network", "interface", new, _uci_real:get_all("network", old)) - - if r then - _uci_real:foreach("network", "alias", - function(s) - if s.interface == old then - _uci_real:set("network", s['.name'], "interface", new) - end - end) - - _uci_real:foreach("network", "route", - function(s) - if s.interface == old then - _uci_real:set("network", s['.name'], "interface", new) - end - end) - - _uci_real:foreach("network", "route6", - function(s) - if s.interface == old then - _uci_real:set("network", s['.name'], "interface", new) - end - end) - - _uci_real:foreach("wireless", "wifi-iface", - function(s) - local net - local list = { } - for net in utl.imatch(s.network) do - if net == old then - list[#list+1] = new - else - list[#list+1] = net - end - end - if #list > 0 then - _uci_real:set("wireless", s['.name'], "network", - table.concat(list, " ")) - end - end) - - _uci_real:delete("network", old) - end - end - return r or false -end - -function get_interface(self, i) - if _interfaces[i] or _wifi_iface(i) then - return interface(i) - else - local ifc - local num = { } - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] and num[s.device] + 1 or 1 - if s['.name'] == i then - ifc = interface( - "%s.network%d" %{s.device, num[s.device] }) - return false - end - end - end) - return ifc - end -end - -function get_interfaces(self) - local iface - local ifaces = { } - local seen = { } - local nfs = { } - local baseof = { } - - -- find normal interfaces - _uci_real:foreach("network", "interface", - function(s) - for iface in utl.imatch(s.ifname) do - if not _iface_ignore(iface) and not _wifi_iface(iface) then - seen[iface] = true - nfs[iface] = interface(iface) - end - end - end) - - for iface in utl.kspairs(_interfaces) do - if not (seen[iface] or _iface_ignore(iface) or _wifi_iface(iface)) then - nfs[iface] = interface(iface) - end - end - - -- find vlan interfaces - _uci_real:foreach("network", "switch_vlan", - function(s) - if not s.device then - return - end - - local base = baseof[s.device] - if not base then - if not s.device:match("^eth%d") then - local l - for l in utl.execi("swconfig dev %q help 2>/dev/null" % s.device) do - if not base then - base = l:match("^%w+: (%w+)") - end - end - if not base or not base:match("^eth%d") then - base = "eth0" - end - else - base = s.device - end - baseof[s.device] = base - end - - local vid = tonumber(s.vid or s.vlan) - if vid ~= nil and vid >= 0 and vid <= 4095 then - local iface = "%s.%d" %{ base, vid } - if not seen[iface] then - seen[iface] = true - nfs[iface] = interface(iface) - end - end - end) - - for iface in utl.kspairs(nfs) do - ifaces[#ifaces+1] = nfs[iface] - end - - -- find wifi interfaces - local num = { } - local wfs = { } - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] and num[s.device] + 1 or 1 - local i = "%s.network%d" %{ s.device, num[s.device] } - wfs[i] = interface(i) - end - end) - - for iface in utl.kspairs(wfs) do - ifaces[#ifaces+1] = wfs[iface] - end - - return ifaces -end - -function ignore_interface(self, x) - return _iface_ignore(x) -end - -function get_wifidev(self, dev) - if _uci_real:get("wireless", dev) == "wifi-device" then - return wifidev(dev) - end -end - -function get_wifidevs(self) - local devs = { } - local wfd = { } - - _uci_real:foreach("wireless", "wifi-device", - function(s) wfd[#wfd+1] = s['.name'] end) - - local dev - for _, dev in utl.vspairs(wfd) do - devs[#devs+1] = wifidev(dev) - end - - return devs -end - -function get_wifinet(self, net) - local wnet = _wifi_lookup(net) - if wnet then - return wifinet(wnet) - end -end - -function add_wifinet(self, net, options) - if type(options) == "table" and options.device and - _uci_real:get("wireless", options.device) == "wifi-device" - then - local wnet = _uci_real:section("wireless", "wifi-iface", nil, options) - return wifinet(wnet) - end -end - -function del_wifinet(self, net) - local wnet = _wifi_lookup(net) - if wnet then - _uci_real:delete("wireless", wnet) - return true - end - return false -end - -function get_status_by_route(self, addr, mask) - local _, object - for _, object in ipairs(_ubus:objects()) do - local net = object:match("^network%.interface%.(.+)") - if net then - local s = _ubus:call(object, "status", {}) - if s and s.route then - local rt - for _, rt in ipairs(s.route) do - if not rt.table and rt.target == addr and rt.mask == mask then - return net, s - end - end - end - end - end -end - -function get_status_by_address(self, addr) - local _, object - for _, object in ipairs(_ubus:objects()) do - local net = object:match("^network%.interface%.(.+)") - if net then - local s = _ubus:call(object, "status", {}) - if s and s['ipv4-address'] then - local a - for _, a in ipairs(s['ipv4-address']) do - if a.address == addr then - return net, s - end - end - end - if s and s['ipv6-address'] then - local a - for _, a in ipairs(s['ipv6-address']) do - if a.address == addr then - return net, s - end - end - end - end - end -end - -function get_wannet(self) - local net = self:get_status_by_route("0.0.0.0", 0) - return net and network(net) -end - -function get_wandev(self) - local _, stat = self:get_status_by_route("0.0.0.0", 0) - return stat and interface(stat.l3_device or stat.device) -end - -function get_wan6net(self) - local net = self:get_status_by_route("::", 0) - return net and network(net) -end - -function get_wan6dev(self) - local _, stat = self:get_status_by_route("::", 0) - return stat and interface(stat.l3_device or stat.device) -end - - -function network(name, proto) - if name then - local p = proto or _uci_real:get("network", name, "proto") - local c = p and _protocols[p] or protocol - return c(name) - end -end - -function protocol.__init__(self, name) - self.sid = name -end - -function protocol._get(self, opt) - local v = _uci_real:get("network", self.sid, opt) - if type(v) == "table" then - return table.concat(v, " ") - end - return v or "" -end - -function protocol._ubus(self, field) - if not _ubusnetcache[self.sid] then - _ubusnetcache[self.sid] = _ubus:call("network.interface.%s" % self.sid, - "status", { }) - end - if _ubusnetcache[self.sid] and field then - return _ubusnetcache[self.sid][field] - end - return _ubusnetcache[self.sid] -end - -function protocol.get(self, opt) - return _get("network", self.sid, opt) -end - -function protocol.set(self, opt, val) - return _set("network", self.sid, opt, val) -end - -function protocol.ifname(self) - local ifname - if self:is_floating() then - ifname = self:_ubus("l3_device") - else - ifname = self:_ubus("device") - end - if not ifname then - local num = { } - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] - and num[s.device] + 1 or 1 - - local net - for net in utl.imatch(s.network) do - if net == self.sid then - ifname = "%s.network%d" %{ s.device, num[s.device] } - return false - end - end - end - end) - end - return ifname -end - -function protocol.proto(self) - return "none" -end - -function protocol.get_i18n(self) - local p = self:proto() - if p == "none" then - return lng.translate("Unmanaged") - elseif p == "static" then - return lng.translate("Static address") - elseif p == "dhcp" then - return lng.translate("DHCP client") - else - return lng.translate("Unknown") - end -end - -function protocol.type(self) - return self:_get("type") -end - -function protocol.name(self) - return self.sid -end - -function protocol.uptime(self) - return self:_ubus("uptime") or 0 -end - -function protocol.expires(self) - local a = tonumber(_uci_state:get("network", self.sid, "lease_acquired")) - local l = tonumber(_uci_state:get("network", self.sid, "lease_lifetime")) - if a and l then - l = l - (nxo.sysinfo().uptime - a) - return l > 0 and l or 0 - end - return -1 -end - -function protocol.metric(self) - return tonumber(_uci_state:get("network", self.sid, "metric")) or 0 -end - -function protocol.ipaddr(self) - local addrs = self:_ubus("ipv4-address") - return addrs and #addrs > 0 and addrs[1].address -end - -function protocol.netmask(self) - local addrs = self:_ubus("ipv4-address") - return addrs and #addrs > 0 and - ipc.IPv4("0.0.0.0/%d" % addrs[1].mask):mask():string() -end - -function protocol.gwaddr(self) - local _, route - for _, route in ipairs(self:_ubus("route") or { }) do - if route.target == "0.0.0.0" and route.mask == 0 then - return route.nexthop - end - end -end - -function protocol.dnsaddrs(self) - local dns = { } - local _, addr - for _, addr in ipairs(self:_ubus("dns-server") or { }) do - if not addr:match(":") then - dns[#dns+1] = addr - end - end - return dns -end - -function protocol.ip6addr(self) - local addrs = self:_ubus("ipv6-address") - if addrs and #addrs > 0 then - return "%s/%d" %{ addrs[1].address, addrs[1].mask } - else - addrs = self:_ubus("ipv6-prefix-assignment") - if addrs and #addrs > 0 then - return "%s/%d" %{ addrs[1].address, addrs[1].mask } - end - end -end - -function protocol.gw6addr(self) - local _, route - for _, route in ipairs(self:_ubus("route") or { }) do - if route.target == "::" and route.mask == 0 then - return ipc.IPv6(route.nexthop):string() - end - end -end - -function protocol.dns6addrs(self) - local dns = { } - local _, addr - for _, addr in ipairs(self:_ubus("dns-server") or { }) do - if addr:match(":") then - dns[#dns+1] = addr - end - end - return dns -end - -function protocol.is_bridge(self) - return (not self:is_virtual() and self:type() == "bridge") -end - -function protocol.opkg_package(self) - return nil -end - -function protocol.is_installed(self) - return true -end - -function protocol.is_virtual(self) - return false -end - -function protocol.is_floating(self) - return false -end - -function protocol.is_empty(self) - if self:is_floating() then - return false - else - local rv = true - - if (self:_get("ifname") or ""):match("%S+") then - rv = false - end - - _uci_real:foreach("wireless", "wifi-iface", - function(s) - local n - for n in utl.imatch(s.network) do - if n == self.sid then - rv = false - return false - end - end - end) - - return rv - end -end - -function protocol.add_interface(self, ifname) - ifname = _M:ifnameof(ifname) - if ifname and not self:is_floating() then - -- if its a wifi interface, change its network option - local wif = _wifi_lookup(ifname) - if wif then - _append("wireless", wif, "network", self.sid) - - -- add iface to our iface list - else - _append("network", self.sid, "ifname", ifname) - end - end -end - -function protocol.del_interface(self, ifname) - ifname = _M:ifnameof(ifname) - if ifname and not self:is_floating() then - -- if its a wireless interface, clear its network option - local wif = _wifi_lookup(ifname) - if wif then _filter("wireless", wif, "network", self.sid) end - - -- remove the interface - _filter("network", self.sid, "ifname", ifname) - end -end - -function protocol.get_interface(self) - if self:is_virtual() then - _tunnel[self:proto() .. "-" .. self.sid] = true - return interface(self:proto() .. "-" .. self.sid, self) - elseif self:is_bridge() then - _bridge["br-" .. self.sid] = true - return interface("br-" .. self.sid, self) - else - local ifn = nil - local num = { } - for ifn in utl.imatch(_uci_real:get("network", self.sid, "ifname")) do - ifn = ifn:match("^[^:/]+") - return ifn and interface(ifn, self) - end - ifn = nil - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] and num[s.device] + 1 or 1 - - local net - for net in utl.imatch(s.network) do - if net == self.sid then - ifn = "%s.network%d" %{ s.device, num[s.device] } - return false - end - end - end - end) - return ifn and interface(ifn, self) - end -end - -function protocol.get_interfaces(self) - if self:is_bridge() or (self:is_virtual() and not self:is_floating()) then - local ifaces = { } - - local ifn - local nfs = { } - for ifn in utl.imatch(self:get("ifname")) do - ifn = ifn:match("^[^:/]+") - nfs[ifn] = interface(ifn, self) - end - - for ifn in utl.kspairs(nfs) do - ifaces[#ifaces+1] = nfs[ifn] - end - - local num = { } - local wfs = { } - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] and num[s.device] + 1 or 1 - - local net - for net in utl.imatch(s.network) do - if net == self.sid then - ifn = "%s.network%d" %{ s.device, num[s.device] } - wfs[ifn] = interface(ifn, self) - end - end - end - end) - - for ifn in utl.kspairs(wfs) do - ifaces[#ifaces+1] = wfs[ifn] - end - - return ifaces - end -end - -function protocol.contains_interface(self, ifname) - ifname = _M:ifnameof(ifname) - if not ifname then - return false - elseif self:is_virtual() and self:proto() .. "-" .. self.sid == ifname then - return true - elseif self:is_bridge() and "br-" .. self.sid == ifname then - return true - else - local ifn - for ifn in utl.imatch(self:get("ifname")) do - ifn = ifn:match("[^:]+") - if ifn == ifname then - return true - end - end - - local wif = _wifi_lookup(ifname) - if wif then - local n - for n in utl.imatch(_uci_real:get("wireless", wif, "network")) do - if n == self.sid then - return true - end - end - end - end - - return false -end - -function protocol.adminlink(self) - return dsp.build_url("admin", "network", "network", self.sid) -end - - -interface = utl.class() - -function interface.__init__(self, ifname, network) - local wif = _wifi_lookup(ifname) - if wif then - self.wif = wifinet(wif) - self.ifname = _wifi_state("section", wif, "ifname") - end - - self.ifname = self.ifname or ifname - self.dev = _interfaces[self.ifname] - self.network = network -end - -function interface._ubus(self, field) - if not _ubusdevcache[self.ifname] then - _ubusdevcache[self.ifname] = _ubus:call("network.device", "status", - { name = self.ifname }) - end - if _ubusdevcache[self.ifname] and field then - return _ubusdevcache[self.ifname][field] - end - return _ubusdevcache[self.ifname] -end - -function interface.name(self) - return self.wif and self.wif:ifname() or self.ifname -end - -function interface.mac(self) - return (self:_ubus("macaddr") or "00:00:00:00:00:00"):upper() -end - -function interface.ipaddrs(self) - return self.dev and self.dev.ipaddrs or { } -end - -function interface.ip6addrs(self) - return self.dev and self.dev.ip6addrs or { } -end - -function interface.type(self) - if self.wif or _wifi_iface(self.ifname) then - return "wifi" - elseif _bridge[self.ifname] then - return "bridge" - elseif _tunnel[self.ifname] then - return "tunnel" - elseif self.ifname:match("%.") then - return "vlan" - elseif _switch[self.ifname] then - return "switch" - else - return "ethernet" - end -end - -function interface.shortname(self) - if self.wif then - return "%s %q" %{ - self.wif:active_mode(), - self.wif:active_ssid() or self.wif:active_bssid() - } - else - return self.ifname - end -end - -function interface.get_i18n(self) - if self.wif then - return "%s: %s %q" %{ - lng.translate("Wireless Network"), - self.wif:active_mode(), - self.wif:active_ssid() or self.wif:active_bssid() - } - else - return "%s: %q" %{ self:get_type_i18n(), self:name() } - end -end - -function interface.get_type_i18n(self) - local x = self:type() - if x == "wifi" then - return lng.translate("Wireless Adapter") - elseif x == "bridge" then - return lng.translate("Bridge") - elseif x == "switch" then - return lng.translate("Ethernet Switch") - elseif x == "vlan" then - return lng.translate("VLAN Interface") - elseif x == "tunnel" then - return lng.translate("Tunnel Interface") - else - return lng.translate("Ethernet Adapter") - end -end - -function interface.adminlink(self) - if self.wif then - return self.wif:adminlink() - end -end - -function interface.ports(self) - local members = self:_ubus("bridge-members") - if members then - local _, iface - local ifaces = { } - for _, iface in ipairs(members) do - ifaces[#ifaces+1] = interface(iface) - end - end -end - -function interface.bridge_id(self) - if self.br then - return self.br.id - else - return nil - end -end - -function interface.bridge_stp(self) - if self.br then - return self.br.stp - else - return false - end -end - -function interface.is_up(self) - return self:_ubus("up") or false -end - -function interface.is_bridge(self) - return (self:type() == "bridge") -end - -function interface.is_bridgeport(self) - return self.dev and self.dev.bridge and true or false -end - -function interface.tx_bytes(self) - local stat = self:_ubus("statistics") - return stat and stat.tx_bytes or 0 -end - -function interface.rx_bytes(self) - local stat = self:_ubus("statistics") - return stat and stat.rx_bytes or 0 -end - -function interface.tx_packets(self) - local stat = self:_ubus("statistics") - return stat and stat.tx_packets or 0 -end - -function interface.rx_packets(self) - local stat = self:_ubus("statistics") - return stat and stat.rx_packets or 0 -end - -function interface.get_network(self) - return self:get_networks()[1] -end - -function interface.get_networks(self) - if not self.networks then - local nets = { } - local _, net - for _, net in ipairs(_M:get_networks()) do - if net:contains_interface(self.ifname) or - net:ifname() == self.ifname - then - nets[#nets+1] = net - end - end - table.sort(nets, function(a, b) return a.sid < b.sid end) - self.networks = nets - return nets - else - return self.networks - end -end - -function interface.get_wifinet(self) - return self.wif -end - - -wifidev = utl.class() - -function wifidev.__init__(self, dev) - self.sid = dev - self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } -end - -function wifidev.get(self, opt) - return _get("wireless", self.sid, opt) -end - -function wifidev.set(self, opt, val) - return _set("wireless", self.sid, opt, val) -end - -function wifidev.name(self) - return self.sid -end - -function wifidev.hwmodes(self) - local l = self.iwinfo.hwmodelist - if l and next(l) then - return l - else - return { b = true, g = true } - end -end - -function wifidev.get_i18n(self) - local t = "Generic" - if self.iwinfo.type == "wl" then - t = "Broadcom" - elseif self.iwinfo.type == "madwifi" then - t = "Atheros" - end - - local m = "" - local l = self:hwmodes() - if l.a then m = m .. "a" end - if l.b then m = m .. "b" end - if l.g then m = m .. "g" end - if l.n then m = m .. "n" end - - return "%s 802.11%s Wireless Controller (%s)" %{ t, m, self:name() } -end - -function wifidev.is_up(self) - if _ubuswificache[self.sid] then - return (_ubuswificache[self.sid].up == true) - end - - local up = false - _uci_state:foreach("wireless", "wifi-iface", - function(s) - if s.device == self.sid then - if s.up == "1" then - up = true - return false - end - end - end) - - return up -end - -function wifidev.get_wifinet(self, net) - if _uci_real:get("wireless", net) == "wifi-iface" then - return wifinet(net) - else - local wnet = _wifi_lookup(net) - if wnet then - return wifinet(wnet) - end - end -end - -function wifidev.get_wifinets(self) - local nets = { } - - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device == self.sid then - nets[#nets+1] = wifinet(s['.name']) - end - end) - - return nets -end - -function wifidev.add_wifinet(self, options) - options = options or { } - options.device = self.sid - - local wnet = _uci_real:section("wireless", "wifi-iface", nil, options) - if wnet then - return wifinet(wnet, options) - end -end - -function wifidev.del_wifinet(self, net) - if utl.instanceof(net, wifinet) then - net = net.sid - elseif _uci_real:get("wireless", net) ~= "wifi-iface" then - net = _wifi_lookup(net) - end - - if net and _uci_real:get("wireless", net, "device") == self.sid then - _uci_real:delete("wireless", net) - return true - end - - return false -end - - -wifinet = utl.class() - -function wifinet.__init__(self, net, data) - self.sid = net - - local num = { } - local netid - _uci_real:foreach("wireless", "wifi-iface", - function(s) - if s.device then - num[s.device] = num[s.device] and num[s.device] + 1 or 1 - if s['.name'] == self.sid then - netid = "%s.network%d" %{ s.device, num[s.device] } - return false - end - end - end) - - local dev = _wifi_state("section", self.sid, "ifname") or netid - - self.netid = netid - self.wdev = dev - self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { } - self.iwdata = data or _uci_state:get_all("wireless", self.sid) or - _uci_real:get_all("wireless", self.sid) or { } -end - -function wifinet.get(self, opt) - return _get("wireless", self.sid, opt) -end - -function wifinet.set(self, opt, val) - return _set("wireless", self.sid, opt, val) -end - -function wifinet.mode(self) - return _uci_state:get("wireless", self.sid, "mode") or "ap" -end - -function wifinet.ssid(self) - return _uci_state:get("wireless", self.sid, "ssid") -end - -function wifinet.bssid(self) - return _uci_state:get("wireless", self.sid, "bssid") -end - -function wifinet.network(self) - return _uci_state:get("wifinet", self.sid, "network") -end - -function wifinet.id(self) - return self.netid -end - -function wifinet.name(self) - return self.sid -end - -function wifinet.ifname(self) - local ifname = self.iwinfo.ifname - if not ifname or ifname:match("^wifi%d") or ifname:match("^radio%d") then - ifname = self.wdev - end - return ifname -end - -function wifinet.get_device(self) - if self.iwdata.device then - return wifidev(self.iwdata.device) - end -end - -function wifinet.is_up(self) - local ifc = self:get_interface() - return (ifc and ifc:is_up() or false) -end - -function wifinet.active_mode(self) - local m = _stror(self.iwinfo.mode, self.iwdata.mode) or "ap" - - if m == "ap" then m = "Master" - elseif m == "sta" then m = "Client" - elseif m == "adhoc" then m = "Ad-Hoc" - elseif m == "mesh" then m = "Mesh" - elseif m == "monitor" then m = "Monitor" - end - - return m -end - -function wifinet.active_mode_i18n(self) - return lng.translate(self:active_mode()) -end - -function wifinet.active_ssid(self) - return _stror(self.iwinfo.ssid, self.iwdata.ssid) -end - -function wifinet.active_bssid(self) - return _stror(self.iwinfo.bssid, self.iwdata.bssid) or "00:00:00:00:00:00" -end - -function wifinet.active_encryption(self) - local enc = self.iwinfo and self.iwinfo.encryption - return enc and enc.description or "-" -end - -function wifinet.assoclist(self) - return self.iwinfo.assoclist or { } -end - -function wifinet.frequency(self) - local freq = self.iwinfo.frequency - if freq and freq > 0 then - return "%.03f" % (freq / 1000) - end -end - -function wifinet.bitrate(self) - local rate = self.iwinfo.bitrate - if rate and rate > 0 then - return (rate / 1000) - end -end - -function wifinet.channel(self) - return self.iwinfo.channel or - tonumber(_uci_state:get("wireless", self.iwdata.device, "channel")) -end - -function wifinet.signal(self) - return self.iwinfo.signal or 0 -end - -function wifinet.noise(self) - return self.iwinfo.noise or 0 -end - -function wifinet.country(self) - return self.iwinfo.country or "00" -end - -function wifinet.txpower(self) - local pwr = (self.iwinfo.txpower or 0) - return pwr + self:txpower_offset() -end - -function wifinet.txpower_offset(self) - return self.iwinfo.txpower_offset or 0 -end - -function wifinet.signal_level(self, s, n) - if self:active_bssid() ~= "00:00:00:00:00:00" then - local signal = s or self:signal() - local noise = n or self:noise() - - if signal < 0 and noise < 0 then - local snr = -1 * (noise - signal) - return math.floor(snr / 5) - else - return 0 - end - else - return -1 - end -end - -function wifinet.signal_percent(self) - local qc = self.iwinfo.quality or 0 - local qm = self.iwinfo.quality_max or 0 - - if qc > 0 and qm > 0 then - return math.floor((100 / qm) * qc) - else - return 0 - end -end - -function wifinet.shortname(self) - return "%s %q" %{ - lng.translate(self:active_mode()), - self:active_ssid() or self:active_bssid() - } -end - -function wifinet.get_i18n(self) - return "%s: %s %q (%s)" %{ - lng.translate("Wireless Network"), - lng.translate(self:active_mode()), - self:active_ssid() or self:active_bssid(), - self:ifname() - } -end - -function wifinet.adminlink(self) - return dsp.build_url("admin", "network", "wireless", self.netid) -end - -function wifinet.get_network(self) - return self:get_networks()[1] -end - -function wifinet.get_networks(self) - local nets = { } - local net - for net in utl.imatch(tostring(self.iwdata.network)) do - if _uci_real:get("network", net) == "interface" then - nets[#nets+1] = network(net) - end - end - table.sort(nets, function(a, b) return a.sid < b.sid end) - return nets -end - -function wifinet.get_interface(self) - return interface(self:ifname()) -end - - --- setup base protocols -_M:register_protocol("static") -_M:register_protocol("dhcp") -_M:register_protocol("none") - --- load protocol extensions -local exts = nfs.dir(utl.libpath() .. "/model/network") -if exts then - local ext - for ext in exts do - if ext:match("%.lua$") then - require("luci.model.network." .. ext:gsub("%.lua$", "")) - end - end -end diff --git a/libs/core/luasrc/model/uci.lua b/libs/core/luasrc/model/uci.lua deleted file mode 100644 index a394563047..0000000000 --- a/libs/core/luasrc/model/uci.lua +++ /dev/null @@ -1,404 +0,0 @@ ---[[ -LuCI - UCI model - -Description: -Generalized UCI model - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- -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 error, pairs, ipairs = error, pairs, ipairs -local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack - ---- LuCI UCI model library. --- The typical workflow for UCI is: Get a cursor instance from the --- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.), --- save the changes to the staging area via Cursor.save and finally --- Cursor.commit the data to the actual config files. --- LuCI then needs to Cursor.apply the changes so deamons etc. are --- reloaded. --- @cstyle instance -module "luci.model.uci" - ---- Create a new UCI-Cursor. --- @class function --- @name cursor --- @return UCI-Cursor -cursor = uci.cursor - -APIVERSION = uci.APIVERSION - ---- Create a new Cursor initialized to the state directory. --- @return UCI cursor -function cursor_state() - return cursor(nil, "/var/state") -end - - -inst = cursor() -inst_state = cursor_state() - -local Cursor = getmetatable(inst) - ---- Applies UCI configuration changes --- @param configlist List of UCI configurations --- @param command Don't apply only return the command -function Cursor.apply(self, configlist, command) - configlist = self:_affected(configlist) - if command then - return { "/sbin/luci-reload", unpack(configlist) } - else - return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" - % table.concat(configlist, " ")) - end -end - - ---- Delete all sections of a given type that match certain criteria. --- @param config UCI config --- @param type UCI section type --- @param comparator Function that will be called for each section and --- returns a boolean whether to delete the current section (optional) -function Cursor.delete_all(self, config, stype, comparator) - local del = {} - - 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 - end - end - return true - end - end - - local function helper (section) - - if not comparator or comparator(section) then - del[#del+1] = section[".name"] - end - end - - self:foreach(config, stype, helper) - - for i, j in ipairs(del) do - self:delete(config, j) - end -end - ---- Create a new section and initialize it with data. --- @param config UCI config --- @param type UCI section type --- @param name UCI section name (optional) --- @param values Table of key - value pairs to initialize the section with --- @return Name of created section -function Cursor.section(self, config, type, name, values) - local stat = true - if name then - stat = self:set(config, name, type) - else - name = self:add(config, type) - stat = name and true - end - - if stat and values then - stat = self:tset(config, name, values) - end - - return stat and name -end - ---- Updated the data of a section using data from a table. --- @param config UCI config --- @param section UCI section name (optional) --- @param values Table of key - value pairs to update the section with -function Cursor.tset(self, config, section, values) - local stat = true - for k, v in pairs(values) do - if k:sub(1, 1) ~= "." then - stat = stat and self:set(config, section, k, v) - end - end - return stat -end - ---- Get a boolean option and return it's value as true or false. --- @param config UCI config --- @param section UCI section name --- @param option UCI option --- @return Boolean -function Cursor.get_bool(self, ...) - local val = self:get(...) - return ( val == "1" or val == "true" or val == "yes" or val == "on" ) -end - ---- Get an option or list and return values as table. --- @param config UCI config --- @param section UCI section name --- @param option UCI option --- @return UCI value -function Cursor.get_list(self, config, section, option) - if config and section and option then - local val = self:get(config, section, option) - return ( type(val) == "table" and val or { val } ) - end - return nil -end - ---- Get the given option from the first section with the given type. --- @param config UCI config --- @param type UCI section type --- @param option UCI option (optional) --- @param default Default value (optional) --- @return UCI value -function Cursor.get_first(self, conf, stype, opt, def) - local rv = def - - self:foreach(conf, stype, - function(s) - local val = not opt and s['.name'] or s[opt] - - 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") - end - - if val ~= nil then - rv = val - return false - end - end) - - return rv -end - ---- Set given values as list. --- @param config UCI config --- @param section UCI section name --- @param option UCI option --- @param value UCI value --- @return Boolean whether operation succeeded -function Cursor.set_list(self, config, section, option, value) - if config and section and option then - return self:set( - config, section, option, - ( type(value) == "table" and value or { value } ) - ) - end - return false -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") - - -- Resolve dependencies - local reloadlist = {} - - local function _resolve_deps(name) - local reload = {name} - local deps = {} - - c:foreach("ucitrack", name, - function(section) - if section.affects then - for i, aff in ipairs(section.affects) do - deps[#deps+1] = aff - end - end - end) - - for i, dep in ipairs(deps) do - for j, add in ipairs(_resolve_deps(dep)) do - reload[#reload+1] = add - end - end - - return reload - end - - -- Collect initscripts - for j, config in ipairs(configlist) do - for i, e in ipairs(_resolve_deps(config)) do - if not util.contains(reloadlist, e) then - reloadlist[#reloadlist+1] = e - end - end - end - - return reloadlist -end - ---- Create a sub-state of this cursor. The sub-state is tied to the parent --- curser, means it the parent unloads or loads configs, the sub state will --- do so as well. --- @return UCI state cursor tied to the parent cursor -function Cursor.substate(self) - Cursor._substates = Cursor._substates or { } - Cursor._substates[self] = Cursor._substates[self] or cursor_state() - 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 - - ---- Add an anonymous section. --- @class function --- @name Cursor.add --- @param config UCI config --- @param type UCI section type --- @return Name of created section - ---- Get a table of saved but uncommitted changes. --- @class function --- @name Cursor.changes --- @param config UCI config --- @return Table of changes --- @see Cursor.save - ---- Commit saved changes. --- @class function --- @name Cursor.commit --- @param config UCI config --- @return Boolean whether operation succeeded --- @see Cursor.revert --- @see Cursor.save - ---- Deletes a section or an option. --- @class function --- @name Cursor.delete --- @param config UCI config --- @param section UCI section name --- @param option UCI option (optional) --- @return Boolean whether operation succeeded - ---- Call a function for every section of a certain type. --- @class function --- @name Cursor.foreach --- @param config UCI config --- @param type UCI section type --- @param callback Function to be called --- @return Boolean whether operation succeeded - ---- Get a section type or an option --- @class function --- @name Cursor.get --- @param config UCI config --- @param section UCI section name --- @param option UCI option (optional) --- @return UCI value - ---- Get all sections of a config or all values of a section. --- @class function --- @name Cursor.get_all --- @param config UCI config --- @param section UCI section name (optional) --- @return Table of UCI sections or table of UCI values - ---- Manually load a config. --- @class function --- @name Cursor.load --- @param config UCI config --- @return Boolean whether operation succeeded --- @see Cursor.save --- @see Cursor.unload - ---- Revert saved but uncommitted changes. --- @class function --- @name Cursor.revert --- @param config UCI config --- @return Boolean whether operation succeeded --- @see Cursor.commit --- @see Cursor.save - ---- Saves changes made to a config to make them committable. --- @class function --- @name Cursor.save --- @param config UCI config --- @return Boolean whether operation succeeded --- @see Cursor.load --- @see Cursor.unload - ---- Set a value or create a named section. --- @class function --- @name Cursor.set --- @param config UCI config --- @param section UCI section name --- @param option UCI option or UCI section type --- @param value UCI value or nil if you want to create a section --- @return Boolean whether operation succeeded - ---- Get the configuration directory. --- @class function --- @name Cursor.get_confdir --- @return Configuration directory - ---- Get the directory for uncomitted changes. --- @class function --- @name Cursor.get_savedir --- @return Save directory - ---- Set the configuration directory. --- @class function --- @name Cursor.set_confdir --- @param directory UCI configuration directory --- @return Boolean whether operation succeeded - ---- Set the directory for uncommited changes. --- @class function --- @name Cursor.set_savedir --- @param directory UCI changes directory --- @return Boolean whether operation succeeded - ---- Discard changes made to a config. --- @class function --- @name Cursor.unload --- @param config UCI config --- @return Boolean whether operation succeeded --- @see Cursor.load --- @see Cursor.save diff --git a/libs/core/luasrc/store.lua b/libs/core/luasrc/store.lua deleted file mode 100644 index c33ef07e11..0000000000 --- a/libs/core/luasrc/store.lua +++ /dev/null @@ -1,16 +0,0 @@ ---[[ - -LuCI - Lua Development Framework -(c) 2009 Steven Barth <steven@midlink.org> -(c) 2009 Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - -local util = require "luci.util" -module("luci.store", util.threadlocal)
\ No newline at end of file diff --git a/libs/core/luasrc/util.lua b/libs/core/luasrc/util.lua deleted file mode 100644 index da761e219a..0000000000 --- a/libs/core/luasrc/util.lua +++ /dev/null @@ -1,791 +0,0 @@ ---[[ -LuCI - Utility library - -Description: -Several common useful Lua functions - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local io = require "io" -local math = require "math" -local table = require "table" -local debug = require "debug" -local ldebug = require "luci.debug" -local string = require "string" -local coroutine = require "coroutine" -local tparser = require "luci.template.parser" - -local getmetatable, setmetatable = getmetatable, setmetatable -local rawget, rawset, unpack = rawget, rawset, unpack -local tostring, type, assert = tostring, type, assert -local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring -local require, pcall, xpcall = require, pcall, xpcall -local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit - ---- LuCI utility functions. -module "luci.util" - --- --- Pythonic string formatting extension --- -getmetatable("").__mod = function(a, b) - if not b then - return a - elseif type(b) == "table" then - for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end - return a:format(unpack(b)) - else - if type(b) == "userdata" then b = tostring(b) end - return a:format(b) - end -end - - --- --- Class helper routines --- - --- Instantiates a class -local function _instantiate(class, ...) - local inst = setmetatable({}, {__index = class}) - - if inst.__init__ then - inst:__init__(...) - end - - return inst -end - ---- Create a Class object (Python-style object model). --- The class object can be instantiated by calling itself. --- Any class functions or shared parameters can be attached to this object. --- Attaching a table to the class object makes this table shared between --- all instances of this class. For object parameters use the __init__ function. --- Classes can inherit member functions and values from a base class. --- Class can be instantiated by calling them. All parameters will be passed --- to the __init__ function of this class - if such a function exists. --- The __init__ function must be used to set any object parameters that are not shared --- with other objects of this class. Any return values will be ignored. --- @param base The base class to inherit from (optional) --- @return A class object --- @see instanceof --- @see clone -function class(base) - return setmetatable({}, { - __call = _instantiate, - __index = base - }) -end - ---- Test whether the given object is an instance of the given class. --- @param object Object instance --- @param class Class object to test against --- @return Boolean indicating whether the object is an instance --- @see class --- @see clone -function instanceof(object, class) - local meta = getmetatable(object) - while meta and meta.__index do - if meta.__index == class then - return true - end - meta = getmetatable(meta.__index) - end - return false -end - - --- --- Scope manipulation routines --- - -local tl_meta = { - __mode = "k", - - __index = function(self, key) - local t = rawget(self, coxpt[coroutine.running()] - or coroutine.running() or 0) - return t and t[key] - end, - - __newindex = function(self, key, value) - local c = coxpt[coroutine.running()] or coroutine.running() or 0 - if not rawget(self, c) then - rawset(self, c, { [key] = value }) - else - rawget(self, c)[key] = value - end - end -} - ---- Create a new or get an already existing thread local store associated with --- the current active coroutine. A thread local store is private a table object --- whose values can't be accessed from outside of the running coroutine. --- @return Table value representing the corresponding thread local store -function threadlocal(tbl) - return setmetatable(tbl or {}, tl_meta) -end - - --- --- Debugging routines --- - ---- Write given object to stderr. --- @param obj Value to write to stderr --- @return Boolean indicating whether the write operation was successful -function perror(obj) - return io.stderr:write(tostring(obj) .. "\n") -end - ---- Recursively dumps a table to stdout, useful for testing and debugging. --- @param t Table value to dump --- @param maxdepth Maximum depth --- @return Always nil -function dumptable(t, maxdepth, i, seen) - i = i or 0 - seen = seen or setmetatable({}, {__mode="k"}) - - for k,v in pairs(t) do - perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v)) - if type(v) == "table" and (not maxdepth or i < maxdepth) then - if not seen[v] then - seen[v] = true - dumptable(v, maxdepth, i+1, seen) - else - perror(string.rep("\t", i) .. "*** RECURSION ***") - end - end - end -end - - --- --- String and data manipulation routines --- - ---- Create valid XML PCDATA from given string. --- @param value String value containing the data to escape --- @return String value containing the escaped data -function pcdata(value) - return value and tparser.pcdata(tostring(value)) -end - ---- Strip HTML tags from given string. --- @param value String containing the HTML text --- @return String with HTML tags stripped of -function striptags(value) - return value and tparser.striptags(tostring(value)) -end - ---- Splits given string on a defined separator sequence and return a table --- containing the resulting substrings. The optional max parameter specifies --- the number of bytes to process, regardless of the actual length of the given --- string. The optional last parameter, regex, specifies whether the separator --- sequence is interpreted as regular expression. --- @param str String value containing the data to split up --- @param pat String with separator pattern (optional, defaults to "\n") --- @param max Maximum times to split (optional) --- @param regex Boolean indicating whether to interpret the separator --- pattern as regular expression (optional, default is false) --- @return Table containing the resulting substrings -function split(str, pat, max, regex) - pat = pat or "\n" - max = max or #str - - local t = {} - local c = 1 - - if #str == 0 then - return {""} - end - - if #pat == 0 then - return nil - end - - if max == 0 then - return str - end - - repeat - local s, e = str:find(pat, c, not regex) - max = max - 1 - if s and max < 0 then - t[#t+1] = str:sub(c) - else - t[#t+1] = str:sub(c, s and s - 1) - end - c = e and e + 1 or #str + 1 - until not s or max < 0 - - return t -end - ---- Remove leading and trailing whitespace from given string value. --- @param str String value containing whitespace padded data --- @return String value with leading and trailing space removed -function trim(str) - return (str:gsub("^%s*(.-)%s*$", "%1")) -end - ---- Count the occurences of given substring in given string. --- @param str String to search in --- @param pattern String containing pattern to find --- @return Number of found occurences -function cmatch(str, pat) - local count = 0 - for _ in str:gmatch(pat) do count = count + 1 end - return count -end - ---- Return a matching iterator for the given value. The iterator will return --- one token per invocation, the tokens are separated by whitespace. If the --- input value is a table, it is transformed into a string first. A nil value --- will result in a valid interator which aborts with the first invocation. --- @param val The value to scan (table, string or nil) --- @return Iterator which returns one token per call -function imatch(v) - if type(v) == "table" then - local k = nil - return function() - k = next(v, k) - return v[k] - end - - elseif type(v) == "number" or type(v) == "boolean" then - local x = true - return function() - if x then - x = false - return tostring(v) - end - end - - elseif type(v) == "userdata" or type(v) == "string" then - return tostring(v):gmatch("%S+") - end - - return function() end -end - ---- Parse certain units from the given string and return the canonical integer --- value or 0 if the unit is unknown. Upper- or lower case is irrelevant. --- Recognized units are: --- o "y" - one year (60*60*24*366) --- o "m" - one month (60*60*24*31) --- o "w" - one week (60*60*24*7) --- o "d" - one day (60*60*24) --- o "h" - one hour (60*60) --- o "min" - one minute (60) --- o "kb" - one kilobyte (1024) --- o "mb" - one megabyte (1024*1024) --- o "gb" - one gigabyte (1024*1024*1024) --- o "kib" - one si kilobyte (1000) --- o "mib" - one si megabyte (1000*1000) --- o "gib" - one si gigabyte (1000*1000*1000) --- @param ustr String containing a numerical value with trailing unit --- @return Number containing the canonical value -function parse_units(ustr) - - local val = 0 - - -- unit map - local map = { - -- date stuff - y = 60 * 60 * 24 * 366, - m = 60 * 60 * 24 * 31, - w = 60 * 60 * 24 * 7, - d = 60 * 60 * 24, - h = 60 * 60, - min = 60, - - -- storage sizes - kb = 1024, - mb = 1024 * 1024, - gb = 1024 * 1024 * 1024, - - -- storage sizes (si) - kib = 1000, - mib = 1000 * 1000, - gib = 1000 * 1000 * 1000 - } - - -- parse input string - for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do - - local num = spec:gsub("[^0-9%.]+$","") - local spn = spec:gsub("^[0-9%.]+", "") - - if map[spn] or map[spn:sub(1,1)] then - val = val + num * ( map[spn] or map[spn:sub(1,1)] ) - else - val = val + num - end - end - - - return val -end - --- also register functions above in the central string class for convenience -string.pcdata = pcdata -string.striptags = striptags -string.split = split -string.trim = trim -string.cmatch = cmatch -string.parse_units = parse_units - - ---- Appends numerically indexed tables or single objects to a given table. --- @param src Target table --- @param ... Objects to insert --- @return Target table -function append(src, ...) - for i, a in ipairs({...}) do - if type(a) == "table" then - for j, v in ipairs(a) do - src[#src+1] = v - end - else - src[#src+1] = a - end - end - return src -end - ---- Combines two or more numerically indexed tables and single objects into one table. --- @param tbl1 Table value to combine --- @param tbl2 Table value to combine --- @param ... More tables to combine --- @return Table value containing all values of given tables -function combine(...) - return append({}, ...) -end - ---- Checks whether the given table contains the given value. --- @param table Table value --- @param value Value to search within the given table --- @return Boolean indicating whether the given value occurs within table -function contains(table, value) - for k, v in pairs(table) do - if value == v then - return k - end - end - return false -end - ---- Update values in given table with the values from the second given table. --- Both table are - in fact - merged together. --- @param t Table which should be updated --- @param updates Table containing the values to update --- @return Always nil -function update(t, updates) - for k, v in pairs(updates) do - t[k] = v - end -end - ---- Retrieve all keys of given associative table. --- @param t Table to extract keys from --- @return Sorted table containing the keys -function keys(t) - local keys = { } - if t then - for k, _ in kspairs(t) do - keys[#keys+1] = k - end - end - return keys -end - ---- Clones the given object and return it's copy. --- @param object Table value to clone --- @param deep Boolean indicating whether to do recursive cloning --- @return Cloned table value -function clone(object, deep) - local copy = {} - - for k, v in pairs(object) do - if deep and type(v) == "table" then - v = clone(v, deep) - end - copy[k] = v - end - - return setmetatable(copy, getmetatable(object)) -end - - ---- Create a dynamic table which automatically creates subtables. --- @return Dynamic Table -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.") - seen[t] = true - - local data = "" - local idata = "" - local ilen = 0 - - for k, v in pairs(t) do - if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then - k = serialize_data(k, seen) - v = serialize_data(v, seen) - data = data .. ( #data > 0 and ", " or "" ) .. - '[' .. k .. '] = ' .. v - elseif k > ilen then - ilen = k - end - end - - for i = 1, ilen do - local v = serialize_data(t[i], seen) - idata = idata .. ( #idata > 0 and ", " or "" ) .. v - end - - return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data -end - ---- Recursively serialize given data to lua code, suitable for restoring --- with loadstring(). --- @param val Value containing the data to serialize --- @return String value containing the serialized code --- @see restore_data --- @see get_bytecode -function serialize_data(val, seen) - seen = seen or setmetatable({}, {__mode="k"}) - - if val == nil then - return "nil" - elseif type(val) == "number" then - return val - elseif type(val) == "string" then - return "%q" % val - elseif type(val) == "boolean" then - return val and "true" or "false" - elseif type(val) == "function" then - return "loadstring(%q)" % get_bytecode(val) - elseif type(val) == "table" then - return "{ " .. _serialize_table(val, seen) .. " }" - else - return '"[unhandled data type:' .. type(val) .. ']"' - end -end - ---- Restore data previously serialized with serialize_data(). --- @param str String containing the data to restore --- @return Value containing the restored data structure --- @see serialize_data --- @see get_bytecode -function restore_data(str) - return loadstring("return " .. str)() -end - - --- --- Byte code manipulation routines --- - ---- Return the current runtime bytecode of the given data. The byte code --- will be stripped before it is returned. --- @param val Value to return as bytecode --- @return String value containing the bytecode of the given data -function get_bytecode(val) - local code - - if type(val) == "function" then - code = string.dump(val) - else - code = string.dump( loadstring( "return " .. serialize_data(val) ) ) - end - - return code -- and strip_bytecode(code) -end - ---- Strips unnescessary lua bytecode from given string. Information like line --- numbers and debugging numbers will be discarded. Original version by --- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) --- @param code String value containing the original lua byte code --- @return String value containing the stripped lua byte code -function strip_bytecode(code) - local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12) - local subint - if endian == 1 then - subint = function(code, i, l) - local val = 0 - for n = l, 1, -1 do - val = val * 256 + code:byte(i + n - 1) - end - return val, i + l - end - else - subint = function(code, i, l) - local val = 0 - for n = 1, l, 1 do - val = val * 256 + code:byte(i + n - 1) - end - return val, i + l - end - end - - local function strip_function(code) - local count, offset = subint(code, 1, size) - local stripped = { string.rep("\0", size) } - local dirty = offset + count - offset = offset + count + int * 2 + 4 - offset = offset + int + subint(code, offset, int) * ins - count, offset = subint(code, offset, int) - for n = 1, count do - local t - t, offset = subint(code, offset, 1) - if t == 1 then - offset = offset + 1 - elseif t == 4 then - offset = offset + size + subint(code, offset, size) - elseif t == 3 then - offset = offset + num - elseif t == 254 or t == 9 then - offset = offset + lnum - end - end - count, offset = subint(code, offset, int) - stripped[#stripped+1] = code:sub(dirty, offset - 1) - for n = 1, count do - local proto, off = strip_function(code:sub(offset, -1)) - stripped[#stripped+1] = proto - offset = offset + off - 1 - end - offset = offset + subint(code, offset, int) * int + int - count, offset = subint(code, offset, int) - for n = 1, count do - offset = offset + subint(code, offset, size) + size + int * 2 - end - count, offset = subint(code, offset, int) - for n = 1, count do - offset = offset + subint(code, offset, size) + size - end - stripped[#stripped+1] = string.rep("\0", int * 3) - return table.concat(stripped), offset - end - - return code:sub(1,12) .. strip_function(code:sub(13,-1)) -end - - --- --- Sorting iterator functions --- - -function _sortiter( t, f ) - local keys = { } - - local k, v - for k, v in pairs(t) do - keys[#keys+1] = k - end - - local _pos = 0 - - table.sort( keys, f ) - - return function() - _pos = _pos + 1 - if _pos <= #keys then - return keys[_pos], t[keys[_pos]], _pos - end - end -end - ---- Return a key, value iterator which returns the values sorted according to --- the provided callback function. --- @param t The table to iterate --- @param f A callback function to decide the order of elements --- @return Function value containing the corresponding iterator -function spairs(t,f) - return _sortiter( t, f ) -end - ---- Return a key, value iterator for the given table. --- The table pairs are sorted by key. --- @param t The table to iterate --- @return Function value containing the corresponding iterator -function kspairs(t) - return _sortiter( t ) -end - ---- Return a key, value iterator for the given table. --- The table pairs are sorted by value. --- @param t The table to iterate --- @return Function value containing the corresponding iterator -function vspairs(t) - return _sortiter( t, function (a,b) return t[a] < t[b] end ) -end - - --- --- System utility functions --- - ---- Test whether the current system is operating in big endian mode. --- @return Boolean value indicating whether system is big endian -function bigendian() - return string.byte(string.dump(function() end), 7) == 0 -end - ---- Execute given commandline and gather stdout. --- @param command String containing command to execute --- @return String containing the command's stdout -function exec(command) - local pp = io.popen(command) - local data = pp:read("*a") - pp:close() - - return data -end - ---- Return a line-buffered iterator over the output of given command. --- @param command String containing the command to execute --- @return Iterator -function execi(command) - local pp = io.popen(command) - - return pp and function() - local line = pp:read() - - if not line then - pp:close() - end - - return line - end -end - --- Deprecated -function execl(command) - local pp = io.popen(command) - local line = "" - local data = {} - - while true do - line = pp:read() - if (line == nil) then break end - data[#data+1] = line - end - pp:close() - - return data -end - ---- Returns the absolute path to LuCI base directory. --- @return String containing the directory path -function libpath() - return require "nixio.fs".dirname(ldebug.__file__) -end - - --- --- Coroutine safe xpcall and pcall versions modified for Luci --- original version: --- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org) --- --- Copyright © 2005 Kepler Project. --- Permission is hereby granted, free of charge, to any person obtaining a --- copy of this software and associated documentation files (the "Software"), --- to deal in the Software without restriction, including without limitation --- the rights to use, copy, modify, merge, publish, distribute, sublicense, --- and/or sell copies of the Software, and to permit persons to whom the --- Software is furnished to do so, subject to the following conditions: --- --- The above copyright notice and this permission notice shall be --- included in all copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, --- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES --- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. --- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, --- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, --- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE --- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -local performResume, handleReturnValue -local oldpcall, oldxpcall = pcall, xpcall -coxpt = {} -setmetatable(coxpt, {__mode = "kv"}) - --- Identity function for copcall -local function copcall_id(trace, ...) - return ... -end - ---- This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function --- @param f Lua function to be called protected --- @param err Custom error handler --- @param ... Parameters passed to the function --- @return A boolean whether the function call succeeded and the return --- values of either the function or the error handler -function coxpcall(f, err, ...) - local res, co = oldpcall(coroutine.create, f) - if not res then - local params = {...} - local newf = function() return f(unpack(params)) end - co = coroutine.create(newf) - end - local c = coroutine.running() - coxpt[co] = coxpt[c] or c or 0 - - return performResume(err, co, ...) -end - ---- This is a coroutine-safe drop-in replacement for Lua's "pcall"-function --- @param f Lua function to be called protected --- @param ... Parameters passed to the function --- @return A boolean whether the function call succeeded and the returns --- values of the function or the error object -function copcall(f, ...) - return coxpcall(f, copcall_id, ...) -end - --- Handle return value of protected call -function handleReturnValue(err, co, status, ...) - if not status then - return false, err(debug.traceback(co, (...)), ...) - end - - if coroutine.status(co) ~= 'suspended' then - return true, ... - end - - return performResume(err, co, coroutine.yield(...)) -end - --- Resume execution of protected function call -function performResume(err, co, ...) - return handleReturnValue(err, co, coroutine.resume(co, ...)) -end diff --git a/libs/core/luasrc/version.lua b/libs/core/luasrc/version.lua deleted file mode 100644 index 9e5cb719c4..0000000000 --- a/libs/core/luasrc/version.lua +++ /dev/null @@ -1,12 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface -Version definition - do not edit this file -]]-- - -module "luci.version" - -distname = "Host System" -distversion = "SDK" - -luciname = "LuCI" -luciversion = "SVN" diff --git a/libs/core/root/etc/config/ucitrack b/libs/core/root/etc/config/ucitrack deleted file mode 100644 index 04467f4fdf..0000000000 --- a/libs/core/root/etc/config/ucitrack +++ /dev/null @@ -1,53 +0,0 @@ -config network - option init network - list affects dhcp - list affects radvd - -config wireless - list affects network - -config firewall - option init firewall - list affects luci-splash - list affects qos - list affects miniupnpd - -config olsr - option init olsrd - -config dhcp - option init dnsmasq - -config dropbear - option init dropbear - -config httpd - option init httpd - -config fstab - option init fstab - -config qos - option init qos - -config system - option init led - list affects luci_statistics - -config luci_splash - option init luci_splash - -config upnpd - option init miniupnpd - -config ntpclient - option init ntpclient - -config samba - option init samba - -config tinyproxy - option init tinyproxy - -config 6relayd - option init 6relayd diff --git a/libs/core/root/sbin/luci-reload b/libs/core/root/sbin/luci-reload deleted file mode 100755 index cc41da2bb7..0000000000 --- a/libs/core/root/sbin/luci-reload +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -. /lib/functions.sh - -apply_config() { - config_get init "$1" init - config_get exec "$1" exec - config_get test "$1" test - - echo "$2" > "/var/run/luci-reload-status" - - [ -n "$init" ] && reload_init "$2" "$init" "$test" - [ -n "$exec" ] && reload_exec "$2" "$exec" "$test" -} - -reload_exec() { - local service="$1" - local ok="$3" - set -- $2 - local cmd="$1"; shift - - [ -x "$cmd" ] && { - echo "Reloading $service... " - ( $cmd "$@" ) 2>/dev/null 1>&2 - [ -n "$ok" -a "$?" != "$ok" ] && echo '!!! Failed to reload' $service '!!!' - } -} - -reload_init() { - [ -x /etc/init.d/$2 ] && /etc/init.d/$2 enabled && { - echo "Reloading $1... " - /etc/init.d/$2 reload >/dev/null 2>&1 - [ -n "$3" -a "$?" != "$3" ] && echo '!!! Failed to reload' $1 '!!!' - } -} - -lock "/var/run/luci-reload" - -config_load ucitrack - -for i in $*; do - config_foreach apply_config $i $i -done - -rm -f "/var/run/luci-reload-status" -lock -u "/var/run/luci-reload" diff --git a/libs/ipkg/Makefile b/libs/ipkg/Makefile deleted file mode 100644 index f7fac7740e..0000000000 --- a/libs/ipkg/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../../build/config.mk -include ../../build/module.mk diff --git a/libs/ipkg/luasrc/model/ipkg.lua b/libs/ipkg/luasrc/model/ipkg.lua deleted file mode 100644 index c927e71163..0000000000 --- a/libs/ipkg/luasrc/model/ipkg.lua +++ /dev/null @@ -1,239 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -(c) 2008-2011 Jo-Philipp Wich <xm@subsignal.org> -(c) 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - -local os = require "os" -local io = require "io" -local fs = require "nixio.fs" -local util = require "luci.util" - -local type = type -local pairs = pairs -local error = error -local table = table - -local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase" -local icfg = "/etc/opkg.conf" - ---- LuCI OPKG call abstraction library -module "luci.model.ipkg" - - --- Internal action function -local function _action(cmd, ...) - local pkg = "" - for k, v in pairs({...}) do - pkg = pkg .. " '" .. v:gsub("'", "") .. "'" - end - - local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg } - local r = os.execute(c) - local e = fs.readfile("/tmp/opkg.stderr") - local o = fs.readfile("/tmp/opkg.stdout") - - fs.unlink("/tmp/opkg.stderr") - fs.unlink("/tmp/opkg.stdout") - - return r, o or "", e or "" -end - --- Internal parser function -local function _parselist(rawdata) - if type(rawdata) ~= "function" then - error("OPKG: Invalid rawdata given") - end - - local data = {} - local c = {} - local l = nil - - for line in rawdata do - if line:sub(1, 1) ~= " " then - local key, val = line:match("(.-): ?(.*)%s*") - - if key and val then - if key == "Package" then - c = {Package = val} - data[val] = c - elseif key == "Status" then - c.Status = {} - for j in val:gmatch("([^ ]+)") do - c.Status[j] = true - end - else - c[key] = val - end - l = key - end - else - -- Multi-line field - c[l] = c[l] .. "\n" .. line - end - end - - return data -end - --- Internal lookup function -local function _lookup(act, pkg) - local cmd = ipkg .. " " .. act - if pkg then - cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'" - 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)) - - local data = _parselist(io.lines(tmpfile)) - os.remove(tmpfile) - return data -end - - ---- Return information about installed and available packages. --- @param pkg Limit output to a (set of) packages --- @return Table containing package information -function info(pkg) - return _lookup("info", pkg) -end - ---- Return the package status of one or more packages. --- @param pkg Limit output to a (set of) packages --- @return Table containing package status information -function status(pkg) - return _lookup("status", pkg) -end - ---- Install one or more packages. --- @param ... List of packages to install --- @return Boolean indicating the status of the action --- @return OPKG return code, STDOUT and STDERR -function install(...) - return _action("install", ...) -end - ---- Determine whether a given package is installed. --- @param pkg Package --- @return Boolean -function installed(pkg) - local p = status(pkg)[pkg] - return (p and p.Status and p.Status.installed) -end - ---- Remove one or more packages. --- @param ... List of packages to install --- @return Boolean indicating the status of the action --- @return OPKG return code, STDOUT and STDERR -function remove(...) - return _action("remove", ...) -end - ---- Update package lists. --- @return Boolean indicating the status of the action --- @return OPKG return code, STDOUT and STDERR -function update() - return _action("update") -end - ---- Upgrades all installed packages. --- @return Boolean indicating the status of the action --- @return OPKG return code, STDOUT and STDERR -function upgrade() - return _action("upgrade") -end - --- List helper -function _list(action, pat, cb) - local fd = io.popen(ipkg .. " " .. action .. - (pat and (" '%s'" % pat:gsub("'", "")) or "")) - - if fd then - local name, version, desc - while true do - local line = fd:read("*l") - if not line then break end - - name, version, desc = line:match("^(.-) %- (.-) %- (.+)") - - if not name then - name, version = line:match("^(.-) %- (.+)") - desc = "" - end - - cb(name, version, desc) - - name = nil - version = nil - desc = nil - end - - fd:close() - end -end - ---- List all packages known to opkg. --- @param pat Only find packages matching this pattern, nil lists all packages --- @param cb Callback function invoked for each package, receives name, version and description as arguments --- @return nothing -function list_all(pat, cb) - _list("list", pat, cb) -end - ---- List installed packages. --- @param pat Only find packages matching this pattern, nil lists all packages --- @param cb Callback function invoked for each package, receives name, version and description as arguments --- @return nothing -function list_installed(pat, cb) - _list("list_installed", pat, cb) -end - ---- Find packages that match the given pattern. --- @param pat Find packages whose names or descriptions match this pattern, nil results in zero results --- @param cb Callback function invoked for each patckage, receives name, version and description as arguments --- @return nothing -function find(pat, cb) - _list("find", pat, cb) -end - - ---- Determines the overlay root used by opkg. --- @return String containing the directory path of the overlay root. -function overlay_root() - local od = "/" - local fd = io.open(icfg, "r") - - if fd then - local ln - - repeat - ln = fd:read("*l") - if ln and ln:match("^%s*option%s+overlay_root%s+") then - od = ln:match("^%s*option%s+overlay_root%s+(%S+)") - - local s = fs.stat(od) - if not s or s.type ~= "dir" then - od = "/" - end - - break - end - until not ln - - fd:close() - end - - return od -end diff --git a/libs/sgi-cgi/Makefile b/libs/sgi-cgi/Makefile deleted file mode 100644 index 81a96f6a83..0000000000 --- a/libs/sgi-cgi/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../../build/config.mk -include ../../build/module.mk
\ No newline at end of file diff --git a/libs/sgi-cgi/htdocs/cgi-bin/luci b/libs/sgi-cgi/htdocs/cgi-bin/luci deleted file mode 100755 index 529d1d0bc5..0000000000 --- a/libs/sgi-cgi/htdocs/cgi-bin/luci +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/lua -require "luci.cacheloader" -require "luci.sgi.cgi" -luci.dispatcher.indexcache = "/tmp/luci-indexcache" -luci.sgi.cgi.run()
\ No newline at end of file diff --git a/libs/sgi-cgi/luasrc/sgi/cgi.lua b/libs/sgi-cgi/luasrc/sgi/cgi.lua deleted file mode 100644 index 04ae9aa592..0000000000 --- a/libs/sgi-cgi/luasrc/sgi/cgi.lua +++ /dev/null @@ -1,95 +0,0 @@ ---[[ -LuCI - SGI-Module for CGI - -Description: -Server Gateway Interface for CGI - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- -exectime = os.clock() -module("luci.sgi.cgi", package.seeall) -local ltn12 = require("luci.ltn12") -require("nixio.util") -require("luci.http") -require("luci.sys") -require("luci.dispatcher") - --- Limited source to avoid endless blocking -local function limitsource(handle, limit) - limit = limit or 0 - local BLOCKSIZE = ltn12.BLOCKSIZE - - return function() - if limit < 1 then - handle:close() - return nil - else - local read = (limit > BLOCKSIZE) and BLOCKSIZE or limit - limit = limit - read - - local chunk = handle:read(read) - if not chunk then handle:close() end - return chunk - end - end -end - -function run() - local r = luci.http.Request( - luci.sys.getenv(), - limitsource(io.stdin, tonumber(luci.sys.getenv("CONTENT_LENGTH"))), - ltn12.sink.file(io.stderr) - ) - - local x = coroutine.create(luci.dispatcher.httpdispatch) - local hcache = "" - local active = true - - while coroutine.status(x) ~= "dead" do - local res, id, data1, data2 = coroutine.resume(x, r) - - if not res then - print("Status: 500 Internal Server Error") - print("Content-Type: text/plain\n") - print(id) - break; - end - - if active then - if id == 1 then - io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\r\n") - elseif id == 2 then - hcache = hcache .. data1 .. ": " .. data2 .. "\r\n" - elseif id == 3 then - io.write(hcache) - io.write("\r\n") - elseif id == 4 then - io.write(tostring(data1 or "")) - elseif id == 5 then - io.flush() - io.close() - active = false - elseif id == 6 then - data1:copyz(nixio.stdout, data2) - data1:close() - end - end - end -end diff --git a/libs/sgi-uhttpd/Makefile b/libs/sgi-uhttpd/Makefile deleted file mode 100644 index 81a96f6a83..0000000000 --- a/libs/sgi-uhttpd/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../../build/config.mk -include ../../build/module.mk
\ No newline at end of file diff --git a/libs/sgi-uhttpd/luasrc/sgi/uhttpd.lua b/libs/sgi-uhttpd/luasrc/sgi/uhttpd.lua deleted file mode 100644 index db8780f7ec..0000000000 --- a/libs/sgi-uhttpd/luasrc/sgi/uhttpd.lua +++ /dev/null @@ -1,105 +0,0 @@ ---[[ -LuCI - Server Gateway Interface for the uHTTPd server - -Copyright 2010 Jo-Philipp Wich <xm@subsignal.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -require "nixio.util" -require "luci.http" -require "luci.sys" -require "luci.dispatcher" -require "luci.ltn12" - -function handle_request(env) - exectime = os.clock() - local renv = { - CONTENT_LENGTH = env.CONTENT_LENGTH, - CONTENT_TYPE = env.CONTENT_TYPE, - REQUEST_METHOD = env.REQUEST_METHOD, - REQUEST_URI = env.REQUEST_URI, - PATH_INFO = env.PATH_INFO, - SCRIPT_NAME = env.SCRIPT_NAME:gsub("/+$", ""), - SCRIPT_FILENAME = env.SCRIPT_NAME, - SERVER_PROTOCOL = env.SERVER_PROTOCOL, - QUERY_STRING = env.QUERY_STRING - } - - local k, v - for k, v in pairs(env.headers) do - k = k:upper():gsub("%-", "_") - renv["HTTP_" .. k] = v - end - - local len = tonumber(env.CONTENT_LENGTH) or 0 - local function recv() - if len > 0 then - local rlen, rbuf = uhttpd.recv(4096) - if rlen >= 0 then - len = len - rlen - return rbuf - end - end - return nil - end - - local send = uhttpd.send - - local req = luci.http.Request( - renv, recv, luci.ltn12.sink.file(io.stderr) - ) - - - local x = coroutine.create(luci.dispatcher.httpdispatch) - local hcache = { } - local active = true - - while coroutine.status(x) ~= "dead" do - local res, id, data1, data2 = coroutine.resume(x, req) - - if not res then - send("Status: 500 Internal Server Error\r\n") - send("Content-Type: text/plain\r\n\r\n") - send(tostring(id)) - break - end - - if active then - if id == 1 then - send("Status: ") - send(tostring(data1)) - send(" ") - send(tostring(data2)) - send("\r\n") - elseif id == 2 then - hcache[data1] = data2 - elseif id == 3 then - for k, v in pairs(hcache) do - send(tostring(k)) - send(": ") - send(tostring(v)) - send("\r\n") - end - send("\r\n") - elseif id == 4 then - send(tostring(data1 or "")) - elseif id == 5 then - active = false - elseif id == 6 then - data1:copyz(nixio.stdout, data2) - end - end - end -end diff --git a/libs/sys/Makefile b/libs/sys/Makefile deleted file mode 100644 index f7fac7740e..0000000000 --- a/libs/sys/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -include ../../build/config.mk -include ../../build/module.mk diff --git a/libs/sys/luasrc/sys.lua b/libs/sys/luasrc/sys.lua deleted file mode 100644 index df6280dda0..0000000000 --- a/libs/sys/luasrc/sys.lua +++ /dev/null @@ -1,961 +0,0 @@ ---[[ -LuCI - System library - -Description: -Utilities for interaction with the Linux system - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - - -local io = require "io" -local os = require "os" -local table = require "table" -local nixio = require "nixio" -local fs = require "nixio.fs" -local uci = require "luci.model.uci" - -local luci = {} -luci.util = require "luci.util" -luci.ip = require "luci.ip" - -local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select = - tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select - - ---- LuCI Linux and POSIX system utilities. -module "luci.sys" - ---- Execute a given shell command and return the error code --- @class function --- @name call --- @param ... Command to call --- @return Error code of the command -function call(...) - return os.execute(...) / 256 -end - ---- Execute a given shell command and capture its standard output --- @class function --- @name exec --- @param command Command to call --- @return String containg the return the output of the command -exec = luci.util.exec - ---- Retrieve information about currently mounted file systems. --- @return Table containing mount information -function mounts() - local data = {} - local k = {"fs", "blocks", "used", "available", "percent", "mountpoint"} - local ps = luci.util.execi("df") - - if not ps then - return - else - ps() - end - - for line in ps do - local row = {} - - local j = 1 - for value in line:gmatch("[^%s]+") do - row[k[j]] = value - j = j + 1 - end - - if row[k[1]] then - - -- this is a rather ugly workaround to cope with wrapped lines in - -- the df output: - -- - -- /dev/scsi/host0/bus0/target0/lun0/part3 - -- 114382024 93566472 15005244 86% /mnt/usb - -- - - if not row[k[2]] then - j = 2 - line = ps() - for value in line:gmatch("[^%s]+") do - row[k[j]] = value - j = j + 1 - end - end - - table.insert(data, row) - end - end - - return data -end - ---- Retrieve environment variables. If no variable is given then a table --- containing the whole environment is returned otherwise this function returns --- the corresponding string value for the given name or nil if no such variable --- exists. --- @class function --- @name getenv --- @param var Name of the environment variable to retrieve (optional) --- @return String containg the value of the specified variable --- @return Table containing all variables if no variable name is given -getenv = nixio.getenv - ---- Get or set the current hostname. --- @param String containing a new hostname to set (optional) --- @return String containing the system hostname -function hostname(newname) - if type(newname) == "string" and #newname > 0 then - fs.writefile( "/proc/sys/kernel/hostname", newname ) - return newname - else - return nixio.uname().nodename - end -end - ---- Returns the contents of a documented referred by an URL. --- @param url The URL to retrieve --- @param stream Return a stream instead of a buffer --- @param target Directly write to target file name --- @return String containing the contents of given the URL -function httpget(url, stream, target) - if not target then - local source = stream and io.popen or luci.util.exec - return source("wget -qO- '"..url:gsub("'", "").."'") - else - return os.execute("wget -qO '%s' '%s'" % - {target:gsub("'", ""), url:gsub("'", "")}) - end -end - ---- Returns the system load average values. --- @return String containing the average load value 1 minute ago --- @return String containing the average load value 5 minutes ago --- @return String containing the average load value 15 minutes ago -function loadavg() - local info = nixio.sysinfo() - return info.loads[1], info.loads[2], info.loads[3] -end - ---- Initiate a system reboot. --- @return Return value of os.execute() -function reboot() - return os.execute("reboot >/dev/null 2>&1") -end - ---- Returns the system type, cpu name and installed physical memory. --- @return String containing the system or platform identifier --- @return String containing hardware model information --- @return String containing the total memory amount in kB --- @return String containing the memory used for caching in kB --- @return String containing the memory used for buffering in kB --- @return String containing the free memory amount in kB --- @return String containing the cpu bogomips (number) -function sysinfo() - local cpuinfo = fs.readfile("/proc/cpuinfo") - local meminfo = fs.readfile("/proc/meminfo") - - local memtotal = tonumber(meminfo:match("MemTotal:%s*(%d+)")) - local memcached = tonumber(meminfo:match("\nCached:%s*(%d+)")) - local memfree = tonumber(meminfo:match("MemFree:%s*(%d+)")) - local membuffers = tonumber(meminfo:match("Buffers:%s*(%d+)")) - local bogomips = tonumber(cpuinfo:match("[Bb]ogo[Mm][Ii][Pp][Ss].-: ([^\n]+)")) or 0 - local swaptotal = tonumber(meminfo:match("SwapTotal:%s*(%d+)")) - local swapcached = tonumber(meminfo:match("SwapCached:%s*(%d+)")) - local swapfree = tonumber(meminfo:match("SwapFree:%s*(%d+)")) - - local system = - cpuinfo:match("system type\t+: ([^\n]+)") or - cpuinfo:match("Processor\t+: ([^\n]+)") or - cpuinfo:match("model name\t+: ([^\n]+)") - - local model = - luci.util.pcdata(fs.readfile("/tmp/sysinfo/model")) or - cpuinfo:match("machine\t+: ([^\n]+)") or - cpuinfo:match("Hardware\t+: ([^\n]+)") or - luci.util.pcdata(fs.readfile("/proc/diag/model")) or - nixio.uname().machine or - system - - return system, model, memtotal, memcached, membuffers, memfree, bogomips, swaptotal, swapcached, swapfree -end - ---- Retrieves the output of the "logread" command. --- @return String containing the current log buffer -function syslog() - return luci.util.exec("logread") -end - ---- Retrieves the output of the "dmesg" command. --- @return String containing the current log buffer -function dmesg() - return luci.util.exec("dmesg") -end - ---- Generates a random id with specified length. --- @param bytes Number of bytes for the unique id --- @return String containing hex encoded id -function uniqueid(bytes) - local rand = fs.readfile("/dev/urandom", bytes) - return rand and nixio.bin.hexlify(rand) -end - ---- Returns the current system uptime stats. --- @return String containing total uptime in seconds -function uptime() - return nixio.sysinfo().uptime -end - - ---- LuCI system utilities / network related functions. --- @class module --- @name luci.sys.net -net = {} - ---- Returns the current arp-table entries as two-dimensional table. --- @return Table of table containing the current arp entries. --- The following fields are defined for arp entry objects: --- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" } -function net.arptable(callback) - local arp = (not callback) and {} or nil - local e, r, v - if fs.access("/proc/net/arp") then - for e in io.lines("/proc/net/arp") do - local r = { }, v - for v in e:gmatch("%S+") do - r[#r+1] = v - end - - if r[1] ~= "IP" then - local x = { - ["IP address"] = r[1], - ["HW type"] = r[2], - ["Flags"] = r[3], - ["HW address"] = r[4], - ["Mask"] = r[5], - ["Device"] = r[6] - } - - if callback then - callback(x) - else - arp = arp or { } - arp[#arp+1] = x - end - end - end - end - return arp -end - -local function _nethints(what, callback) - local _, k, e, mac, ip, name - local cur = uci.cursor() - local ifn = { } - local hosts = { } - - local function _add(i, ...) - local k = select(i, ...) - if k then - if not hosts[k] then hosts[k] = { } end - hosts[k][1] = select(1, ...) or hosts[k][1] - hosts[k][2] = select(2, ...) or hosts[k][2] - hosts[k][3] = select(3, ...) or hosts[k][3] - hosts[k][4] = select(4, ...) or hosts[k][4] - end - end - - if fs.access("/proc/net/arp") then - for e in io.lines("/proc/net/arp") do - ip, mac = e:match("^([%d%.]+)%s+%S+%s+%S+%s+([a-fA-F0-9:]+)%s+") - if ip and mac then - _add(what, mac:upper(), ip, nil, nil) - end - end - end - - if fs.access("/etc/ethers") then - for e in io.lines("/etc/ethers") do - mac, ip = e:match("^([a-f0-9]%S+) (%S+)") - if mac and ip then - _add(what, mac:upper(), ip, nil, nil) - end - end - end - - if fs.access("/var/dhcp.leases") then - for e in io.lines("/var/dhcp.leases") do - mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)") - if mac and ip then - _add(what, mac:upper(), ip, nil, name ~= "*" and name) - end - end - end - - cur:foreach("dhcp", "host", - function(s) - for mac in luci.util.imatch(s.mac) do - _add(what, mac:upper(), s.ip, nil, s.name) - end - end) - - for _, e in ipairs(nixio.getifaddrs()) do - if e.name ~= "lo" then - ifn[e.name] = ifn[e.name] or { } - if e.family == "packet" and e.addr and #e.addr == 17 then - ifn[e.name][1] = e.addr:upper() - elseif e.family == "inet" then - ifn[e.name][2] = e.addr - elseif e.family == "inet6" then - ifn[e.name][3] = e.addr - end - end - end - - for _, e in pairs(ifn) do - if e[what] and (e[2] or e[3]) then - _add(what, e[1], e[2], e[3], e[4]) - end - end - - for _, e in luci.util.kspairs(hosts) do - callback(e[1], e[2], e[3], e[4]) - end -end - ---- Returns a two-dimensional table of mac address hints. --- @return Table of table containing known hosts from various sources. --- Each entry contains the values in the following order: --- [ "mac", "name" ] -function net.mac_hints(callback) - if callback then - _nethints(1, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4 - if name and name ~= mac then - callback(mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4) - end - end) - else - local rv = { } - _nethints(1, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4 - if name and name ~= mac then - rv[#rv+1] = { mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4 } - end - end) - return rv - end -end - ---- Returns a two-dimensional table of IPv4 address hints. --- @return Table of table containing known hosts from various sources. --- Each entry contains the values in the following order: --- [ "ip", "name" ] -function net.ipv4_hints(callback) - if callback then - _nethints(2, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v4, nil, 100) or mac - if name and name ~= v4 then - callback(v4, name) - end - end) - else - local rv = { } - _nethints(2, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v4, nil, 100) or mac - if name and name ~= v4 then - rv[#rv+1] = { v4, name } - end - end) - return rv - end -end - ---- Returns a two-dimensional table of IPv6 address hints. --- @return Table of table containing known hosts from various sources. --- Each entry contains the values in the following order: --- [ "ip", "name" ] -function net.ipv6_hints(callback) - if callback then - _nethints(3, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v6, nil, 100) or mac - if name and name ~= v6 then - callback(v6, name) - end - end) - else - local rv = { } - _nethints(3, function(mac, v4, v6, name) - name = name or nixio.getnameinfo(v6, nil, 100) or mac - if name and name ~= v6 then - rv[#rv+1] = { v6, name } - end - end) - return rv - end -end - ---- Returns conntrack information --- @return Table with the currently tracked IP connections -function net.conntrack(callback) - local connt = {} - if fs.access("/proc/net/nf_conntrack", "r") then - for line in io.lines("/proc/net/nf_conntrack") do - line = line:match "^(.-( [^ =]+=).-)%2" - local entry, flags = _parse_mixed_record(line, " +") - if flags[6] ~= "TIME_WAIT" then - entry.layer3 = flags[1] - entry.layer4 = flags[3] - for i=1, #entry do - entry[i] = nil - end - - if callback then - callback(entry) - else - connt[#connt+1] = entry - end - end - end - elseif fs.access("/proc/net/ip_conntrack", "r") then - for line in io.lines("/proc/net/ip_conntrack") do - line = line:match "^(.-( [^ =]+=).-)%2" - local entry, flags = _parse_mixed_record(line, " +") - if flags[4] ~= "TIME_WAIT" then - entry.layer3 = "ipv4" - entry.layer4 = flags[1] - for i=1, #entry do - entry[i] = nil - end - - if callback then - callback(entry) - else - connt[#connt+1] = entry - end - end - end - else - return nil - end - return connt -end - ---- Determine the current IPv4 default route. If multiple default routes exist, --- return the one with the lowest metric. --- @return Table with the properties of the current default route. --- The following fields are defined: --- { "dest", "gateway", "metric", "refcount", "usecount", "irtt", --- "flags", "device" } -function net.defaultroute() - local route - - net.routes(function(rt) - if rt.dest:prefix() == 0 and (not route or route.metric > rt.metric) then - route = rt - end - end) - - return route -end - ---- Determine the current IPv6 default route. If multiple default routes exist, --- return the one with the lowest metric. --- @return Table with the properties of the current default route. --- The following fields are defined: --- { "source", "dest", "nexthop", "metric", "refcount", "usecount", --- "flags", "device" } -function net.defaultroute6() - local route - - net.routes6(function(rt) - if rt.dest:prefix() == 0 and rt.device ~= "lo" and - (not route or route.metric > rt.metric) - then - route = rt - end - end) - - if not route then - local global_unicast = luci.ip.IPv6("2000::/3") - net.routes6(function(rt) - if rt.dest:equal(global_unicast) and - (not route or route.metric > rt.metric) - then - route = rt - end - end) - end - - return route -end - ---- Determine the names of available network interfaces. --- @return Table containing all current interface names -function net.devices() - local devs = {} - for k, v in ipairs(nixio.getifaddrs()) do - if v.family == "packet" then - devs[#devs+1] = v.name - end - end - return devs -end - - ---- Return information about available network interfaces. --- @return Table containing all current interface names and their information -function net.deviceinfo() - local devs = {} - for k, v in ipairs(nixio.getifaddrs()) do - if v.family == "packet" then - local d = v.data - d[1] = d.rx_bytes - d[2] = d.rx_packets - d[3] = d.rx_errors - d[4] = d.rx_dropped - d[5] = 0 - d[6] = 0 - d[7] = 0 - d[8] = d.multicast - d[9] = d.tx_bytes - d[10] = d.tx_packets - d[11] = d.tx_errors - d[12] = d.tx_dropped - d[13] = 0 - d[14] = d.collisions - d[15] = 0 - d[16] = 0 - devs[v.name] = d - end - end - return devs -end - - --- Determine the MAC address belonging to the given IP address. --- @param ip IPv4 address --- @return String containing the MAC address or nil if it cannot be found -function net.ip4mac(ip) - local mac = nil - net.arptable(function(e) - if e["IP address"] == ip then - mac = e["HW address"] - end - end) - return mac -end - ---- Returns the current kernel routing table entries. --- @return Table of tables with properties of the corresponding routes. --- The following fields are defined for route entry tables: --- { "dest", "gateway", "metric", "refcount", "usecount", "irtt", --- "flags", "device" } -function net.routes(callback) - local routes = { } - - for line in io.lines("/proc/net/route") do - - local dev, dst_ip, gateway, flags, refcnt, usecnt, metric, - dst_mask, mtu, win, irtt = line:match( - "([^%s]+)\t([A-F0-9]+)\t([A-F0-9]+)\t([A-F0-9]+)\t" .. - "(%d+)\t(%d+)\t(%d+)\t([A-F0-9]+)\t(%d+)\t(%d+)\t(%d+)" - ) - - if dev then - gateway = luci.ip.Hex( gateway, 32, luci.ip.FAMILY_INET4 ) - dst_mask = luci.ip.Hex( dst_mask, 32, luci.ip.FAMILY_INET4 ) - dst_ip = luci.ip.Hex( - dst_ip, dst_mask:prefix(dst_mask), luci.ip.FAMILY_INET4 - ) - - local rt = { - dest = dst_ip, - gateway = gateway, - metric = tonumber(metric), - refcount = tonumber(refcnt), - usecount = tonumber(usecnt), - mtu = tonumber(mtu), - window = tonumber(window), - irtt = tonumber(irtt), - flags = tonumber(flags, 16), - device = dev - } - - if callback then - callback(rt) - else - routes[#routes+1] = rt - end - end - end - - return routes -end - ---- Returns the current ipv6 kernel routing table entries. --- @return Table of tables with properties of the corresponding routes. --- The following fields are defined for route entry tables: --- { "source", "dest", "nexthop", "metric", "refcount", "usecount", --- "flags", "device" } -function net.routes6(callback) - if fs.access("/proc/net/ipv6_route", "r") then - local routes = { } - - for line in io.lines("/proc/net/ipv6_route") do - - local dst_ip, dst_prefix, src_ip, src_prefix, nexthop, - metric, refcnt, usecnt, flags, dev = line:match( - "([a-f0-9]+) ([a-f0-9]+) " .. - "([a-f0-9]+) ([a-f0-9]+) " .. - "([a-f0-9]+) ([a-f0-9]+) " .. - "([a-f0-9]+) ([a-f0-9]+) " .. - "([a-f0-9]+) +([^%s]+)" - ) - - if dst_ip and dst_prefix and - src_ip and src_prefix and - nexthop and metric and - refcnt and usecnt and - flags and dev - then - src_ip = luci.ip.Hex( - src_ip, tonumber(src_prefix, 16), luci.ip.FAMILY_INET6, false - ) - - dst_ip = luci.ip.Hex( - dst_ip, tonumber(dst_prefix, 16), luci.ip.FAMILY_INET6, false - ) - - nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false ) - - local rt = { - source = src_ip, - dest = dst_ip, - nexthop = nexthop, - metric = tonumber(metric, 16), - refcount = tonumber(refcnt, 16), - usecount = tonumber(usecnt, 16), - flags = tonumber(flags, 16), - device = dev, - - -- lua number is too small for storing the metric - -- add a metric_raw field with the original content - metric_raw = metric - } - - if callback then - callback(rt) - else - routes[#routes+1] = rt - end - end - end - - return routes - end -end - ---- Tests whether the given host responds to ping probes. --- @param host String containing a hostname or IPv4 address --- @return Number containing 0 on success and >= 1 on error -function net.pingtest(host) - return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1") -end - - ---- LuCI system utilities / process related functions. --- @class module --- @name luci.sys.process -process = {} - ---- Get the current process id. --- @class function --- @name process.info --- @return Number containing the current pid -function process.info(key) - local s = {uid = nixio.getuid(), gid = nixio.getgid()} - return not key and s or s[key] -end - ---- Retrieve information about currently running processes. --- @return Table containing process information -function process.list() - local data = {} - local k - local ps = luci.util.execi("/bin/busybox top -bn1") - - if not ps then - return - end - - for line in ps do - local pid, ppid, user, stat, vsz, mem, cpu, cmd = line:match( - "^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][W ][<N ]) +(%d+) +(%d+%%) +(%d+%%) +(.+)" - ) - - local idx = tonumber(pid) - if idx then - data[idx] = { - ['PID'] = pid, - ['PPID'] = ppid, - ['USER'] = user, - ['STAT'] = stat, - ['VSZ'] = vsz, - ['%MEM'] = mem, - ['%CPU'] = cpu, - ['COMMAND'] = cmd - } - end - end - - return data -end - ---- Set the gid of a process identified by given pid. --- @param gid Number containing the Unix group id --- @return Boolean indicating successful operation --- @return String containing the error message if failed --- @return Number containing the error code if failed -function process.setgroup(gid) - return nixio.setgid(gid) -end - ---- Set the uid of a process identified by given pid. --- @param uid Number containing the Unix user id --- @return Boolean indicating successful operation --- @return String containing the error message if failed --- @return Number containing the error code if failed -function process.setuser(uid) - return nixio.setuid(uid) -end - ---- Send a signal to a process identified by given pid. --- @class function --- @name process.signal --- @param pid Number containing the process id --- @param sig Signal to send (default: 15 [SIGTERM]) --- @return Boolean indicating successful operation --- @return Number containing the error code if failed -process.signal = nixio.kill - - ---- LuCI system utilities / user related functions. --- @class module --- @name luci.sys.user -user = {} - ---- Retrieve user informations for given uid. --- @class function --- @name getuser --- @param uid Number containing the Unix user id --- @return Table containing the following fields: --- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" } -user.getuser = nixio.getpw - ---- Retrieve the current user password hash. --- @param username String containing the username to retrieve the password for --- @return String containing the hash or nil if no password is set. --- @return Password database entry -function user.getpasswd(username) - local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username) - local pwh = pwe and (pwe.pwdp or pwe.passwd) - if not pwh or #pwh < 1 or pwh == "!" or pwh == "x" then - return nil, pwe - else - return pwh, pwe - end -end - ---- Test whether given string matches the password of a given system user. --- @param username String containing the Unix user name --- @param pass String containing the password to compare --- @return Boolean indicating wheather the passwords are equal -function user.checkpasswd(username, pass) - local pwh, pwe = user.getpasswd(username) - if pwe then - return (pwh == nil or nixio.crypt(pass, pwh) == pwh) - end - return false -end - ---- Change the password of given user. --- @param username String containing the Unix user name --- @param password String containing the password to compare --- @return Number containing 0 on success and >= 1 on error -function user.setpasswd(username, password) - if password then - password = password:gsub("'", [['"'"']]) - end - - if username then - username = username:gsub("'", [['"'"']]) - end - - return os.execute( - "(echo '" .. password .. "'; sleep 1; echo '" .. password .. "') | " .. - "passwd '" .. username .. "' >/dev/null 2>&1" - ) -end - - ---- LuCI system utilities / wifi related functions. --- @class module --- @name luci.sys.wifi -wifi = {} - ---- Get wireless information for given interface. --- @param ifname String containing the interface name --- @return A wrapped iwinfo object instance -function wifi.getiwinfo(ifname) - local stat, iwinfo = pcall(require, "iwinfo") - - if ifname then - local c = 0 - local u = uci.cursor_state() - local d, n = ifname:match("^(%w+)%.network(%d+)") - if d and n then - ifname = d - n = tonumber(n) - u:foreach("wireless", "wifi-iface", - function(s) - if s.device == d then - c = c + 1 - if c == n then - ifname = s.ifname or s.device - return false - end - end - end) - elseif u:get("wireless", ifname) == "wifi-device" then - u:foreach("wireless", "wifi-iface", - function(s) - if s.device == ifname and s.ifname then - ifname = s.ifname - return false - end - end) - end - - local t = stat and iwinfo.type(ifname) - local x = t and iwinfo[t] or { } - return setmetatable({}, { - __index = function(t, k) - if k == "ifname" then - return ifname - elseif x[k] then - return x[k](ifname) - end - end - }) - end -end - - ---- LuCI system utilities / init related functions. --- @class module --- @name luci.sys.init -init = {} -init.dir = "/etc/init.d/" - ---- Get the names of all installed init scripts --- @return Table containing the names of all inistalled init scripts -function init.names() - local names = { } - for name in fs.glob(init.dir.."*") do - names[#names+1] = fs.basename(name) - end - return names -end - ---- Get the index of he given init script --- @param name Name of the init script --- @return Numeric index value -function init.index(name) - if fs.access(init.dir..name) then - return call("env -i sh -c 'source %s%s enabled; exit ${START:-255}' >/dev/null" - %{ init.dir, name }) - end -end - -local function init_action(action, name) - if fs.access(init.dir..name) then - return call("env -i %s%s %s >/dev/null" %{ init.dir, name, action }) - end -end - ---- Test whether the given init script is enabled --- @param name Name of the init script --- @return Boolean indicating whether init is enabled -function init.enabled(name) - return (init_action("enabled", name) == 0) -end - ---- Enable the given init script --- @param name Name of the init script --- @return Boolean indicating success -function init.enable(name) - return (init_action("enable", name) == 1) -end - ---- Disable the given init script --- @param name Name of the init script --- @return Boolean indicating success -function init.disable(name) - return (init_action("disable", name) == 0) -end - ---- Start the given init script --- @param name Name of the init script --- @return Boolean indicating success -function init.start(name) - return (init_action("start", name) == 0) -end - ---- Stop the given init script --- @param name Name of the init script --- @return Boolean indicating success -function init.stop(name) - return (init_action("stop", name) == 0) -end - - --- Internal functions - -function _parse_mixed_record(cnt, delimiter) - delimiter = delimiter or " " - local data = {} - local flags = {} - - for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n")) do - for j, f in pairs(luci.util.split(luci.util.trim(l), delimiter, nil, true)) do - local k, x, v = f:match('([^%s][^:=]*) *([:=]*) *"*([^\n"]*)"*') - - if k then - if x == "" then - table.insert(flags, k) - else - data[k] = v - end - end - end - end - - return data, flags -end diff --git a/libs/sys/luasrc/sys/iptparser.lua b/libs/sys/luasrc/sys/iptparser.lua deleted file mode 100644 index d82363309a..0000000000 --- a/libs/sys/luasrc/sys/iptparser.lua +++ /dev/null @@ -1,373 +0,0 @@ ---[[ - -Iptables parser and query library -(c) 2008-2009 Jo-Philipp Wich <xm@leipzig.freifunk.net> -(c) 2008-2009 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - -local luci = {} -luci.util = require "luci.util" -luci.sys = require "luci.sys" -luci.ip = require "luci.ip" - -local tonumber, ipairs, table = tonumber, ipairs, table - ---- LuCI iptables parser and query library --- @cstyle instance -module("luci.sys.iptparser") - ---- Create a new iptables parser object. --- @class function --- @name IptParser --- @param family Number specifying the address family. 4 for IPv4, 6 for IPv6 --- @return IptParser instance -IptParser = luci.util.class() - -function IptParser.__init__( self, family ) - self._family = (tonumber(family) == 6) and 6 or 4 - self._rules = { } - self._chains = { } - - if self._family == 4 then - self._nulladdr = "0.0.0.0/0" - self._tables = { "filter", "nat", "mangle", "raw" } - self._command = "iptables -t %s --line-numbers -nxvL" - else - self._nulladdr = "::/0" - self._tables = { "filter", "mangle", "raw" } - self._command = "ip6tables -t %s --line-numbers -nxvL" - end - - self:_parse_rules() -end - ---- Find all firewall rules that match the given criteria. Expects a table with --- search criteria as only argument. If args is nil or an empty table then all --- rules will be returned. --- --- The following keys in the args table are recognized: --- <ul> --- <li> table - Match rules that are located within the given table --- <li> chain - Match rules that are located within the given chain --- <li> target - Match rules with the given target --- <li> protocol - Match rules that match the given protocol, rules with --- protocol "all" are always matched --- <li> source - Match rules with the given source, rules with source --- "0.0.0.0/0" (::/0) are always matched --- <li> destination - Match rules with the given destination, rules with --- destination "0.0.0.0/0" (::/0) are always matched --- <li> inputif - Match rules with the given input interface, rules --- with input interface "*" (=all) are always matched --- <li> outputif - Match rules with the given output interface, rules --- with output interface "*" (=all) are always matched --- <li> flags - Match rules that match the given flags, current --- supported values are "-f" (--fragment) --- and "!f" (! --fragment) --- <li> options - Match rules containing all given options --- </ul> --- The return value is a list of tables representing the matched rules. --- Each rule table contains the following fields: --- <ul> --- <li> index - The index number of the rule --- <li> table - The table where the rule is located, can be one --- of "filter", "nat" or "mangle" --- <li> chain - The chain where the rule is located, e.g. "INPUT" --- or "postrouting_wan" --- <li> target - The rule target, e.g. "REJECT" or "DROP" --- <li> protocol The matching protocols, e.g. "all" or "tcp" --- <li> flags - Special rule options ("--", "-f" or "!f") --- <li> inputif - Input interface of the rule, e.g. "eth0.0" --- or "*" for all interfaces --- <li> outputif - Output interface of the rule,e.g. "eth0.0" --- or "*" for all interfaces --- <li> source - The source ip range, e.g. "0.0.0.0/0" (::/0) --- <li> destination - The destination ip range, e.g. "0.0.0.0/0" (::/0) --- <li> options - A list of specific options of the rule, --- e.g. { "reject-with", "tcp-reset" } --- <li> packets - The number of packets matched by the rule --- <li> bytes - The number of total bytes matched by the rule --- </ul> --- Example: --- <pre> --- ip = luci.sys.iptparser.IptParser() --- result = ip.find( { --- target="REJECT", --- protocol="tcp", --- options={ "reject-with", "tcp-reset" } --- } ) --- </pre> --- This will match all rules with target "-j REJECT", --- protocol "-p tcp" (or "-p all") --- and the option "--reject-with tcp-reset". --- @params args Table containing the search arguments (optional) --- @return Table of matching rule tables -function IptParser.find( self, args ) - - local args = args or { } - local rv = { } - - args.source = args.source and self:_parse_addr(args.source) - args.destination = args.destination and self:_parse_addr(args.destination) - - for i, rule in ipairs(self._rules) do - local match = true - - -- match table - if not ( not args.table or args.table:lower() == rule.table ) then - match = false - end - - -- match chain - if not ( match == true and ( - not args.chain or args.chain == rule.chain - ) ) then - match = false - end - - -- match target - if not ( match == true and ( - not args.target or args.target == rule.target - ) ) then - match = false - end - - -- match protocol - if not ( match == true and ( - not args.protocol or rule.protocol == "all" or - args.protocol:lower() == rule.protocol - ) ) then - match = false - end - - -- match source - if not ( match == true and ( - not args.source or rule.source == self._nulladdr or - self:_parse_addr(rule.source):contains(args.source) - ) ) then - match = false - end - - -- match destination - if not ( match == true and ( - not args.destination or rule.destination == self._nulladdr or - self:_parse_addr(rule.destination):contains(args.destination) - ) ) then - match = false - end - - -- match input interface - if not ( match == true and ( - not args.inputif or rule.inputif == "*" or - args.inputif == rule.inputif - ) ) then - match = false - end - - -- match output interface - if not ( match == true and ( - not args.outputif or rule.outputif == "*" or - args.outputif == rule.outputif - ) ) then - match = false - end - - -- match flags (the "opt" column) - if not ( match == true and ( - not args.flags or rule.flags == args.flags - ) ) then - match = false - end - - -- match specific options - if not ( match == true and ( - not args.options or - self:_match_options( rule.options, args.options ) - ) ) then - match = false - end - - -- insert match - if match == true then - rv[#rv+1] = rule - end - end - - return rv -end - - ---- Rebuild the internal lookup table, for example when rules have changed --- through external commands. --- @return nothing -function IptParser.resync( self ) - self._rules = { } - self._chain = nil - self:_parse_rules() -end - - ---- Find the names of all tables. --- @return Table of table names. -function IptParser.tables( self ) - return self._tables -end - - ---- Find the names of all chains within the given table name. --- @param table String containing the table name --- @return Table of chain names in the order they occur. -function IptParser.chains( self, table ) - local lookup = { } - local chains = { } - for _, r in ipairs(self:find({table=table})) do - if not lookup[r.chain] then - lookup[r.chain] = true - chains[#chains+1] = r.chain - end - end - return chains -end - - ---- Return the given firewall chain within the given table name. --- @param table String containing the table name --- @param chain String containing the chain name --- @return Table containing the fields "policy", "packets", "bytes" --- and "rules". The "rules" field is a table of rule tables. -function IptParser.chain( self, table, chain ) - return self._chains[table:lower()] and self._chains[table:lower()][chain] -end - - ---- Test whether the given target points to a custom chain. --- @param target String containing the target action --- @return Boolean indicating whether target is a custom chain. -function IptParser.is_custom_target( self, target ) - for _, r in ipairs(self._rules) do - if r.chain == target then - return true - end - end - return false -end - - --- [internal] Parse address according to family. -function IptParser._parse_addr( self, addr ) - if self._family == 4 then - return luci.ip.IPv4(addr) - else - return luci.ip.IPv6(addr) - end -end - --- [internal] Parse iptables output from all tables. -function IptParser._parse_rules( self ) - - for i, tbl in ipairs(self._tables) do - - self._chains[tbl] = { } - - for i, rule in ipairs(luci.util.execl(self._command % tbl)) do - - if rule:find( "^Chain " ) == 1 then - - local crefs - local cname, cpol, cpkt, cbytes = rule:match( - "^Chain ([^%s]*) %(policy (%w+) " .. - "(%d+) packets, (%d+) bytes%)" - ) - - if not cname then - cname, crefs = rule:match( - "^Chain ([^%s]*) %((%d+) references%)" - ) - end - - self._chain = cname - self._chains[tbl][cname] = { - policy = cpol, - packets = tonumber(cpkt or 0), - bytes = tonumber(cbytes or 0), - references = tonumber(crefs or 0), - rules = { } - } - - else - if rule:find("%d") == 1 then - - local rule_parts = luci.util.split( rule, "%s+", nil, true ) - local rule_details = { } - - -- cope with rules that have no target assigned - if rule:match("^%d+%s+%d+%s+%d+%s%s") then - table.insert(rule_parts, 4, nil) - end - - -- ip6tables opt column is usually zero-width - if self._family == 6 then - table.insert(rule_parts, 6, "--") - end - - rule_details["table"] = tbl - rule_details["chain"] = self._chain - rule_details["index"] = tonumber(rule_parts[1]) - rule_details["packets"] = tonumber(rule_parts[2]) - rule_details["bytes"] = tonumber(rule_parts[3]) - rule_details["target"] = rule_parts[4] - rule_details["protocol"] = rule_parts[5] - rule_details["flags"] = rule_parts[6] - rule_details["inputif"] = rule_parts[7] - rule_details["outputif"] = rule_parts[8] - rule_details["source"] = rule_parts[9] - rule_details["destination"] = rule_parts[10] - rule_details["options"] = { } - - for i = 11, #rule_parts do - if #rule_parts[i] > 0 then - rule_details["options"][i-10] = rule_parts[i] - end - end - - self._rules[#self._rules+1] = rule_details - - self._chains[tbl][self._chain].rules[ - #self._chains[tbl][self._chain].rules + 1 - ] = rule_details - end - end - end - end - - self._chain = nil -end - - --- [internal] Return true if optlist1 contains all elements of optlist 2. --- Return false in all other cases. -function IptParser._match_options( self, o1, o2 ) - - -- construct a hashtable of first options list to speed up lookups - local oh = { } - for i, opt in ipairs( o1 ) do oh[opt] = true end - - -- iterate over second options list - -- each string in o2 must be also present in o1 - -- if o2 contains a string which is not found in o1 then return false - for i, opt in ipairs( o2 ) do - if not oh[opt] then - return false - end - end - - return true -end diff --git a/libs/sys/luasrc/sys/zoneinfo.lua b/libs/sys/luasrc/sys/zoneinfo.lua deleted file mode 100644 index f5a12bfcb6..0000000000 --- a/libs/sys/luasrc/sys/zoneinfo.lua +++ /dev/null @@ -1,28 +0,0 @@ ---[[ -LuCI - Autogenerated Zoneinfo Module - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - -local setmetatable, require, rawget, rawset = setmetatable, require, rawget, rawset - -module "luci.sys.zoneinfo" - -setmetatable(_M, { - __index = function(t, k) - if k == "TZ" and not rawget(t, k) then - local m = require "luci.sys.zoneinfo.tzdata" - rawset(t, k, rawget(m, k)) - elseif k == "OFFSET" and not rawget(t, k) then - local m = require "luci.sys.zoneinfo.tzoffset" - rawset(t, k, rawget(m, k)) - end - - return rawget(t, k) - end -}) diff --git a/libs/sys/luasrc/sys/zoneinfo/tzdata.lua b/libs/sys/luasrc/sys/zoneinfo/tzdata.lua deleted file mode 100644 index 1a99f6a7eb..0000000000 --- a/libs/sys/luasrc/sys/zoneinfo/tzdata.lua +++ /dev/null @@ -1,420 +0,0 @@ ---[[ -LuCI - Autogenerated Zoneinfo Module - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - -module "luci.sys.zoneinfo.tzdata" - -TZ = { - { 'Africa/Abidjan', 'GMT0' }, - { 'Africa/Accra', 'GMT0' }, - { 'Africa/Addis Ababa', 'EAT-3' }, - { 'Africa/Algiers', 'CET-1' }, - { 'Africa/Asmara', 'EAT-3' }, - { 'Africa/Bamako', 'GMT0' }, - { 'Africa/Bangui', 'WAT-1' }, - { 'Africa/Banjul', 'GMT0' }, - { 'Africa/Bissau', 'GMT0' }, - { 'Africa/Blantyre', 'CAT-2' }, - { 'Africa/Brazzaville', 'WAT-1' }, - { 'Africa/Bujumbura', 'CAT-2' }, - { 'Africa/Casablanca', 'WET0' }, - { 'Africa/Ceuta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Africa/Conakry', 'GMT0' }, - { 'Africa/Dakar', 'GMT0' }, - { 'Africa/Dar es Salaam', 'EAT-3' }, - { 'Africa/Djibouti', 'EAT-3' }, - { 'Africa/Douala', 'WAT-1' }, - { 'Africa/El Aaiun', 'WET0' }, - { 'Africa/Freetown', 'GMT0' }, - { 'Africa/Gaborone', 'CAT-2' }, - { 'Africa/Harare', 'CAT-2' }, - { 'Africa/Johannesburg', 'SAST-2' }, - { 'Africa/Juba', 'EAT-3' }, - { 'Africa/Kampala', 'EAT-3' }, - { 'Africa/Khartoum', 'EAT-3' }, - { 'Africa/Kigali', 'CAT-2' }, - { 'Africa/Kinshasa', 'WAT-1' }, - { 'Africa/Lagos', 'WAT-1' }, - { 'Africa/Libreville', 'WAT-1' }, - { 'Africa/Lome', 'GMT0' }, - { 'Africa/Luanda', 'WAT-1' }, - { 'Africa/Lubumbashi', 'CAT-2' }, - { 'Africa/Lusaka', 'CAT-2' }, - { 'Africa/Malabo', 'WAT-1' }, - { 'Africa/Maputo', 'CAT-2' }, - { 'Africa/Maseru', 'SAST-2' }, - { 'Africa/Mbabane', 'SAST-2' }, - { 'Africa/Mogadishu', 'EAT-3' }, - { 'Africa/Monrovia', 'GMT0' }, - { 'Africa/Nairobi', 'EAT-3' }, - { 'Africa/Ndjamena', 'WAT-1' }, - { 'Africa/Niamey', 'WAT-1' }, - { 'Africa/Nouakchott', 'GMT0' }, - { 'Africa/Ouagadougou', 'GMT0' }, - { 'Africa/Porto-Novo', 'WAT-1' }, - { 'Africa/Sao Tome', 'GMT0' }, - { 'Africa/Tripoli', 'EET-2' }, - { 'Africa/Tunis', 'CET-1' }, - { 'Africa/Windhoek', 'WAT-1WAST,M9.1.0,M4.1.0' }, - { 'America/Adak', 'HAST10HADT,M3.2.0,M11.1.0' }, - { 'America/Anchorage', 'AKST9AKDT,M3.2.0,M11.1.0' }, - { 'America/Anguilla', 'AST4' }, - { 'America/Antigua', 'AST4' }, - { 'America/Araguaina', 'BRT3' }, - { 'America/Argentina/Buenos Aires', 'ART3' }, - { 'America/Argentina/Catamarca', 'ART3' }, - { 'America/Argentina/Cordoba', 'ART3' }, - { 'America/Argentina/Jujuy', 'ART3' }, - { 'America/Argentina/La Rioja', 'ART3' }, - { 'America/Argentina/Mendoza', 'ART3' }, - { 'America/Argentina/Rio Gallegos', 'ART3' }, - { 'America/Argentina/Salta', 'ART3' }, - { 'America/Argentina/San Juan', 'ART3' }, - { 'America/Argentina/Tucuman', 'ART3' }, - { 'America/Argentina/Ushuaia', 'ART3' }, - { 'America/Aruba', 'AST4' }, - { 'America/Asuncion', 'PYT4PYST,M10.1.0/0,M4.2.0/0' }, - { 'America/Atikokan', 'EST5' }, - { 'America/Bahia', 'BRT3BRST,M10.3.0/0,M2.3.0/0' }, - { 'America/Bahia Banderas', 'CST6CDT,M4.1.0,M10.5.0' }, - { 'America/Barbados', 'AST4' }, - { 'America/Belem', 'BRT3' }, - { 'America/Belize', 'CST6' }, - { 'America/Blanc-Sablon', 'AST4' }, - { 'America/Boa Vista', 'AMT4' }, - { 'America/Bogota', 'COT5' }, - { 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Campo Grande', 'AMT4AMST,M10.3.0/0,M2.3.0/0' }, - { 'America/Cancun', 'CST6CDT,M4.1.0,M10.5.0' }, - { 'America/Caracas', 'VET4:30' }, - { 'America/Cayenne', 'GFT3' }, - { 'America/Cayman', 'EST5' }, - { 'America/Chicago', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' }, - { 'America/Costa Rica', 'CST6' }, - { 'America/Cuiaba', 'AMT4AMST,M10.3.0/0,M2.3.0/0' }, - { 'America/Curacao', 'AST4' }, - { 'America/Danmarkshavn', 'GMT0' }, - { 'America/Dawson', 'PST8PDT,M3.2.0,M11.1.0' }, - { 'America/Dawson Creek', 'MST7' }, - { 'America/Denver', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Detroit', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Dominica', 'AST4' }, - { 'America/Edmonton', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Eirunepe', 'AMT4' }, - { 'America/El Salvador', 'CST6' }, - { 'America/Fortaleza', 'BRT3' }, - { 'America/Glace Bay', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'America/Goose Bay', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'America/Grand Turk', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Grenada', 'AST4' }, - { 'America/Guadeloupe', 'AST4' }, - { 'America/Guatemala', 'CST6' }, - { 'America/Guayaquil', 'ECT5' }, - { 'America/Guyana', 'GYT4' }, - { 'America/Halifax', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'America/Havana', 'CST5CDT,M3.2.0/0,M10.5.0/1' }, - { 'America/Hermosillo', 'MST7' }, - { 'America/Indiana/Indianapolis', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Knox', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Marengo', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Petersburg', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Tell City', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Vevay', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Vincennes', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Indiana/Winamac', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Inuvik', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Iqaluit', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Jamaica', 'EST5' }, - { 'America/Juneau', 'AKST9AKDT,M3.2.0,M11.1.0' }, - { 'America/Kentucky/Louisville', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Kentucky/Monticello', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Kralendijk', 'AST4' }, - { 'America/La Paz', 'BOT4' }, - { 'America/Lima', 'PET5' }, - { 'America/Los Angeles', 'PST8PDT,M3.2.0,M11.1.0' }, - { 'America/Lower Princes', 'AST4' }, - { 'America/Maceio', 'BRT3' }, - { 'America/Managua', 'CST6' }, - { 'America/Manaus', 'AMT4' }, - { 'America/Marigot', 'AST4' }, - { 'America/Martinique', 'AST4' }, - { 'America/Matamoros', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Mazatlan', 'MST7MDT,M4.1.0,M10.5.0' }, - { 'America/Menominee', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Merida', 'CST6CDT,M4.1.0,M10.5.0' }, - { 'America/Metlakatla', 'MeST8' }, - { 'America/Mexico City', 'CST6CDT,M4.1.0,M10.5.0' }, - { 'America/Miquelon', 'PMST3PMDT,M3.2.0,M11.1.0' }, - { 'America/Moncton', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'America/Monterrey', 'CST6CDT,M4.1.0,M10.5.0' }, - { 'America/Montevideo', 'UYT3UYST,M10.1.0,M3.2.0' }, - { 'America/Montreal', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Montserrat', 'AST4' }, - { 'America/Nassau', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/New York', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Nipigon', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Nome', 'AKST9AKDT,M3.2.0,M11.1.0' }, - { 'America/Noronha', 'FNT2' }, - { 'America/North Dakota/Beulah', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/North Dakota/Center', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/North Dakota/New Salem', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Ojinaga', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Panama', 'EST5' }, - { 'America/Pangnirtung', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Paramaribo', 'SRT3' }, - { 'America/Phoenix', 'MST7' }, - { 'America/Port of Spain', 'AST4' }, - { 'America/Port-au-Prince', 'EST5' }, - { 'America/Porto Velho', 'AMT4' }, - { 'America/Puerto Rico', 'AST4' }, - { 'America/Rainy River', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Rankin Inlet', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Recife', 'BRT3' }, - { 'America/Regina', 'CST6' }, - { 'America/Resolute', 'CST6CDT,M3.2.0,M11.1.0' }, - { 'America/Rio Branco', 'AMT4' }, - { 'America/Santa Isabel', 'PST8PDT,M4.1.0,M10.5.0' }, - { 'America/Santarem', 'BRT3' }, - { 'America/Santo Domingo', 'AST4' }, - { 'America/Sao Paulo', 'BRT3BRST,M10.3.0/0,M2.3.0/0' }, - { 'America/Scoresbysund', 'EGT1EGST,M3.5.0/0,M10.5.0/1' }, - { 'America/Shiprock', 'MST7MDT,M3.2.0,M11.1.0' }, - { 'America/Sitka', 'AKST9AKDT,M3.2.0,M11.1.0' }, - { 'America/St Barthelemy', 'AST4' }, - { 'America/St Johns', 'NST3:30NDT,M3.2.0,M11.1.0' }, - { 'America/St Kitts', 'AST4' }, - { 'America/St Lucia', 'AST4' }, - { 'America/St Thomas', 'AST4' }, - { 'America/St Vincent', 'AST4' }, - { 'America/Swift Current', 'CST6' }, - { 'America/Tegucigalpa', 'CST6' }, - { 'America/Thule', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'America/Thunder Bay', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Tijuana', 'PST8PDT,M3.2.0,M11.1.0' }, - { 'America/Toronto', 'EST5EDT,M3.2.0,M11.1.0' }, - { 'America/Tortola', 'AST4' }, - { 'America/Vancouver', 'PST8PDT,M3.2.0,M11.1.0' }, - { 'America/Whitehorse', 'PST8PDT,M3.2.0,M11.1.0' }, - { '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', 'WST-8' }, - { 'Antarctica/Davis', 'DAVT-7' }, - { 'Antarctica/DumontDUrville', 'DDUT-10' }, - { 'Antarctica/Macquarie', 'MIST-11' }, - { 'Antarctica/Mawson', 'MAWT-5' }, - { 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, - { 'Antarctica/Rothera', 'ROTT3' }, - { 'Antarctica/South Pole', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, - { 'Antarctica/Syowa', 'SYOT-3' }, - { 'Antarctica/Vostok', 'VOST-6' }, - { 'Arctic/Longyearbyen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Asia/Aden', 'AST-3' }, - { 'Asia/Almaty', 'ALMT-6' }, - { 'Asia/Anadyr', 'ANAT-12' }, - { 'Asia/Aqtau', 'AQTT-5' }, - { 'Asia/Aqtobe', 'AQTT-5' }, - { 'Asia/Ashgabat', 'TMT-5' }, - { 'Asia/Baghdad', 'AST-3' }, - { 'Asia/Bahrain', 'AST-3' }, - { 'Asia/Baku', 'AZT-4AZST,M3.5.0/4,M10.5.0/5' }, - { 'Asia/Bangkok', 'ICT-7' }, - { 'Asia/Beirut', 'EET-2EEST,M3.5.0/0,M10.5.0/0' }, - { 'Asia/Bishkek', 'KGT-6' }, - { 'Asia/Brunei', 'BNT-8' }, - { 'Asia/Choibalsan', 'CHOT-8' }, - { 'Asia/Chongqing', 'CST-8' }, - { 'Asia/Colombo', 'IST-5:30' }, - { 'Asia/Damascus', 'EET-2EEST,M4.1.5/0,M10.5.5/0' }, - { 'Asia/Dhaka', 'BDT-6' }, - { 'Asia/Dili', 'TLT-9' }, - { 'Asia/Dubai', 'GST-4' }, - { 'Asia/Dushanbe', 'TJT-5' }, - { 'Asia/Gaza', 'EET-2' }, - { 'Asia/Harbin', 'CST-8' }, - { 'Asia/Hebron', 'EET-2' }, - { 'Asia/Ho Chi Minh', 'ICT-7' }, - { 'Asia/Hong Kong', 'HKT-8' }, - { 'Asia/Hovd', 'HOVT-7' }, - { 'Asia/Irkutsk', 'IRKT-9' }, - { 'Asia/Jakarta', 'WIT-7' }, - { 'Asia/Jayapura', 'EIT-9' }, - { 'Asia/Kabul', 'AFT-4:30' }, - { 'Asia/Kamchatka', 'PETT-12' }, - { 'Asia/Karachi', 'PKT-5' }, - { 'Asia/Kashgar', 'CST-8' }, - { 'Asia/Kathmandu', 'NPT-5:45' }, - { 'Asia/Kolkata', 'IST-5:30' }, - { 'Asia/Krasnoyarsk', 'KRAT-8' }, - { 'Asia/Kuala Lumpur', 'MYT-8' }, - { 'Asia/Kuching', 'MYT-8' }, - { 'Asia/Kuwait', 'AST-3' }, - { 'Asia/Macau', 'CST-8' }, - { 'Asia/Magadan', 'MAGT-12' }, - { 'Asia/Makassar', 'CIT-8' }, - { 'Asia/Manila', 'PHT-8' }, - { 'Asia/Muscat', 'GST-4' }, - { 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Asia/Novokuznetsk', 'NOVT-7' }, - { 'Asia/Novosibirsk', 'NOVT-7' }, - { 'Asia/Omsk', 'OMST-7' }, - { 'Asia/Oral', 'ORAT-5' }, - { 'Asia/Phnom Penh', 'ICT-7' }, - { 'Asia/Pontianak', 'WIT-7' }, - { 'Asia/Pyongyang', 'KST-9' }, - { 'Asia/Qatar', 'AST-3' }, - { 'Asia/Qyzylorda', 'QYZT-6' }, - { 'Asia/Rangoon', 'MMT-6:30' }, - { 'Asia/Riyadh', 'AST-3' }, - { 'Asia/Sakhalin', 'SAKT-11' }, - { 'Asia/Samarkand', 'UZT-5' }, - { 'Asia/Seoul', 'KST-9' }, - { 'Asia/Shanghai', 'CST-8' }, - { 'Asia/Singapore', 'SGT-8' }, - { 'Asia/Taipei', 'CST-8' }, - { 'Asia/Tashkent', 'UZT-5' }, - { 'Asia/Tbilisi', 'GET-4' }, - { 'Asia/Thimphu', 'BTT-6' }, - { 'Asia/Tokyo', 'JST-9' }, - { 'Asia/Ulaanbaatar', 'ULAT-8' }, - { 'Asia/Urumqi', 'CST-8' }, - { 'Asia/Vientiane', 'ICT-7' }, - { 'Asia/Vladivostok', 'VLAT-11' }, - { 'Asia/Yakutsk', 'YAKT-10' }, - { 'Asia/Yekaterinburg', 'YEKT-6' }, - { 'Asia/Yerevan', 'AMT-4AMST,M3.5.0,M10.5.0/3' }, - { 'Atlantic/Azores', 'AZOT1AZOST,M3.5.0/0,M10.5.0/1' }, - { 'Atlantic/Bermuda', 'AST4ADT,M3.2.0,M11.1.0' }, - { 'Atlantic/Canary', 'WET0WEST,M3.5.0/1,M10.5.0' }, - { 'Atlantic/Cape Verde', 'CVT1' }, - { 'Atlantic/Faroe', 'WET0WEST,M3.5.0/1,M10.5.0' }, - { 'Atlantic/Madeira', 'WET0WEST,M3.5.0/1,M10.5.0' }, - { 'Atlantic/Reykjavik', 'GMT0' }, - { 'Atlantic/South Georgia', 'GST2' }, - { 'Atlantic/St Helena', 'GMT0' }, - { 'Atlantic/Stanley', 'FKT4FKST,M9.1.0,M4.3.0' }, - { 'Australia/Adelaide', 'CST-9:30CST,M10.1.0,M4.1.0/3' }, - { 'Australia/Brisbane', 'EST-10' }, - { 'Australia/Broken Hill', 'CST-9:30CST,M10.1.0,M4.1.0/3' }, - { 'Australia/Currie', 'EST-10EST,M10.1.0,M4.1.0/3' }, - { 'Australia/Darwin', 'CST-9:30' }, - { 'Australia/Eucla', 'CWST-8:45' }, - { 'Australia/Hobart', 'EST-10EST,M10.1.0,M4.1.0/3' }, - { 'Australia/Lindeman', 'EST-10' }, - { 'Australia/Lord Howe', 'LHST-10:30LHST-11,M10.1.0,M4.1.0' }, - { 'Australia/Melbourne', 'EST-10EST,M10.1.0,M4.1.0/3' }, - { 'Australia/Perth', 'WST-8' }, - { 'Australia/Sydney', 'EST-10EST,M10.1.0,M4.1.0/3' }, - { 'Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Andorra', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Athens', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Belgrade', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Berlin', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Bratislava', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Brussels', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Bucharest', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Budapest', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Chisinau', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Dublin', 'GMT0IST,M3.5.0/1,M10.5.0' }, - { 'Europe/Gibraltar', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Guernsey', 'GMT0BST,M3.5.0/1,M10.5.0' }, - { 'Europe/Helsinki', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Isle of Man', 'GMT0BST,M3.5.0/1,M10.5.0' }, - { 'Europe/Istanbul', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Jersey', 'GMT0BST,M3.5.0/1,M10.5.0' }, - { 'Europe/Kaliningrad', 'FET-3' }, - { 'Europe/Kiev', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Lisbon', 'WET0WEST,M3.5.0/1,M10.5.0' }, - { 'Europe/Ljubljana', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/London', 'GMT0BST,M3.5.0/1,M10.5.0' }, - { 'Europe/Luxembourg', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Madrid', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Malta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Mariehamn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Minsk', 'FET-3' }, - { 'Europe/Monaco', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Moscow', 'MSK-4' }, - { 'Europe/Oslo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Paris', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Podgorica', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Prague', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Riga', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Rome', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Samara', 'SAMT-4' }, - { 'Europe/San Marino', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Sarajevo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Simferopol', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Skopje', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Sofia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Stockholm', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Tallinn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Tirane', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Uzhgorod', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Vaduz', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Vatican', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Vienna', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Vilnius', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Volgograd', 'VOLT-4' }, - { 'Europe/Warsaw', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Zagreb', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Europe/Zaporozhye', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, - { 'Europe/Zurich', 'CET-1CEST,M3.5.0,M10.5.0/3' }, - { 'Indian/Antananarivo', 'EAT-3' }, - { 'Indian/Chagos', 'IOT-6' }, - { 'Indian/Christmas', 'CXT-7' }, - { 'Indian/Cocos', 'CCT-6:30' }, - { 'Indian/Comoro', 'EAT-3' }, - { 'Indian/Kerguelen', 'TFT-5' }, - { 'Indian/Mahe', 'SCT-4' }, - { 'Indian/Maldives', 'MVT-5' }, - { 'Indian/Mauritius', 'MUT-4' }, - { 'Indian/Mayotte', 'EAT-3' }, - { 'Indian/Reunion', 'RET-4' }, - { 'Pacific/Apia', 'WST-13' }, - { 'Pacific/Auckland', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, - { 'Pacific/Chatham', 'CHAST-12:45CHADT,M9.5.0/2:45,M4.1.0/3:45' }, - { 'Pacific/Chuuk', 'CHUT-10' }, - { 'Pacific/Efate', 'VUT-11' }, - { 'Pacific/Enderbury', 'PHOT-13' }, - { 'Pacific/Fakaofo', 'TKT10' }, - { 'Pacific/Fiji', 'FJT-12' }, - { 'Pacific/Funafuti', 'TVT-12' }, - { 'Pacific/Galapagos', 'GALT6' }, - { 'Pacific/Gambier', 'GAMT9' }, - { 'Pacific/Guadalcanal', 'SBT-11' }, - { 'Pacific/Guam', 'ChST-10' }, - { 'Pacific/Honolulu', 'HST10' }, - { 'Pacific/Johnston', 'HST10' }, - { 'Pacific/Kiritimati', 'LINT-14' }, - { 'Pacific/Kosrae', 'KOST-11' }, - { 'Pacific/Kwajalein', 'MHT-12' }, - { 'Pacific/Majuro', 'MHT-12' }, - { 'Pacific/Marquesas', 'MART9:30' }, - { 'Pacific/Midway', 'SST11' }, - { 'Pacific/Nauru', 'NRT-12' }, - { 'Pacific/Niue', 'NUT11' }, - { 'Pacific/Norfolk', 'NFT-11:30' }, - { 'Pacific/Noumea', 'NCT-11' }, - { 'Pacific/Pago Pago', 'SST11' }, - { 'Pacific/Palau', 'PWT-9' }, - { 'Pacific/Pitcairn', 'PST8' }, - { 'Pacific/Pohnpei', 'PONT-11' }, - { 'Pacific/Port Moresby', 'PGT-10' }, - { 'Pacific/Rarotonga', 'CKT10' }, - { 'Pacific/Saipan', 'ChST-10' }, - { 'Pacific/Tahiti', 'TAHT10' }, - { 'Pacific/Tarawa', 'GILT-12' }, - { 'Pacific/Tongatapu', 'TOT-13' }, - { 'Pacific/Wake', 'WAKT-12' }, - { 'Pacific/Wallis', 'WFT-12' }, -} diff --git a/libs/sys/luasrc/sys/zoneinfo/tzoffset.lua b/libs/sys/luasrc/sys/zoneinfo/tzoffset.lua deleted file mode 100644 index bbe75d5a47..0000000000 --- a/libs/sys/luasrc/sys/zoneinfo/tzoffset.lua +++ /dev/null @@ -1,162 +0,0 @@ ---[[ -LuCI - Autogenerated Zoneinfo Module - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - -module "luci.sys.zoneinfo.tzoffset" - -OFFSET = { - gmt = 0, -- GMT - eat = 10800, -- EAT - cet = 3600, -- CET - wat = 3600, -- WAT - cat = 7200, -- CAT - wet = 0, -- WET - sast = 7200, -- SAST - eet = 7200, -- EET - hast = -36000, -- HAST - hadt = -32400, -- HADT - akst = -32400, -- AKST - akdt = -28800, -- AKDT - ast = -14400, -- AST - brt = -10800, -- BRT - art = -10800, -- ART - pyt = -14400, -- PYT - pyst = -10800, -- PYST - est = -18000, -- EST - cst = -21600, -- CST - cdt = -18000, -- CDT - amt = -14400, -- AMT - cot = -18000, -- COT - mst = -25200, -- MST - mdt = -21600, -- MDT - vet = -16200, -- VET - gft = -10800, -- GFT - pst = -28800, -- PST - pdt = -25200, -- PDT - ect = -18000, -- ECT - gyt = -14400, -- GYT - bot = -14400, -- BOT - pet = -18000, -- PET - pmst = -10800, -- PMST - pmdt = -7200, -- PMDT - uyt = -10800, -- UYT - uyst = -7200, -- UYST - fnt = -7200, -- FNT - srt = -10800, -- SRT - egt = -3600, -- EGT - egst = 0, -- EGST - nst = -12600, -- NST - ndt = -9000, -- NDT - wst = 28800, -- WST - davt = 25200, -- DAVT - ddut = 36000, -- DDUT - mist = 39600, -- MIST - mawt = 18000, -- MAWT - nzst = 43200, -- NZST - nzdt = 46800, -- NZDT - rott = -10800, -- ROTT - syot = 10800, -- SYOT - vost = 21600, -- VOST - almt = 21600, -- ALMT - anat = 43200, -- ANAT - aqtt = 18000, -- AQTT - tmt = 18000, -- TMT - azt = 14400, -- AZT - azst = 18000, -- AZST - ict = 25200, -- ICT - kgt = 21600, -- KGT - bnt = 28800, -- BNT - chot = 28800, -- CHOT - ist = 19800, -- IST - bdt = 21600, -- BDT - tlt = 32400, -- TLT - gst = 14400, -- GST - tjt = 18000, -- TJT - hkt = 28800, -- HKT - hovt = 25200, -- HOVT - irkt = 32400, -- IRKT - wit = 25200, -- WIT - eit = 32400, -- EIT - aft = 16200, -- AFT - pett = 43200, -- PETT - pkt = 18000, -- PKT - npt = 20700, -- NPT - krat = 28800, -- KRAT - myt = 28800, -- MYT - magt = 43200, -- MAGT - cit = 28800, -- CIT - pht = 28800, -- PHT - novt = 25200, -- NOVT - omst = 25200, -- OMST - orat = 18000, -- ORAT - kst = 32400, -- KST - qyzt = 21600, -- QYZT - mmt = 23400, -- MMT - sakt = 39600, -- SAKT - uzt = 18000, -- UZT - sgt = 28800, -- SGT - get = 14400, -- GET - btt = 21600, -- BTT - jst = 32400, -- JST - ulat = 28800, -- ULAT - vlat = 39600, -- VLAT - yakt = 36000, -- YAKT - yekt = 21600, -- YEKT - azot = -3600, -- AZOT - azost = 0, -- AZOST - cvt = -3600, -- CVT - fkt = -14400, -- FKT - fkst = -10800, -- FKST - cwst = 31500, -- CWST - lhst = 37800, -- LHST - lhst = 39600, -- LHST - fet = 10800, -- FET - msk = 14400, -- MSK - samt = 14400, -- SAMT - volt = 14400, -- VOLT - iot = 21600, -- IOT - cxt = 25200, -- CXT - cct = 23400, -- CCT - tft = 18000, -- TFT - sct = 14400, -- SCT - mvt = 18000, -- MVT - mut = 14400, -- MUT - ret = 14400, -- RET - chast = 45900, -- CHAST - chadt = 49500, -- CHADT - chut = 36000, -- CHUT - vut = 39600, -- VUT - phot = 46800, -- PHOT - tkt = -36000, -- TKT - fjt = 43200, -- FJT - tvt = 43200, -- TVT - galt = -21600, -- GALT - gamt = -32400, -- GAMT - sbt = 39600, -- SBT - hst = -36000, -- HST - lint = 50400, -- LINT - kost = 39600, -- KOST - mht = 43200, -- MHT - mart = -34200, -- MART - sst = -39600, -- SST - nrt = 43200, -- NRT - nut = -39600, -- NUT - nft = 41400, -- NFT - nct = 39600, -- NCT - pwt = 32400, -- PWT - pont = 39600, -- PONT - pgt = 36000, -- PGT - ckt = -36000, -- CKT - taht = -36000, -- TAHT - gilt = 43200, -- GILT - tot = 46800, -- TOT - wakt = 43200, -- WAKT - wft = 43200, -- WFT -} diff --git a/libs/web/Makefile b/libs/web/Makefile deleted file mode 100644 index ad16ec7376..0000000000 --- a/libs/web/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -ifneq (,$(wildcard ../../build/config.mk)) -include ../../build/config.mk -include ../../build/module.mk -include ../../build/gccconfig.mk -else -include standalone.mk -endif - -TPL_LDFLAGS = -TPL_CFLAGS = -TPL_SO = parser.so -TPL_PO2LMO = po2lmo -TPL_PO2LMO_OBJ = src/po2lmo.o -TPL_LMO_OBJ = src/template_lmo.o -TPL_COMMON_OBJ = src/template_parser.o src/template_utils.o -TPL_LUALIB_OBJ = src/template_lualib.o - -%.o: %.c - $(COMPILE) $(TPL_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< - -compile: build-clean $(TPL_COMMON_OBJ) $(TPL_LUALIB_OBJ) $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ) - $(LINK) $(SHLIB_FLAGS) $(TPL_LDFLAGS) -o src/$(TPL_SO) \ - $(TPL_COMMON_OBJ) $(TPL_LMO_OBJ) $(TPL_LUALIB_OBJ) - $(LINK) -o src/$(TPL_PO2LMO) \ - $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ) - mkdir -p dist$(LUCI_LIBRARYDIR)/template - cp src/$(TPL_SO) dist$(LUCI_LIBRARYDIR)/template/$(TPL_SO) - -install: build - cp -pR dist$(LUA_LIBRARYDIR)/* $(LUA_LIBRARYDIR) - -clean: build-clean - -build-clean: - rm -f src/*.o src/$(TPL_SO) - -host-compile: build-clean host-clean $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ) - $(LINK) -o src/$(TPL_PO2LMO) $(TPL_LMO_OBJ) $(TPL_PO2LMO_OBJ) - -host-install: host-compile - cp src/$(TPL_PO2LMO) ../../build/$(TPL_PO2LMO) - -host-clean: - rm -f src/$(TPL_PO2LMO) - rm -f ../../build/$(TPL_PO2LMO) diff --git a/libs/web/htdocs/luci-static/resources/cbi.js b/libs/web/htdocs/luci-static/resources/cbi.js deleted file mode 100644 index 02814a5428..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi.js +++ /dev/null @@ -1,1339 +0,0 @@ -/* - LuCI - Lua Configuration Interface - - Copyright 2008 Steven Barth <steven@midlink.org> - Copyright 2008-2012 Jo-Philipp Wich <xm@subsignal.org> - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 -*/ - -var cbi_d = []; -var cbi_t = []; -var cbi_c = []; - -var cbi_validators = { - - 'integer': function() - { - return (this.match(/^-?[0-9]+$/) != null); - }, - - 'uinteger': function() - { - return (cbi_validators.integer.apply(this) && (this >= 0)); - }, - - 'float': function() - { - return !isNaN(parseFloat(this)); - }, - - 'ufloat': function() - { - return (cbi_validators['float'].apply(this) && (this >= 0)); - }, - - 'ipaddr': function() - { - return cbi_validators.ip4addr.apply(this) || - cbi_validators.ip6addr.apply(this); - }, - - 'ip4addr': function() - { - if (this.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(\/(\S+))?$/)) - { - return (RegExp.$1 >= 0) && (RegExp.$1 <= 255) && - (RegExp.$2 >= 0) && (RegExp.$2 <= 255) && - (RegExp.$3 >= 0) && (RegExp.$3 <= 255) && - (RegExp.$4 >= 0) && (RegExp.$4 <= 255) && - ((RegExp.$6.indexOf('.') < 0) - ? ((RegExp.$6 >= 0) && (RegExp.$6 <= 32)) - : (cbi_validators.ip4addr.apply(RegExp.$6))) - ; - } - - return false; - }, - - 'ip6addr': function() - { - if( this.match(/^([a-fA-F0-9:.]+)(\/(\d+))?$/) ) - { - if( !RegExp.$2 || ((RegExp.$3 >= 0) && (RegExp.$3 <= 128)) ) - { - var addr = RegExp.$1; - - if( addr == '::' ) - { - return true; - } - - if( addr.indexOf('.') > 0 ) - { - var off = addr.lastIndexOf(':'); - - if( !(off && cbi_validators.ip4addr.apply(addr.substr(off+1))) ) - return false; - - addr = addr.substr(0, off) + ':0:0'; - } - - if( addr.indexOf('::') >= 0 ) - { - var colons = 0; - var fill = '0'; - - for( var i = 1; i < (addr.length-1); i++ ) - if( addr.charAt(i) == ':' ) - colons++; - - if( colons > 7 ) - return false; - - for( var i = 0; i < (7 - colons); i++ ) - fill += ':0'; - - if (addr.match(/^(.*?)::(.*?)$/)) - addr = (RegExp.$1 ? RegExp.$1 + ':' : '') + fill + - (RegExp.$2 ? ':' + RegExp.$2 : ''); - } - - return (addr.match(/^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/) != null); - } - } - - return false; - }, - - 'port': function() - { - return cbi_validators.integer.apply(this) && - (this >= 0) && (this <= 65535); - }, - - 'portrange': function() - { - if (this.match(/^(\d+)-(\d+)$/)) - { - var p1 = RegExp.$1; - var p2 = RegExp.$2; - - return cbi_validators.port.apply(p1) && - cbi_validators.port.apply(p2) && - (parseInt(p1) <= parseInt(p2)) - ; - } - else - { - return cbi_validators.port.apply(this); - } - }, - - 'macaddr': function() - { - return (this.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null); - }, - - 'host': function() - { - return cbi_validators.hostname.apply(this) || - cbi_validators.ipaddr.apply(this); - }, - - 'hostname': function() - { - if (this.length <= 253) - 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.]/))); - - return false; - }, - - 'network': function() - { - return cbi_validators.uciname.apply(this) || - cbi_validators.host.apply(this); - }, - - 'wpakey': function() - { - var v = this; - - if( v.length == 64 ) - return (v.match(/^[a-fA-F0-9]{64}$/) != null); - else - return (v.length >= 8) && (v.length <= 63); - }, - - 'wepkey': function() - { - var v = this; - - if ( v.substr(0,2) == 's:' ) - v = v.substr(2); - - if( (v.length == 10) || (v.length == 26) ) - return (v.match(/^[a-fA-F0-9]{10,26}$/) != null); - else - return (v.length == 5) || (v.length == 13); - }, - - 'uciname': function() - { - return (this.match(/^[a-zA-Z0-9_]+$/) != null); - }, - - 'range': function(min, max) - { - var val = parseFloat(this); - if (!isNaN(min) && !isNaN(max) && !isNaN(val)) - return ((val >= min) && (val <= max)); - - return false; - }, - - 'min': function(min) - { - var val = parseFloat(this); - if (!isNaN(min) && !isNaN(val)) - return (val >= min); - - return false; - }, - - 'max': function(max) - { - var val = parseFloat(this); - if (!isNaN(max) && !isNaN(val)) - return (val <= max); - - return false; - }, - - 'rangelength': function(min, max) - { - var val = '' + this; - if (!isNaN(min) && !isNaN(max)) - return ((val.length >= min) && (val.length <= max)); - - return false; - }, - - 'minlength': function(min) - { - var val = '' + this; - if (!isNaN(min)) - return (val.length >= min); - - return false; - }, - - 'maxlength': function(max) - { - var val = '' + this; - if (!isNaN(max)) - return (val.length <= max); - - return false; - }, - - 'or': function() - { - for (var i = 0; i < arguments.length; i += 2) - { - if (typeof arguments[i] != 'function') - { - if (arguments[i] == this) - return true; - i--; - } - else if (arguments[i].apply(this, arguments[i+1])) - { - return true; - } - } - return false; - }, - - 'and': function() - { - for (var i = 0; i < arguments.length; i += 2) - { - if (typeof arguments[i] != 'function') - { - if (arguments[i] != this) - return false; - i--; - } - else if (!arguments[i].apply(this, arguments[i+1])) - { - return false; - } - } - return true; - }, - - 'neg': function() - { - return cbi_validators.or.apply( - this.replace(/^[ \t]*![ \t]*/, ''), arguments); - }, - - 'list': function(subvalidator, subargs) - { - if (typeof subvalidator != 'function') - return false; - - var tokens = this.match(/[^ \t]+/g); - for (var i = 0; i < tokens.length; i++) - if (!subvalidator.apply(tokens[i], subargs)) - return false; - - return true; - }, - 'phonedigit': function() - { - return (this.match(/^[0-9\*#!\.]+$/) != null); - } -}; - - -function cbi_d_add(field, dep, next) { - var obj = document.getElementById(field); - if (obj) { - var entry - for (var i=0; i<cbi_d.length; i++) { - if (cbi_d[i].id == field) { - entry = cbi_d[i]; - break; - } - } - if (!entry) { - entry = { - "node": obj, - "id": field, - "parent": obj.parentNode.id, - "next": next, - "deps": [] - }; - cbi_d.unshift(entry); - } - entry.deps.push(dep) - } -} - -function cbi_d_checkvalue(target, ref) { - var t = document.getElementById(target); - var value; - - if (!t) { - var tl = document.getElementsByName(target); - - if( tl.length > 0 && (tl[0].type == 'radio' || tl[0].type == 'checkbox')) - for( var i = 0; i < tl.length; i++ ) - if( tl[i].checked ) { - value = tl[i].value; - break; - } - - value = value ? value : ""; - } else if (!t.value) { - value = ""; - } else { - value = t.value; - - if (t.type == "checkbox") { - value = t.checked ? value : ""; - } - } - - return (value == ref) -} - -function cbi_d_check(deps) { - var reverse; - var def = false; - for (var i=0; i<deps.length; i++) { - var istat = true; - reverse = false; - for (var j in deps[i]) { - if (j == "!reverse") { - reverse = true; - } else if (j == "!default") { - def = true; - istat = false; - } else { - istat = (istat && cbi_d_checkvalue(j, deps[i][j])) - } - } - if (istat) { - return !reverse; - } - } - return def; -} - -function cbi_d_update() { - var state = false; - for (var i=0; i<cbi_d.length; i++) { - var entry = cbi_d[i]; - var next = document.getElementById(entry.next) - var node = document.getElementById(entry.id) - var parent = document.getElementById(entry.parent) - - if (node && node.parentNode && !cbi_d_check(entry.deps)) { - node.parentNode.removeChild(node); - state = true; - if( entry.parent ) - cbi_c[entry.parent]--; - } else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) { - if (!next) { - parent.appendChild(entry.node); - } else { - next.parentNode.insertBefore(entry.node, next); - } - state = true; - if( entry.parent ) - cbi_c[entry.parent]++; - } - } - - if (entry && entry.parent) { - if (!cbi_t_update()) - cbi_tag_last(parent); - } - - if (state) { - cbi_d_update(); - } -} - -function cbi_bind(obj, type, callback, mode) { - if (!obj.addEventListener) { - obj.attachEvent('on' + type, - function(){ - var e = window.event; - - if (!e.target && e.srcElement) - e.target = e.srcElement; - - return !!callback(e); - } - ); - } else { - obj.addEventListener(type, callback, !!mode); - } - return obj; -} - -function cbi_combobox(id, values, def, man) { - var selid = "cbi.combobox." + id; - if (document.getElementById(selid)) { - return - } - - var obj = document.getElementById(id) - var sel = document.createElement("select"); - sel.id = selid; - sel.className = obj.className.replace(/cbi-input-text/, 'cbi-input-select'); - - if (obj.nextSibling) { - obj.parentNode.insertBefore(sel, obj.nextSibling); - } else { - obj.parentNode.appendChild(sel); - } - - var dt = obj.getAttribute('cbi_datatype'); - var op = obj.getAttribute('cbi_optional'); - - if (dt) - cbi_validate_field(sel, op == 'true', dt); - - if (!values[obj.value]) { - if (obj.value == "") { - var optdef = document.createElement("option"); - optdef.value = ""; - optdef.appendChild(document.createTextNode(def)); - sel.appendChild(optdef); - } else { - var opt = document.createElement("option"); - opt.value = obj.value; - opt.selected = "selected"; - opt.appendChild(document.createTextNode(obj.value)); - sel.appendChild(opt); - } - } - - for (var i in values) { - var opt = document.createElement("option"); - opt.value = i; - - if (obj.value == i) { - opt.selected = "selected"; - } - - opt.appendChild(document.createTextNode(values[i])); - sel.appendChild(opt); - } - - var optman = document.createElement("option"); - optman.value = ""; - optman.appendChild(document.createTextNode(man)); - sel.appendChild(optman); - - obj.style.display = "none"; - - cbi_bind(sel, "change", function() { - if (sel.selectedIndex == sel.options.length - 1) { - obj.style.display = "inline"; - sel.parentNode.removeChild(sel); - obj.focus(); - } else { - obj.value = sel.options[sel.selectedIndex].value; - } - - try { - cbi_d_update(); - } catch (e) { - //Do nothing - } - }) - - // Retrigger validation in select - sel.focus(); - sel.blur(); -} - -function cbi_combobox_init(id, values, def, man) { - var obj = document.getElementById(id); - cbi_bind(obj, "blur", function() { - cbi_combobox(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(); -} - -function cbi_browser_init(id, respath, url, defpath) -{ - function cbi_browser_btnclick(e) { - cbi_filebrowser(id, url, defpath); - return false; - } - - var field = document.getElementById(id); - - var btn = document.createElement('img'); - btn.className = 'cbi-image-button'; - btn.src = respath + '/cbi/folder.gif'; - field.parentNode.insertBefore(btn, field.nextSibling); - - cbi_bind(btn, 'click', cbi_browser_btnclick); -} - -function cbi_dynlist_init(name, respath, datatype, optional, choices) -{ - var input0 = document.getElementsByName(name)[0]; - var prefix = input0.name; - var parent = input0.parentNode; - var holder = input0.placeholder; - - var values; - - function cbi_dynlist_redraw(focus, add, del) - { - values = [ ]; - - while (parent.firstChild) - { - var n = parent.firstChild; - var i = parseInt(n.index); - - if (i != del) - { - if (n.nodeName.toLowerCase() == 'input') - values.push(n.value || ''); - else if (n.nodeName.toLowerCase() == 'select') - values[values.length-1] = n.options[n.selectedIndex].value; - } - - parent.removeChild(n); - } - - if (add >= 0) - { - focus = add+1; - values.splice(focus, 0, ''); - } - else if (values.length == 0) - { - focus = 0; - values.push(''); - } - - for (var i = 0; i < values.length; i++) - { - var t = document.createElement('input'); - t.id = prefix + '.' + (i+1); - t.name = prefix; - t.value = values[i]; - t.type = 'text'; - t.index = i; - t.className = 'cbi-input-text'; - - if (i == 0 && holder) - { - t.placeholder = holder; - } - - var b = document.createElement('img'); - b.src = respath + ((i+1) < values.length ? '/cbi/remove.gif' : '/cbi/add.gif'); - b.className = 'cbi-image-button'; - - parent.appendChild(t); - parent.appendChild(b); - parent.appendChild(document.createElement('br')); - - if (datatype) - { - cbi_validate_field(t.id, ((i+1) == values.length) || optional, datatype); - } - - if (choices) - { - cbi_combobox_init(t.id, choices[0], '', choices[1]); - t.nextSibling.index = i; - - cbi_bind(t.nextSibling, 'keydown', cbi_dynlist_keydown); - cbi_bind(t.nextSibling, 'keypress', cbi_dynlist_keypress); - - if (i == focus || -i == focus) - t.nextSibling.focus(); - } - else - { - cbi_bind(t, 'keydown', cbi_dynlist_keydown); - cbi_bind(t, 'keypress', cbi_dynlist_keypress); - - if (i == focus) - { - t.focus(); - } - else if (-i == focus) - { - t.focus(); - - /* force cursor to end */ - var v = t.value; - t.value = ' ' - t.value = v; - } - } - - cbi_bind(b, 'click', cbi_dynlist_btnclick); - } - } - - function cbi_dynlist_keypress(ev) - { - ev = ev ? ev : window.event; - - var se = ev.target ? ev.target : ev.srcElement; - - if (se.nodeType == 3) - se = se.parentNode; - - switch (ev.keyCode) - { - /* backspace, delete */ - case 8: - case 46: - if (se.value.length == 0) - { - if (ev.preventDefault) - ev.preventDefault(); - - return false; - } - - return true; - - /* enter, arrow up, arrow down */ - case 13: - case 38: - case 40: - if (ev.preventDefault) - ev.preventDefault(); - - return false; - } - - return true; - } - - function cbi_dynlist_keydown(ev) - { - ev = ev ? ev : window.event; - - var se = ev.target ? ev.target : ev.srcElement; - - if (se.nodeType == 3) - se = se.parentNode; - - var prev = se.previousSibling; - while (prev && prev.name != name) - prev = prev.previousSibling; - - var next = se.nextSibling; - while (next && next.name != name) - next = next.nextSibling; - - /* advance one further in combobox case */ - if (next && next.nextSibling.name == name) - next = next.nextSibling; - - switch (ev.keyCode) - { - /* backspace, delete */ - case 8: - case 46: - var del = (se.nodeName.toLowerCase() == 'select') - ? true : (se.value.length == 0); - - if (del) - { - if (ev.preventDefault) - ev.preventDefault(); - - var focus = se.index; - if (ev.keyCode == 8) - focus = -focus+1; - - cbi_dynlist_redraw(focus, -1, se.index); - - return false; - } - - break; - - /* enter */ - case 13: - cbi_dynlist_redraw(-1, se.index, -1); - break; - - /* arrow up */ - case 38: - if (prev) - prev.focus(); - - break; - - /* arrow down */ - case 40: - if (next) - next.focus(); - - break; - } - - return true; - } - - function cbi_dynlist_btnclick(ev) - { - ev = ev ? ev : window.event; - - var se = ev.target ? ev.target : ev.srcElement; - - if (se.src.indexOf('remove') > -1) - { - se.previousSibling.value = ''; - - cbi_dynlist_keydown({ - target: se.previousSibling, - keyCode: 8 - }); - } - else - { - cbi_dynlist_keydown({ - target: se.previousSibling, - keyCode: 13 - }); - } - - return false; - } - - cbi_dynlist_redraw(NaN, -1, -1); -} - -//Hijacks the CBI form to send via XHR (requires Prototype) -function cbi_hijack_forms(layer, win, fail, load) { - var forms = layer.getElementsByTagName('form'); - for (var i=0; i<forms.length; i++) { - $(forms[i]).observe('submit', function(event) { - // Prevent the form from also submitting the regular way - event.stop(); - - // Submit via XHR - event.element().request({ - onSuccess: win, - onFailure: fail - }); - - if (load) { - load(); - } - }); - } -} - - -function cbi_t_add(section, tab) { - var t = document.getElementById('tab.' + section + '.' + tab); - var c = document.getElementById('container.' + section + '.' + tab); - - if( t && c ) { - cbi_t[section] = (cbi_t[section] || [ ]); - cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id }; - } -} - -function cbi_t_switch(section, tab) { - if( cbi_t[section] && cbi_t[section][tab] ) { - var o = cbi_t[section][tab]; - var h = document.getElementById('tab.' + section); - for( var tid in cbi_t[section] ) { - var o2 = cbi_t[section][tid]; - if( o.tab.id != o2.tab.id ) { - o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled "); - o2.container.style.display = 'none'; - } - else { - if(h) h.value = tab; - o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab "); - o2.container.style.display = 'block'; - } - } - } - return false -} - -function cbi_t_update() { - var hl_tabs = [ ]; - var updated = false; - - for( var sid in cbi_t ) - for( var tid in cbi_t[sid] ) - { - if( cbi_c[cbi_t[sid][tid].cid] == 0 ) { - cbi_t[sid][tid].tab.style.display = 'none'; - } - else if( cbi_t[sid][tid].tab && cbi_t[sid][tid].tab.style.display == 'none' ) { - cbi_t[sid][tid].tab.style.display = ''; - - var t = cbi_t[sid][tid].tab; - t.className += ' cbi-tab-highlighted'; - hl_tabs.push(t); - } - - cbi_tag_last(cbi_t[sid][tid].container); - updated = true; - } - - if( hl_tabs.length > 0 ) - window.setTimeout(function() { - for( var i = 0; i < hl_tabs.length; i++ ) - hl_tabs[i].className = hl_tabs[i].className.replace(/ cbi-tab-highlighted/g, ''); - }, 750); - - return updated; -} - - -function cbi_validate_form(form, errmsg) -{ - /* if triggered by a section removal or addition, don't validate */ - if( form.cbi_state == 'add-section' || form.cbi_state == 'del-section' ) - return true; - - if( form.cbi_validators ) - { - for( var i = 0; i < form.cbi_validators.length; i++ ) - { - var validator = form.cbi_validators[i]; - if( !validator() && errmsg ) - { - alert(errmsg); - return false; - } - } - } - - return true; -} - -function cbi_validate_reset(form) -{ - window.setTimeout( - function() { cbi_validate_form(form, null) }, 100 - ); - - return true; -} - -function cbi_validate_compile(code) -{ - var pos = 0; - var esc = false; - var depth = 0; - var stack = [ ]; - - code += ','; - - for (var i = 0; i < code.length; i++) - { - if (esc) - { - esc = false; - continue; - } - - switch (code.charCodeAt(i)) - { - case 92: - esc = true; - break; - - case 40: - case 44: - if (depth <= 0) - { - if (pos < i) - { - var label = code.substring(pos, i); - label = label.replace(/\\(.)/g, '$1'); - label = label.replace(/^[ \t]+/g, ''); - label = label.replace(/[ \t]+$/g, ''); - - if (label && !isNaN(label)) - { - stack.push(parseFloat(label)); - } - else if (label.match(/^(['"]).*\1$/)) - { - stack.push(label.replace(/^(['"])(.*)\1$/, '$2')); - } - else if (typeof cbi_validators[label] == 'function') - { - stack.push(cbi_validators[label]); - stack.push(null); - } - else - { - throw "Syntax error, unhandled token '"+label+"'"; - } - } - pos = i+1; - } - depth += (code.charCodeAt(i) == 40); - break; - - case 41: - if (--depth <= 0) - { - if (typeof stack[stack.length-2] != 'function') - throw "Syntax error, argument list follows non-function"; - - stack[stack.length-1] = - arguments.callee(code.substring(pos, i)); - - pos = i+1; - } - break; - } - } - - return stack; -} - -function cbi_validate_field(cbid, optional, type) -{ - var field = (typeof cbid == "string") ? document.getElementById(cbid) : cbid; - var vstack; try { vstack = cbi_validate_compile(type); } catch(e) { }; - - if (field && vstack && typeof vstack[0] == "function") - { - var validator = function() - { - // is not detached - if( field.form ) - { - field.className = field.className.replace(/ cbi-input-invalid/g, ''); - - // validate value - var value = (field.options && field.options.selectedIndex > -1) - ? field.options[field.options.selectedIndex].value : field.value; - - if (!(((value.length == 0) && optional) || vstack[0].apply(value, vstack[1]))) - { - // invalid - field.className += ' cbi-input-invalid'; - return false; - } - } - - return true; - }; - - if( ! field.form.cbi_validators ) - field.form.cbi_validators = [ ]; - - field.form.cbi_validators.push(validator); - - cbi_bind(field, "blur", validator); - cbi_bind(field, "keyup", validator); - - if (field.nodeName == 'SELECT') - { - cbi_bind(field, "change", validator); - cbi_bind(field, "click", validator); - } - - field.setAttribute("cbi_validate", validator); - field.setAttribute("cbi_datatype", type); - field.setAttribute("cbi_optional", (!!optional).toString()); - - validator(); - - var fcbox = document.getElementById('cbi.combobox.' + field.id); - if (fcbox) - cbi_validate_field(fcbox, optional, type); - } -} - -function cbi_row_swap(elem, up, store) -{ - var tr = elem.parentNode; - while (tr && tr.nodeName.toLowerCase() != 'tr') - tr = tr.parentNode; - - if (!tr) - return false; - - var table = tr.parentNode; - while (table && table.nodeName.toLowerCase() != 'table') - table = table.parentNode; - - if (!table) - return false; - - var s = up ? 3 : 2; - var e = up ? table.rows.length : table.rows.length - 1; - - for (var idx = s; idx < e; idx++) - { - if (table.rows[idx] == tr) - { - if (up) - tr.parentNode.insertBefore(table.rows[idx], table.rows[idx-1]); - else - tr.parentNode.insertBefore(table.rows[idx+1], table.rows[idx]); - - break; - } - } - - var ids = [ ]; - for (idx = 2; idx < table.rows.length; idx++) - { - table.rows[idx].className = table.rows[idx].className.replace( - /cbi-rowstyle-[12]/, 'cbi-rowstyle-' + (1 + (idx % 2)) - ); - - if (table.rows[idx].id && table.rows[idx].id.match(/-([^\-]+)$/) ) - ids.push(RegExp.$1); - } - - var input = document.getElementById(store); - if (input) - input.value = ids.join(' '); - - return false; -} - -function cbi_tag_last(container) -{ - var last; - - for (var i = 0; i < container.childNodes.length; i++) - { - var c = container.childNodes[i]; - if (c.nodeType == 1 && c.nodeName.toLowerCase() == 'div') - { - c.className = c.className.replace(/ cbi-value-last$/, ''); - last = c; - } - } - - if (last) - { - last.className += ' cbi-value-last'; - } -} - -String.prototype.serialize = function() -{ - var o = this; - switch(typeof(o)) - { - case 'object': - // null - if( o == null ) - { - return 'null'; - } - - // array - else if( o.length ) - { - var i, s = ''; - - for( var i = 0; i < o.length; i++ ) - s += (s ? ', ' : '') + String.serialize(o[i]); - - return '[ ' + s + ' ]'; - } - - // object - else - { - var k, s = ''; - - for( k in o ) - s += (s ? ', ' : '') + k + ': ' + String.serialize(o[k]); - - return '{ ' + s + ' }'; - } - - break; - - case 'string': - // complex string - if( o.match(/[^a-zA-Z0-9_,.: -]/) ) - return 'decodeURIComponent("' + encodeURIComponent(o) + '")'; - - // simple string - else - return '"' + o + '"'; - - break; - - default: - return o.toString(); - } -} - -String.prototype.format = function() -{ - if (!RegExp) - return; - - var html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>']; - var quot_esc = [/"/g, '"', /'/g, ''']; - - function esc(s, r) { - for( var i = 0; i < r.length; i += 2 ) - s = s.replace(r[i], r[i+1]); - return s; - } - - var str = this; - var out = ''; - var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/; - var a = b = [], numSubstitutions = 0, numMatches = 0; - - while( a = re.exec(str) ) - { - var m = a[1]; - var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5]; - var pPrecision = a[6], pType = a[7]; - - numMatches++; - - if (pType == '%') - { - subst = '%'; - } - else - { - if (numSubstitutions < arguments.length) - { - var param = arguments[numSubstitutions++]; - - var pad = ''; - if (pPad && pPad.substr(0,1) == "'") - pad = leftpart.substr(1,1); - else if (pPad) - pad = pPad; - - var justifyRight = true; - if (pJustify && pJustify === "-") - justifyRight = false; - - var minLength = -1; - if (pMinLength) - minLength = parseInt(pMinLength); - - var precision = -1; - if (pPrecision && pType == 'f') - precision = parseInt(pPrecision.substring(1)); - - var subst = param; - - switch(pType) - { - case 'b': - subst = (parseInt(param) || 0).toString(2); - break; - - case 'c': - subst = String.fromCharCode(parseInt(param) || 0); - break; - - case 'd': - subst = (parseInt(param) || 0); - break; - - case 'u': - subst = Math.abs(parseInt(param) || 0); - break; - - case 'f': - subst = (precision > -1) - ? ((parseFloat(param) || 0.0)).toFixed(precision) - : (parseFloat(param) || 0.0); - break; - - case 'o': - subst = (parseInt(param) || 0).toString(8); - break; - - case 's': - subst = param; - break; - - case 'x': - subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase(); - break; - - case 'X': - subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase(); - break; - - case 'h': - subst = esc(param, html_esc); - break; - - case 'q': - subst = esc(param, quot_esc); - break; - - case 'j': - subst = String.serialize(param); - break; - - case 't': - var td = 0; - var th = 0; - var tm = 0; - var ts = (param || 0); - - if (ts > 60) { - tm = Math.floor(ts / 60); - ts = (ts % 60); - } - - if (tm > 60) { - th = Math.floor(tm / 60); - tm = (tm % 60); - } - - if (th > 24) { - td = Math.floor(th / 24); - th = (th % 24); - } - - subst = (td > 0) - ? String.format('%dd %dh %dm %ds', td, th, tm, ts) - : String.format('%dh %dm %ds', th, tm, ts); - - break; - - case 'm': - var mf = pMinLength ? parseInt(pMinLength) : 1000; - var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2; - - var i = 0; - var val = parseFloat(param || 0); - var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ]; - - for (i = 0; (i < units.length) && (val > mf); i++) - val /= mf; - - subst = val.toFixed(pr) + ' ' + units[i]; - break; - } - } - } - - out += leftpart + subst; - str = str.substr(m.length); - } - - return out + str; -} - -String.prototype.nobr = function() -{ - return this.replace(/[\s\n]+/g, ' '); -} - -String.serialize = function() -{ - var a = [ ]; - for (var i = 1; i < arguments.length; i++) - a.push(arguments[i]); - return ''.serialize.apply(arguments[0], a); -} - -String.format = function() -{ - var a = [ ]; - for (var i = 1; i < arguments.length; i++) - a.push(arguments[i]); - return ''.format.apply(arguments[0], a); -} - -String.nobr = function() -{ - var a = [ ]; - for (var i = 1; i < arguments.length; i++) - a.push(arguments[i]); - return ''.nobr.apply(arguments[0], a); -} diff --git a/libs/web/htdocs/luci-static/resources/cbi/add.gif b/libs/web/htdocs/luci-static/resources/cbi/add.gif Binary files differdeleted file mode 100644 index 0888abf85e..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/add.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/apply.gif b/libs/web/htdocs/luci-static/resources/cbi/apply.gif Binary files differdeleted file mode 100644 index 82ae7ed821..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/apply.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/arrow.gif b/libs/web/htdocs/luci-static/resources/cbi/arrow.gif Binary files differdeleted file mode 100644 index 10d797e9b0..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/arrow.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/down.gif b/libs/web/htdocs/luci-static/resources/cbi/down.gif Binary files differdeleted file mode 100644 index f0bb6a4ea6..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/down.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/download.gif b/libs/web/htdocs/luci-static/resources/cbi/download.gif Binary files differdeleted file mode 100644 index f99a5383b2..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/download.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/edit.gif b/libs/web/htdocs/luci-static/resources/cbi/edit.gif Binary files differdeleted file mode 100644 index 7b02b6e72a..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/edit.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/fieldadd.gif b/libs/web/htdocs/luci-static/resources/cbi/fieldadd.gif Binary files differdeleted file mode 100644 index 431ff64d1f..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/fieldadd.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/file.gif b/libs/web/htdocs/luci-static/resources/cbi/file.gif Binary files differdeleted file mode 100644 index 3b1217dd65..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/file.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/find.gif b/libs/web/htdocs/luci-static/resources/cbi/find.gif Binary files differdeleted file mode 100644 index 9ae5e3489b..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/find.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/folder.gif b/libs/web/htdocs/luci-static/resources/cbi/folder.gif Binary files differdeleted file mode 100644 index 22b583bb59..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/folder.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/help.gif b/libs/web/htdocs/luci-static/resources/cbi/help.gif Binary files differdeleted file mode 100644 index 9dfa0e196a..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/help.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/key.gif b/libs/web/htdocs/luci-static/resources/cbi/key.gif Binary files differdeleted file mode 100644 index e3853e5afd..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/key.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/link.gif b/libs/web/htdocs/luci-static/resources/cbi/link.gif Binary files differdeleted file mode 100644 index f0bb78da6b..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/link.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/reload.gif b/libs/web/htdocs/luci-static/resources/cbi/reload.gif Binary files differdeleted file mode 100644 index 8268958a19..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/reload.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/remove.gif b/libs/web/htdocs/luci-static/resources/cbi/remove.gif Binary files differdeleted file mode 100644 index bf43a0a0bc..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/remove.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/reset.gif b/libs/web/htdocs/luci-static/resources/cbi/reset.gif Binary files differdeleted file mode 100644 index c941c19028..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/reset.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/save.gif b/libs/web/htdocs/luci-static/resources/cbi/save.gif Binary files differdeleted file mode 100644 index 35e949963e..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/save.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/up.gif b/libs/web/htdocs/luci-static/resources/cbi/up.gif Binary files differdeleted file mode 100644 index e8234178ef..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/up.gif +++ /dev/null diff --git a/libs/web/htdocs/luci-static/resources/cbi/user.gif b/libs/web/htdocs/luci-static/resources/cbi/user.gif Binary files differdeleted file mode 100644 index dcb5c2a899..0000000000 --- a/libs/web/htdocs/luci-static/resources/cbi/user.gif +++ /dev/null diff --git a/libs/web/luasrc/cacheloader.lua b/libs/web/luasrc/cacheloader.lua deleted file mode 100644 index 942c4b7b48..0000000000 --- a/libs/web/luasrc/cacheloader.lua +++ /dev/null @@ -1,23 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -Copyright 2008 Steven Barth <steven@midlink.org> -Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ -]]-- - -local config = require "luci.config" -local ccache = require "luci.ccache" - -module "luci.cacheloader" - -if config.ccache and config.ccache.enable == "1" then - ccache.cache_ondemand() -end
\ No newline at end of file diff --git a/libs/web/luasrc/cbi.lua b/libs/web/luasrc/cbi.lua deleted file mode 100644 index ae570b1556..0000000000 --- a/libs/web/luasrc/cbi.lua +++ /dev/null @@ -1,1850 +0,0 @@ ---[[ -LuCI - Configuration Bind Interface - -Description: -Offers an interface for binding configuration values to certain -data types. Supports value and range validation and basic dependencies. - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- -module("luci.cbi", package.seeall) - -require("luci.template") -local util = require("luci.util") -require("luci.http") - - ---local event = require "luci.sys.event" -local fs = require("nixio.fs") -local uci = require("luci.model.uci") -local datatypes = require("luci.cbi.datatypes") -local class = util.class -local instanceof = util.instanceof - -FORM_NODATA = 0 -FORM_PROCEED = 0 -FORM_VALID = 1 -FORM_DONE = 1 -FORM_INVALID = -1 -FORM_CHANGED = 2 -FORM_SKIP = 4 - -AUTO = true - -CREATE_PREFIX = "cbi.cts." -REMOVE_PREFIX = "cbi.rts." -RESORT_PREFIX = "cbi.sts." -FEXIST_PREFIX = "cbi.cbe." - --- Loads a CBI map from given file, creating an environment and returns it -function load(cbimap, ...) - local fs = require "nixio.fs" - local i18n = require "luci.i18n" - require("luci.config") - require("luci.util") - - local upldir = "/lib/uci/upload/" - local cbidir = luci.util.libpath() .. "/model/cbi/" - local func, err - - if fs.access(cbidir..cbimap..".lua") then - func, err = loadfile(cbidir..cbimap..".lua") - elseif fs.access(cbimap) then - func, err = loadfile(cbimap) - else - func, err = nil, "Model '" .. cbimap .. "' not found!" - end - - assert(func, err) - - local env = { - translate=i18n.translate, - translatef=i18n.translatef, - arg={...} - } - - setfenv(func, setmetatable(env, {__index = - function(tbl, key) - return rawget(tbl, key) or _M[key] or _G[key] - end})) - - local maps = { func() } - local uploads = { } - local has_upload = false - - for i, map in ipairs(maps) do - if not instanceof(map, Node) then - error("CBI map returns no valid map object!") - 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 or '1') .. '.' .. - 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 ) or s - if 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 - --- --- Compile a datatype specification into a parse tree for evaluation later on --- -local cdt_cache = { } - -function compile_datatype(code) - local i - local pos = 0 - local esc = false - local depth = 0 - local stack = { } - - for i = 1, #code+1 do - local byte = code:byte(i) or 44 - if esc then - esc = false - elseif byte == 92 then - esc = true - elseif byte == 40 or byte == 44 then - if depth <= 0 then - if pos < i then - local label = code:sub(pos, i-1) - :gsub("\\(.)", "%1") - :gsub("^%s+", "") - :gsub("%s+$", "") - - if #label > 0 and tonumber(label) then - stack[#stack+1] = tonumber(label) - elseif label:match("^'.*'$") or label:match('^".*"$') then - stack[#stack+1] = label:gsub("[\"'](.*)[\"']", "%1") - elseif type(datatypes[label]) == "function" then - stack[#stack+1] = datatypes[label] - stack[#stack+1] = { } - else - error("Datatype error, bad token %q" % label) - end - end - pos = i + 1 - end - depth = depth + (byte == 40 and 1 or 0) - elseif byte == 41 then - depth = depth - 1 - if depth <= 0 then - if type(stack[#stack-1]) ~= "function" then - error("Datatype error, argument list follows non-function") - end - stack[#stack] = compile_datatype(code:sub(pos, i-1)) - pos = i + 1 - end - end - end - - return stack -end - -function verify_datatype(dt, value) - if dt and #dt > 0 then - if not cdt_cache[dt] then - local c = compile_datatype(dt) - if c and type(c[1]) == "function" then - cdt_cache[dt] = c - else - error("Datatype error, not a function expression") - end - end - if cdt_cache[dt] then - return cdt_cache[dt][1](value, unpack(cdt_cache[dt][2])) - end - end - return true -end - - --- Node pseudo abstract class -Node = class() - -function Node.__init__(self, title, description) - self.children = {} - self.title = title or "" - self.description = description or "" - self.template = "cbi/node" -end - --- hook helper -function Node._run_hook(self, hook) - if type(self[hook]) == "function" then - return self[hook](self) - end -end - -function Node._run_hooks(self, ...) - local f - local r = false - for _, f in ipairs(arg) do - if type(self[f]) == "function" then - self[f](self) - r = true - end - end - return r -end - --- Prepare nodes -function Node.prepare(self, ...) - for k, child in ipairs(self.children) do - child:prepare(...) - end -end - --- Append child nodes -function Node.append(self, obj) - table.insert(self.children, obj) -end - --- Parse this node and its children -function Node.parse(self, ...) - for k, child in ipairs(self.children) do - child:parse(...) - end -end - --- Render this node -function Node.render(self, scope) - scope = scope or {} - scope.self = self - - luci.template.render(self.template, scope) -end - --- Render the children -function Node.render_children(self, ...) - local k, node - for k, node in ipairs(self.children) do - node.last_child = (k == #self.children) - node:render(...) - end -end - - ---[[ -A simple template element -]]-- -Template = class(Node) - -function Template.__init__(self, template) - Node.__init__(self) - self.template = template -end - -function Template.render(self) - luci.template.render(self.template, {self=self}) -end - -function Template.parse(self, readinput) - self.readinput = (readinput ~= false) - return Map.formvalue(self, "cbi.submit") and FORM_DONE or FORM_NODATA -end - - ---[[ -Map - A map describing a configuration file -]]-- -Map = class(Node) - -function Map.__init__(self, config, ...) - Node.__init__(self, ...) - - self.config = config - self.parsechain = {self.config} - self.template = "cbi/map" - self.apply_on_parse = nil - self.readinput = true - self.proceed = false - self.flow = {} - - self.uci = uci.cursor() - self.save = true - - self.changed = false - - if not self.uci:load(self.config) then - error("Unable to read UCI data: " .. self.config) - end -end - -function Map.formvalue(self, key) - return self.readinput and luci.http.formvalue(key) -end - -function Map.formvaluetable(self, key) - return self.readinput and luci.http.formvaluetable(key) or {} -end - -function Map.get_scheme(self, sectiontype, option) - if not option then - return self.scheme and self.scheme.sections[sectiontype] - else - return self.scheme and self.scheme.variables[sectiontype] - and self.scheme.variables[sectiontype][option] - end -end - -function Map.submitstate(self) - return self:formvalue("cbi.submit") -end - --- Chain foreign config -function Map.chain(self, config) - table.insert(self.parsechain, config) -end - -function Map.state_handler(self, state) - return state -end - --- Use optimized UCI writing -function Map.parse(self, readinput, ...) - self.readinput = (readinput ~= false) - self:_run_hooks("on_parse") - - if self:formvalue("cbi.skip") then - self.state = FORM_SKIP - return self:state_handler(self.state) - end - - Node.parse(self, ...) - - if self.save then - self:_run_hooks("on_save", "on_before_save") - for i, config in ipairs(self.parsechain) do - self.uci:save(config) - end - self:_run_hooks("on_after_save") - if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then - self:_run_hooks("on_before_commit") - for i, config in ipairs(self.parsechain) do - self.uci:commit(config) - - -- Refresh data because commit changes section names - self.uci:load(config) - end - self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") - if self.apply_on_parse then - self.uci:apply(self.parsechain) - self:_run_hooks("on_apply", "on_after_apply") - else - -- This is evaluated by the dispatcher and delegated to the - -- template which in turn fires XHR to perform the actual - -- apply actions. - self.apply_needed = true - end - - -- Reparse sections - Node.parse(self, true) - - end - 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 not self.save then - self.state = FORM_INVALID - elseif self.proceed then - self.state = FORM_PROCEED - else - self.state = self.changed and FORM_CHANGED or FORM_VALID - end - else - self.state = FORM_NODATA - end - - return self:state_handler(self.state) -end - -function Map.render(self, ...) - self:_run_hooks("on_init") - Node.render(self, ...) -end - --- Creates a child section -function Map.section(self, class, ...) - if instanceof(class, AbstractSection) then - local obj = class(self, ...) - self:append(obj) - return obj - else - error("class must be a descendent of AbstractSection") - end -end - --- UCI add -function Map.add(self, sectiontype) - return self.uci:add(self.config, sectiontype) -end - --- UCI set -function Map.set(self, section, option, value) - if type(value) ~= "table" or #value > 0 then - if option then - return self.uci:set(self.config, section, option, value) - else - return self.uci:set(self.config, section, value) - end - else - return Map.del(self, section, option) - end -end - --- UCI del -function Map.del(self, section, option) - if option then - return self.uci:delete(self.config, section, option) - else - return self.uci:delete(self.config, section) - end -end - --- UCI get -function Map.get(self, section, option) - if not section then - return self.uci:get_all(self.config) - elseif option then - return self.uci:get(self.config, section, option) - else - return self.uci:get_all(self.config, section) - end -end - ---[[ -Compound - Container -]]-- -Compound = class(Node) - -function Compound.__init__(self, ...) - Node.__init__(self) - self.template = "cbi/compound" - self.children = {...} -end - -function Compound.populate_delegator(self, delegator) - for _, v in ipairs(self.children) do - v.delegator = delegator - end -end - -function Compound.parse(self, ...) - local cstate, state = 0 - - for k, child in ipairs(self.children) do - cstate = child:parse(...) - state = (not state or cstate < state) and cstate or state - end - - return state -end - - ---[[ -Delegator - Node controller -]]-- -Delegator = class(Node) -function Delegator.__init__(self, ...) - Node.__init__(self, ...) - self.nodes = {} - self.defaultpath = {} - self.pageaction = false - self.readinput = true - self.allow_reset = false - self.allow_cancel = false - self.allow_back = false - self.allow_finish = false - self.template = "cbi/delegator" -end - -function Delegator.set(self, name, node) - assert(not self.nodes[name], "Duplicate entry") - - self.nodes[name] = node -end - -function Delegator.add(self, name, node) - node = self:set(name, node) - self.defaultpath[#self.defaultpath+1] = name -end - -function Delegator.insert_after(self, name, after) - local n = #self.chain + 1 - for k, v in ipairs(self.chain) do - if v == after then - n = k + 1 - break - end - end - table.insert(self.chain, n, name) -end - -function Delegator.set_route(self, ...) - local n, chain, route = 0, self.chain, {...} - for i = 1, #chain do - if chain[i] == self.current then - n = i - break - end - end - for i = 1, #route do - n = n + 1 - chain[n] = route[i] - end - for i = n + 1, #chain do - chain[i] = nil - end -end - -function Delegator.get(self, name) - local node = self.nodes[name] - - if type(node) == "string" then - node = load(node, name) - end - - if type(node) == "table" and getmetatable(node) == nil then - node = Compound(unpack(node)) - end - - return node -end - -function Delegator.parse(self, ...) - if self.allow_cancel and Map.formvalue(self, "cbi.cancel") then - if self:_run_hooks("on_cancel") then - return FORM_DONE - end - end - - if not Map.formvalue(self, "cbi.delg.current") then - self:_run_hooks("on_init") - end - - local newcurrent - self.chain = self.chain or self:get_chain() - self.current = self.current or self:get_active() - self.active = self.active or self:get(self.current) - assert(self.active, "Invalid state") - - local stat = FORM_DONE - if type(self.active) ~= "function" then - self.active:populate_delegator(self) - stat = self.active:parse() - else - self:active() - end - - if stat > FORM_PROCEED then - if Map.formvalue(self, "cbi.delg.back") then - newcurrent = self:get_prev(self.current) - else - newcurrent = self:get_next(self.current) - end - elseif stat < FORM_PROCEED then - return stat - end - - - if not Map.formvalue(self, "cbi.submit") then - return FORM_NODATA - elseif stat > FORM_PROCEED - and (not newcurrent or not self:get(newcurrent)) then - return self:_run_hook("on_done") or FORM_DONE - else - self.current = newcurrent or self.current - self.active = self:get(self.current) - if type(self.active) ~= "function" then - self.active:populate_delegator(self) - local stat = self.active:parse(false) - if stat == FORM_SKIP then - return self:parse(...) - else - return FORM_PROCEED - end - else - return self:parse(...) - end - end -end - -function Delegator.get_next(self, state) - for k, v in ipairs(self.chain) do - if v == state then - return self.chain[k+1] - end - end -end - -function Delegator.get_prev(self, state) - for k, v in ipairs(self.chain) do - if v == state then - return self.chain[k-1] - end - end -end - -function Delegator.get_chain(self) - local x = Map.formvalue(self, "cbi.delg.path") or self.defaultpath - return type(x) == "table" and x or {x} -end - -function Delegator.get_active(self) - return Map.formvalue(self, "cbi.delg.current") or self.chain[1] -end - ---[[ -Page - A simple node -]]-- - -Page = class(Node) -Page.__init__ = Node.__init__ -Page.parse = function() end - - ---[[ -SimpleForm - A Simple non-UCI form -]]-- -SimpleForm = class(Node) - -function SimpleForm.__init__(self, config, title, description, data) - Node.__init__(self, title, description) - self.config = config - self.data = data or {} - self.template = "cbi/simpleform" - self.dorender = true - self.pageaction = false - self.readinput = true -end - -SimpleForm.formvalue = Map.formvalue -SimpleForm.formvaluetable = Map.formvaluetable - -function SimpleForm.parse(self, readinput, ...) - self.readinput = (readinput ~= false) - - if self:formvalue("cbi.skip") then - return FORM_SKIP - end - - if self:formvalue("cbi.cancel") and self:_run_hooks("on_cancel") then - return FORM_DONE - end - - if self:submitstate() then - Node.parse(self, 1, ...) - end - - local valid = true - for k, j in ipairs(self.children) do - for i, v in ipairs(j.children) do - valid = valid - and (not v.tag_missing or not v.tag_missing[1]) - and (not v.tag_invalid or not v.tag_invalid[1]) - and (not v.error) - end - end - - local state = - not self:submitstate() and FORM_NODATA - or valid and FORM_VALID - or FORM_INVALID - - self.dorender = not self.handle - if self.handle then - local nrender, nstate = self:handle(state, self.data) - self.dorender = self.dorender or (nrender ~= false) - state = nstate or state - end - return state -end - -function SimpleForm.render(self, ...) - if self.dorender then - Node.render(self, ...) - end -end - -function SimpleForm.submitstate(self) - return self:formvalue("cbi.submit") -end - -function SimpleForm.section(self, class, ...) - if instanceof(class, AbstractSection) then - local obj = class(self, ...) - self:append(obj) - return obj - else - error("class must be a descendent of AbstractSection") - end -end - --- Creates a child field -function SimpleForm.field(self, class, ...) - local section - for k, v in ipairs(self.children) do - if instanceof(v, SimpleSection) then - section = v - break - end - end - if not section then - section = self:section(SimpleSection) - end - - if instanceof(class, AbstractValue) then - local obj = class(self, section, ...) - obj.track_missing = true - section:append(obj) - return obj - else - error("class must be a descendent of AbstractValue") - end -end - -function SimpleForm.set(self, section, option, value) - self.data[option] = value -end - - -function SimpleForm.del(self, section, option) - self.data[option] = nil -end - - -function SimpleForm.get(self, section, option) - return self.data[option] -end - - -function SimpleForm.get_scheme() - return nil -end - - -Form = class(SimpleForm) - -function Form.__init__(self, ...) - SimpleForm.__init__(self, ...) - self.embedded = true -end - - ---[[ -AbstractSection -]]-- -AbstractSection = class(Node) - -function AbstractSection.__init__(self, map, sectiontype, ...) - Node.__init__(self, ...) - self.sectiontype = sectiontype - self.map = map - self.config = map.config - self.optionals = {} - self.defaults = {} - self.fields = {} - self.tag_error = {} - self.tag_invalid = {} - self.tag_deperror = {} - self.changed = false - - self.optional = true - self.addremove = false - self.dynamic = false -end - --- Define a tab for the section -function AbstractSection.tab(self, tab, title, desc) - self.tabs = self.tabs or { } - self.tab_names = self.tab_names or { } - - self.tab_names[#self.tab_names+1] = tab - self.tabs[tab] = { - title = title, - description = desc, - childs = { } - } -end - --- Check whether the section has tabs -function AbstractSection.has_tabs(self) - return (self.tabs ~= nil) and (next(self.tabs) ~= nil) -end - --- Appends a new option -function AbstractSection.option(self, class, option, ...) - if instanceof(class, AbstractValue) then - local obj = class(self.map, self, option, ...) - self:append(obj) - self.fields[option] = obj - return obj - elseif class == true then - error("No valid class was given and autodetection failed.") - else - error("class must be a descendant of AbstractValue") - end -end - --- Appends a new tabbed option -function AbstractSection.taboption(self, tab, ...) - - assert(tab and self.tabs and self.tabs[tab], - "Cannot assign option to not existing tab %q" % tostring(tab)) - - local l = self.tabs[tab].childs - local o = AbstractSection.option(self, ...) - - if o then l[#l+1] = o end - - return o -end - --- Render a single tab -function AbstractSection.render_tab(self, tab, ...) - - assert(tab and self.tabs and self.tabs[tab], - "Cannot render not existing tab %q" % tostring(tab)) - - local k, node - for k, node in ipairs(self.tabs[tab].childs) do - node.last_child = (k == #self.tabs[tab].childs) - node:render(...) - end -end - --- Parse optional options -function AbstractSection.parse_optionals(self, section) - if not self.optional then - return - end - - self.optionals[section] = {} - - local field = self.map:formvalue("cbi.opt."..self.config.."."..section) - for k,v in ipairs(self.children) do - if v.optional and not v:cfgvalue(section) and not self:has_tabs() then - if field == v.option then - field = nil - self.map.proceed = true - else - table.insert(self.optionals[section], v) - end - end - end - - if field and #field > 0 and self.dynamic then - self:add_dynamic(field) - end -end - --- Add a dynamic option -function AbstractSection.add_dynamic(self, field, optional) - local o = self:option(Value, field, field) - o.optional = optional -end - --- Parse all dynamic options -function AbstractSection.parse_dynamic(self, section) - if not self.dynamic then - return - end - - local arr = luci.util.clone(self:cfgvalue(section)) - local form = self.map:formvaluetable("cbid."..self.config.."."..section) - for k, v in pairs(form) do - arr[k] = v - end - - for key,val in pairs(arr) do - local create = true - - for i,c in ipairs(self.children) do - if c.option == key then - create = false - end - end - - if create and key:sub(1, 1) ~= "." then - self.map.proceed = true - self:add_dynamic(key, true) - end - end -end - --- Returns the section's UCI table -function AbstractSection.cfgvalue(self, section) - return self.map:get(section) -end - --- Push events -function AbstractSection.push_events(self) - --luci.util.append(self.map.events, self.events) - self.map.changed = true -end - --- Removes the section -function AbstractSection.remove(self, section) - self.map.proceed = true - return self.map:del(section) -end - --- Creates the section -function AbstractSection.create(self, section) - local stat - - if section then - stat = section:match("^[%w_]+$") and self.map:set(section, nil, self.sectiontype) - else - section = self.map:add(self.sectiontype) - stat = section - end - - if stat then - for k,v in pairs(self.children) do - if v.default then - self.map:set(section, v.option, v.default) - end - end - - for k,v in pairs(self.defaults) do - self.map:set(section, k, v) - end - end - - self.map.proceed = true - - return stat -end - - -SimpleSection = class(AbstractSection) - -function SimpleSection.__init__(self, form, ...) - AbstractSection.__init__(self, form, nil, ...) - self.template = "cbi/nullsection" -end - - -Table = class(AbstractSection) - -function Table.__init__(self, form, data, ...) - local datasource = {} - local tself = self - datasource.config = "table" - self.data = data or {} - - datasource.formvalue = Map.formvalue - datasource.formvaluetable = Map.formvaluetable - datasource.readinput = true - - function datasource.get(self, section, option) - return tself.data[section] and tself.data[section][option] - end - - function datasource.submitstate(self) - return Map.formvalue(self, "cbi.submit") - end - - function datasource.del(...) - return true - end - - function datasource.get_scheme() - return nil - end - - AbstractSection.__init__(self, datasource, "table", ...) - self.template = "cbi/tblsection" - self.rowcolors = true - self.anonymous = true -end - -function Table.parse(self, readinput) - self.map.readinput = (readinput ~= false) - for i, k in ipairs(self:cfgsections()) do - if self.map:submitstate() then - Node.parse(self, k) - end - end -end - -function Table.cfgsections(self) - local sections = {} - - for i, v in luci.util.kspairs(self.data) do - table.insert(sections, i) - end - - return sections -end - -function Table.update(self, data) - self.data = data -end - - - ---[[ -NamedSection - A fixed configuration section defined by its name -]]-- -NamedSection = class(AbstractSection) - -function NamedSection.__init__(self, map, section, stype, ...) - AbstractSection.__init__(self, map, stype, ...) - - -- Defaults - self.addremove = false - self.template = "cbi/nsection" - self.section = section -end - -function NamedSection.parse(self, novld) - local s = self.section - local active = self:cfgvalue(s) - - if self.addremove then - local path = self.config.."."..s - if active then -- Remove the section - if self.map:formvalue("cbi.rns."..path) and self:remove(s) then - self:push_events() - return - end - else -- Create and apply default values - if self.map:formvalue("cbi.cns."..path) then - self:create(s) - return - end - end - end - - if active then - AbstractSection.parse_dynamic(self, s) - if self.map:submitstate() then - Node.parse(self, s) - end - AbstractSection.parse_optionals(self, s) - - if self.changed then - self:push_events() - end - end -end - - ---[[ -TypedSection - A (set of) configuration section(s) defined by the type - addremove: Defines whether the user can add/remove sections of this type - anonymous: Allow creating anonymous sections - validate: a validation function returning nil if the section is invalid -]]-- -TypedSection = class(AbstractSection) - -function TypedSection.__init__(self, map, type, ...) - AbstractSection.__init__(self, map, type, ...) - - self.template = "cbi/tsection" - self.deps = {} - self.anonymous = false -end - --- Return all matching UCI sections for this TypedSection -function TypedSection.cfgsections(self) - local sections = {} - self.map.uci:foreach(self.map.config, self.sectiontype, - function (section) - if self:checkscope(section[".name"]) then - table.insert(sections, section[".name"]) - end - end) - - return sections -end - --- Limits scope to sections that have certain option => value pairs -function TypedSection.depends(self, option, value) - table.insert(self.deps, {option=option, value=value}) -end - -function TypedSection.parse(self, novld) - if self.addremove then - -- Remove - local crval = REMOVE_PREFIX .. self.config - local name = self.map:formvaluetable(crval) - for k,v in pairs(name) do - if k:sub(-2) == ".x" then - k = k:sub(1, #k - 2) - end - if self:cfgvalue(k) and self:checkscope(k) then - self:remove(k) - end - end - end - - local co - for i, k in ipairs(self:cfgsections()) do - AbstractSection.parse_dynamic(self, k) - if self.map:submitstate() then - Node.parse(self, k, novld) - end - AbstractSection.parse_optionals(self, k) - end - - if self.addremove then - -- Create - local created - local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype - local origin, name = next(self.map:formvaluetable(crval)) - if self.anonymous then - if name then - created = self:create(nil, origin) - end - else - if name then - -- Ignore if it already exists - if self:cfgvalue(name) then - name = nil; - end - - name = self:checkscope(name) - - if not name then - self.err_invalid = true - end - - if name and #name > 0 then - created = self:create(name, origin) and name - if not created then - self.invalid_cts = true - end - end - end - end - - if created then - AbstractSection.parse_optionals(self, created) - end - end - - if self.sortable then - local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype - local order = self.map:formvalue(stval) - if order and #order > 0 then - local sid - local num = 0 - for sid in util.imatch(order) do - self.map.uci:reorder(self.config, sid, num) - num = num + 1 - end - self.changed = (num > 0) - end - end - - if created or self.changed then - self:push_events() - end -end - --- Verifies scope of sections -function TypedSection.checkscope(self, section) - -- Check if we are not excluded - if self.filter and not self:filter(section) then - return nil - end - - -- Check if at least one dependency is met - if #self.deps > 0 and self:cfgvalue(section) then - local stat = false - - for k, v in ipairs(self.deps) do - if self:cfgvalue(section)[v.option] == v.value then - stat = true - end - end - - if not stat then - return nil - end - end - - return self:validate(section) -end - - --- Dummy validate function -function TypedSection.validate(self, section) - return section -end - - ---[[ -AbstractValue - An abstract Value Type - null: Value can be empty - valid: A function returning the value if it is valid otherwise nil - depends: A table of option => value pairs of which one must be true - default: The default value - size: The size of the input fields - rmempty: Unset value if empty - optional: This value is optional (see AbstractSection.optionals) -]]-- -AbstractValue = class(Node) - -function AbstractValue.__init__(self, map, section, option, ...) - Node.__init__(self, ...) - self.section = section - self.option = option - self.map = map - self.config = map.config - self.tag_invalid = {} - self.tag_missing = {} - self.tag_reqerror = {} - self.tag_error = {} - self.deps = {} - self.subdeps = {} - --self.cast = "string" - - self.track_missing = false - self.rmempty = true - self.default = nil - self.size = nil - self.optional = false -end - -function AbstractValue.prepare(self) - self.cast = self.cast or "string" -end - --- Add a dependencie to another section field -function AbstractValue.depends(self, field, value) - local deps - if type(field) == "string" then - deps = {} - deps[field] = value - else - deps = field - end - - table.insert(self.deps, {deps=deps, add=""}) -end - --- Generates the unique CBID -function AbstractValue.cbid(self, section) - return "cbid."..self.map.config.."."..section.."."..self.option -end - --- Return whether this object should be created -function AbstractValue.formcreated(self, section) - local key = "cbi.opt."..self.config.."."..section - return (self.map:formvalue(key) == self.option) -end - --- Returns the formvalue for this object -function AbstractValue.formvalue(self, section) - return self.map:formvalue(self:cbid(section)) -end - -function AbstractValue.additional(self, value) - self.optional = value -end - -function AbstractValue.mandatory(self, value) - self.rmempty = not value -end - -function AbstractValue.add_error(self, section, type, msg) - self.error = self.error or { } - self.error[section] = msg or type - - self.section.error = self.section.error or { } - self.section.error[section] = self.section.error[section] or { } - table.insert(self.section.error[section], msg or type) - - if type == "invalid" then - self.tag_invalid[section] = true - elseif type == "missing" then - self.tag_missing[section] = true - end - - self.tag_error[section] = true - self.map.save = false -end - -function AbstractValue.parse(self, section, novld) - local fvalue = self:formvalue(section) - local cvalue = self:cfgvalue(section) - - -- If favlue and cvalue are both tables and have the same content - -- make them identical - if type(fvalue) == "table" and type(cvalue) == "table" then - local equal = #fvalue == #cvalue - if equal then - for i=1, #fvalue do - if cvalue[i] ~= fvalue[i] then - equal = false - end - end - end - if equal then - fvalue = cvalue - end - end - - if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI - local val_err - fvalue, val_err = self:validate(fvalue, section) - fvalue = self:transform(fvalue) - - if not fvalue and not novld then - self:add_error(section, "invalid", val_err) - end - - if fvalue and (self.forcewrite or not (fvalue == cvalue)) then - if self:write(section, fvalue) then - -- Push events - self.section.changed = true - --luci.util.append(self.map.events, self.events) - end - end - else -- Unset the UCI or error - if self.rmempty or self.optional then - if self:remove(section) then - -- Push events - self.section.changed = true - --luci.util.append(self.map.events, self.events) - end - elseif cvalue ~= fvalue and not novld then - -- trigger validator with nil value to get custom user error msg. - local _, val_err = self:validate(nil, section) - self:add_error(section, "missing", val_err) - end - end -end - --- Render if this value exists or if it is mandatory -function AbstractValue.render(self, s, scope) - if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then - scope = scope or {} - scope.section = s - scope.cbid = self:cbid(s) - Node.render(self, scope) - end -end - --- Return the UCI value of this object -function AbstractValue.cfgvalue(self, section) - local value - if self.tag_error[section] then - value = self:formvalue(section) - else - value = self.map:get(section, self.option) - end - - if not value then - return nil - elseif not self.cast or self.cast == type(value) then - return value - elseif self.cast == "string" then - if type(value) == "table" then - return value[1] - end - elseif self.cast == "table" then - return { value } - end -end - --- Validate the form value -function AbstractValue.validate(self, value) - if self.datatype and value then - if type(value) == "table" then - local v - for _, v in ipairs(value) do - if v and #v > 0 and not verify_datatype(self.datatype, v) then - return nil - end - end - else - if not verify_datatype(self.datatype, value) then - return nil - end - end - end - - return value -end - -AbstractValue.transform = AbstractValue.validate - - --- Write to UCI -function AbstractValue.write(self, section, value) - return self.map:set(section, self.option, value) -end - --- Remove from UCI -function AbstractValue.remove(self, section) - return self.map:del(section, self.option) -end - - - - ---[[ -Value - A one-line value - maxlength: The maximum length -]]-- -Value = class(AbstractValue) - -function Value.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/value" - self.keylist = {} - self.vallist = {} -end - -function Value.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function Value.value(self, key, val) - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - - --- DummyValue - This does nothing except being there -DummyValue = class(AbstractValue) - -function DummyValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/dvalue" - self.value = nil -end - -function DummyValue.cfgvalue(self, section) - local value - if self.value then - if type(self.value) == "function" then - value = self:value(section) - else - value = self.value - end - else - value = AbstractValue.cfgvalue(self, section) - end - return value -end - -function DummyValue.parse(self) - -end - - ---[[ -Flag - A flag being enabled or disabled -]]-- -Flag = class(AbstractValue) - -function Flag.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/fvalue" - - self.enabled = "1" - self.disabled = "0" - self.default = self.disabled -end - --- A flag can only have two states: set or unset -function Flag.parse(self, section) - local fexists = self.map:formvalue( - FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option) - - if fexists then - local fvalue = self:formvalue(section) and self.enabled or self.disabled - if fvalue ~= self.default or (not self.optional and not self.rmempty) then - self:write(section, fvalue) - else - self:remove(section) - end - else - self:remove(section) - end -end - -function Flag.cfgvalue(self, section) - return AbstractValue.cfgvalue(self, section) or self.default -end - - ---[[ -ListValue - A one-line value predefined in a list - widget: The widget that will be used (select, radio) -]]-- -ListValue = class(AbstractValue) - -function ListValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/lvalue" - - self.keylist = {} - self.vallist = {} - self.size = 1 - self.widget = "select" -end - -function ListValue.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function ListValue.value(self, key, val, ...) - if luci.util.contains(self.keylist, key) then - return - end - - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) - - for i, deps in ipairs({...}) do - self.subdeps[#self.subdeps + 1] = {add = "-"..key, deps=deps} - end -end - -function ListValue.validate(self, val) - if luci.util.contains(self.keylist, val) then - return val - else - return nil - end -end - - - ---[[ -MultiValue - Multiple delimited values - widget: The widget that will be used (select, checkbox) - delimiter: The delimiter that will separate the values (default: " ") -]]-- -MultiValue = class(AbstractValue) - -function MultiValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/mvalue" - - self.keylist = {} - self.vallist = {} - - self.widget = "checkbox" - self.delimiter = " " -end - -function MultiValue.render(self, ...) - if self.widget == "select" and not self.size then - self.size = #self.vallist - end - - AbstractValue.render(self, ...) -end - -function MultiValue.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function MultiValue.value(self, key, val) - if luci.util.contains(self.keylist, key) then - return - end - - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - -function MultiValue.valuelist(self, section) - local val = self:cfgvalue(section) - - if not(type(val) == "string") then - return {} - end - - return luci.util.split(val, self.delimiter) -end - -function MultiValue.validate(self, val) - val = (type(val) == "table") and val or {val} - - local result - - for i, value in ipairs(val) do - if luci.util.contains(self.keylist, value) then - result = result and (result .. self.delimiter .. value) or value - end - end - - return result -end - - -StaticList = class(MultiValue) - -function StaticList.__init__(self, ...) - MultiValue.__init__(self, ...) - self.cast = "table" - self.valuelist = self.cfgvalue - - if not self.override_scheme - and self.map:get_scheme(self.section.sectiontype, self.option) then - local vs = self.map:get_scheme(self.section.sectiontype, self.option) - if self.value and vs.values and not self.override_values then - for k, v in pairs(vs.values) do - self:value(k, v) - end - end - end -end - -function StaticList.validate(self, value) - value = (type(value) == "table") and value or {value} - - local valid = {} - for i, v in ipairs(value) do - if luci.util.contains(self.keylist, v) then - table.insert(valid, v) - end - end - return valid -end - - -DynamicList = class(AbstractValue) - -function DynamicList.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/dynlist" - self.cast = "table" - self.keylist = {} - self.vallist = {} -end - -function DynamicList.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function DynamicList.value(self, key, val) - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - -function DynamicList.write(self, section, value) - local t = { } - - if type(value) == "table" then - local x - for _, x in ipairs(value) do - if x and #x > 0 then - t[#t+1] = x - end - end - else - t = { value } - end - - if self.cast == "string" then - value = table.concat(t, " ") - else - value = t - end - - return AbstractValue.write(self, section, value) -end - -function DynamicList.cfgvalue(self, section) - local value = AbstractValue.cfgvalue(self, section) - - if type(value) == "string" then - local x - local t = { } - for x in value:gmatch("%S+") do - if #x > 0 then - t[#t+1] = x - end - end - value = t - end - - return value -end - -function DynamicList.formvalue(self, section) - local value = AbstractValue.formvalue(self, section) - - if type(value) == "string" then - if self.cast == "string" then - local x - local t = { } - for x in value:gmatch("%S+") do - t[#t+1] = x - end - value = t - else - value = { value } - end - end - - return value -end - - ---[[ -TextValue - A multi-line value - rows: Rows -]]-- -TextValue = class(AbstractValue) - -function TextValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/tvalue" -end - ---[[ -Button -]]-- -Button = class(AbstractValue) - -function Button.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/button" - 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 - self.map:formvalue("cbi.rlf."..section.."."..self.option) or - self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") -end - -function FileUpload.cfgvalue(self, section) - local val = AbstractValue.cfgvalue(self, section) - if val and 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 self.map:formvalue("cbi.rlf."..section.."."..self.option) and - not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") - then - return val - end - fs.unlink(val) - self.value = nil - end - return nil -end - -function FileUpload.remove(self, section) - local val = AbstractValue.formvalue(self, section) - if val and fs.access(val) then 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 diff --git a/libs/web/luasrc/cbi/datatypes.lua b/libs/web/luasrc/cbi/datatypes.lua deleted file mode 100644 index c5f4ec0f0d..0000000000 --- a/libs/web/luasrc/cbi/datatypes.lua +++ /dev/null @@ -1,345 +0,0 @@ ---[[ - -LuCI - Configuration Bind Interface - Datatype Tests -(c) 2010 Jo-Philipp Wich <xm@subsignal.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - -local fs = require "nixio.fs" -local ip = require "luci.ip" -local math = require "math" -local util = require "luci.util" -local tonumber, tostring, type, unpack, select = tonumber, tostring, type, unpack, select - - -module "luci.cbi.datatypes" - - -_M['or'] = function(v, ...) - local i - for i = 1, select('#', ...), 2 do - local f = select(i, ...) - local a = select(i+1, ...) - if type(f) ~= "function" then - if f == v then - return true - end - i = i - 1 - elseif f(v, unpack(a)) then - return true - end - end - return false -end - -_M['and'] = function(v, ...) - local i - for i = 1, select('#', ...), 2 do - local f = select(i, ...) - local a = select(i+1, ...) - if type(f) ~= "function" then - if f ~= v then - return false - end - i = i - 1 - elseif not f(v, unpack(a)) then - return false - end - end - return true -end - -function neg(v, ...) - return _M['or'](v:gsub("^%s*!%s*", ""), ...) -end - -function list(v, subvalidator, subargs) - if type(subvalidator) ~= "function" then - return false - end - local token - for token in v:gmatch("%S+") do - if not subvalidator(token, unpack(subargs)) then - return false - end - end - return true -end - -function bool(val) - if val == "1" or val == "yes" or val == "on" or val == "true" then - return true - elseif val == "0" or val == "no" or val == "off" or val == "false" then - return true - elseif val == "" or val == nil then - return true - end - - return false -end - -function uinteger(val) - local n = tonumber(val) - if n ~= nil and math.floor(n) == n and n >= 0 then - return true - end - - return false -end - -function integer(val) - local n = tonumber(val) - if n ~= nil and math.floor(n) == n then - return true - end - - return false -end - -function ufloat(val) - local n = tonumber(val) - return ( n ~= nil and n >= 0 ) -end - -function float(val) - return ( tonumber(val) ~= nil ) -end - -function ipaddr(val) - return ip4addr(val) or ip6addr(val) -end - -function ip4addr(val) - if val then - return ip.IPv4(val) and true or false - end - - return false -end - -function ip4prefix(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 32 ) -end - -function ip6addr(val) - if val then - return ip.IPv6(val) and true or false - end - - return false -end - -function ip6prefix(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 128 ) -end - -function port(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 65535 ) -end - -function portrange(val) - local p1, p2 = val:match("^(%d+)%-(%d+)$") - if p1 and p2 and port(p1) and port(p2) then - return true - else - return port(val) - end -end - -function macaddr(val) - if val and val:match( - "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" .. - "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$" - ) then - local parts = util.split( val, ":" ) - - for i = 1,6 do - parts[i] = tonumber( parts[i], 16 ) - if parts[i] < 0 or parts[i] > 255 then - return false - end - end - - return true - end - - return false -end - -function hostname(val) - 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 - end - return false -end - -function host(val) - return hostname(val) or ipaddr(val) -end - -function network(val) - return uciname(val) or host(val) -end - -function wpakey(val) - if #val == 64 then - return (val:match("^[a-fA-F0-9]+$") ~= nil) - else - return (#val >= 8) and (#val <= 63) - end -end - -function wepkey(val) - if val:sub(1, 2) == "s:" then - val = val:sub(3) - end - - if (#val == 10) or (#val == 26) then - return (val:match("^[a-fA-F0-9]+$") ~= nil) - else - return (#val == 5) or (#val == 13) - end -end - -function string(val) - return true -- Everything qualifies as valid string -end - -function directory( val, seen ) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "dir" then - return true - elseif s.type == "lnk" then - return directory( fs.readlink(val), seen ) - end - end - - return false -end - -function file( val, seen ) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "reg" then - return true - elseif s.type == "lnk" then - return file( fs.readlink(val), seen ) - end - end - - return false -end - -function device( val, seen ) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "chr" or s.type == "blk" then - return true - elseif s.type == "lnk" then - return device( fs.readlink(val), seen ) - end - end - - return false -end - -function uciname(val) - return (val:match("^[a-zA-Z0-9_]+$") ~= nil) -end - -function range(val, min, max) - val = tonumber(val) - min = tonumber(min) - max = tonumber(max) - - if val ~= nil and min ~= nil and max ~= nil then - return ((val >= min) and (val <= max)) - end - - return false -end - -function min(val, min) - val = tonumber(val) - min = tonumber(min) - - if val ~= nil and min ~= nil then - return (val >= min) - end - - return false -end - -function max(val, max) - val = tonumber(val) - max = tonumber(max) - - if val ~= nil and max ~= nil then - return (val <= max) - end - - return false -end - -function rangelength(val, min, max) - val = tostring(val) - min = tonumber(min) - max = tonumber(max) - - if val ~= nil and min ~= nil and max ~= nil then - return ((#val >= min) and (#val <= max)) - end - - return false -end - -function minlength(val, min) - val = tostring(val) - min = tonumber(min) - - if val ~= nil and min ~= nil then - return (#val >= min) - end - - return false -end - -function maxlength(val, max) - val = tostring(val) - max = tonumber(max) - - if val ~= nil and max ~= nil then - return (#val <= max) - end - - return false -end - -function phonedigit(val) - return (val:match("^[0-9\*#!%.]+$") ~= nil) -end diff --git a/libs/web/luasrc/config.lua b/libs/web/luasrc/config.lua deleted file mode 100644 index 53db82b322..0000000000 --- a/libs/web/luasrc/config.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[ -LuCI - Configuration - -Description: -Some LuCI configuration values read from uci file "luci" - - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local util = require "luci.util" -module("luci.config", - function(m) - if pcall(require, "luci.model.uci") then - local config = util.threadlocal() - setmetatable(m, { - __index = function(tbl, key) - if not config[key] then - config[key] = luci.model.uci.cursor():get_all("luci", key) - end - return config[key] - end - }) - end - end) diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua deleted file mode 100644 index 9e5b78d5e9..0000000000 --- a/libs/web/luasrc/dispatcher.lua +++ /dev/null @@ -1,959 +0,0 @@ ---[[ -LuCI - Dispatcher - -Description: -The request dispatcher and module dispatcher generators - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - ---- LuCI web dispatcher. -local fs = require "nixio.fs" -local sys = require "luci.sys" -local init = require "luci.init" -local util = require "luci.util" -local http = require "luci.http" -local nixio = require "nixio", require "nixio.util" - -module("luci.dispatcher", package.seeall) -context = util.threadlocal() -uci = require "luci.model.uci" -i18n = require "luci.i18n" -_M.fs = fs - -authenticator = {} - --- Index table -local index = nil - --- Fastindex -local fi - - ---- Build the URL relative to the server webroot from given virtual path. --- @param ... Virtual path --- @return Relative URL -function build_url(...) - local path = {...} - local url = { http.getenv("SCRIPT_NAME") or "" } - - local k, v - for k, v in pairs(context.urltoken) do - url[#url+1] = "/;" - url[#url+1] = http.urlencode(k) - url[#url+1] = "=" - url[#url+1] = http.urlencode(v) - end - - local p - for _, p in ipairs(path) do - if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then - url[#url+1] = "/" - url[#url+1] = p - end - end - - return table.concat(url, "") -end - ---- Check whether a dispatch node shall be visible --- @param node Dispatch node --- @return Boolean indicating whether the node should be visible -function node_visible(node) - if node then - return not ( - (not node.title or #node.title == 0) or - (not node.target or node.hidden == true) or - (type(node.target) == "table" and node.target.type == "firstchild" and - (type(node.nodes) ~= "table" or not next(node.nodes))) - ) - end - return false -end - ---- Return a sorted table of visible childs within a given node --- @param node Dispatch node --- @return Ordered table of child node names -function node_childs(node) - local rv = { } - if node then - local k, v - for k, v in util.spairs(node.nodes, - function(a, b) - return (node.nodes[a].order or 100) - < (node.nodes[b].order or 100) - end) - do - if node_visible(v) then - rv[#rv+1] = k - end - end - end - return rv -end - - ---- Send a 404 error code and render the "error404" template if available. --- @param message Custom error message (optional) --- @return false -function error404(message) - luci.http.status(404, "Not Found") - message = message or "Not Found" - - require("luci.template") - if not luci.util.copcall(luci.template.render, "error404") then - luci.http.prepare_content("text/plain") - luci.http.write(message) - end - return false -end - ---- Send a 500 error code and render the "error500" template if available. --- @param message Custom error message (optional)# --- @return false -function error500(message) - luci.util.perror(message) - if not context.template_header_sent then - luci.http.status(500, "Internal Server Error") - luci.http.prepare_content("text/plain") - luci.http.write(message) - else - require("luci.template") - if not luci.util.copcall(luci.template.render, "error500", {message=message}) then - luci.http.prepare_content("text/plain") - luci.http.write(message) - end - end - return false -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. --- @param request LuCI HTTP Request object -function httpdispatch(request, prefix) - luci.http.context.request = request - - local r = {} - context.request = r - context.urltoken = {} - - local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) - - if prefix then - for _, node in ipairs(prefix) do - r[#r+1] = node - end - end - - local tokensok = true - for node in pathinfo:gmatch("[^/]+") do - local tkey, tval - if tokensok then - tkey, tval = node:match(";(%w+)=([a-fA-F0-9]*)") - end - if tkey then - context.urltoken[tkey] = tval - else - tokensok = false - r[#r+1] = node - end - end - - local stat, err = util.coxpcall(function() - dispatch(context.request) - end, error500) - - luci.http.close() - - --context._disable_memtrace() -end - ---- Dispatches a LuCI virtual path. --- @param request Virtual path -function dispatch(request) - --context._disable_memtrace = require "luci.debug".trap_memtrace("l") - local ctx = context - ctx.path = request - - local conf = require "luci.config" - assert(conf.main, - "/etc/config/luci seems to be corrupt, unable to find section 'main'") - - local lang = conf.main.lang or "auto" - if lang == "auto" then - local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or "" - for lpat in aclang:gmatch("[%w-]+") do - lpat = lpat and lpat:gsub("-", "_") - if conf.languages[lpat] then - lang = lpat - break - end - end - end - require "luci.i18n".setlanguage(lang) - - local c = ctx.tree - local stat - if not c then - c = createtree() - end - - local track = {} - local args = {} - ctx.args = args - ctx.requestargs = ctx.requestargs or args - local n - local token = ctx.urltoken - local preq = {} - local freq = {} - - for i, s in ipairs(request) do - preq[#preq+1] = s - freq[#freq+1] = s - c = c.nodes[s] - n = i - if not c then - break - end - - util.update(track, c) - - if c.leaf then - break - end - end - - if c and c.leaf then - for j=n+1, #request do - args[#args+1] = request[j] - freq[#freq+1] = request[j] - end - end - - ctx.requestpath = ctx.requestpath or freq - ctx.path = preq - - if track.i18n then - i18n.loadc(track.i18n) - end - - -- Init template engine - if (c and c.index) or not track.notemplate then - local tpl = require("luci.template") - 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 - if name:sub(1,1) ~= "." and pcall(tpl.Template, - "themes/%s/header" % fs.basename(theme)) then - media = theme - end - end - assert(media, "No valid theme found") - end - - local function _ifattr(cond, key, val) - if cond then - local env = getfenv(3) - local scope = (type(env.self) == "table") and env.self - return string.format( - ' %s="%s"', tostring(key), - luci.util.pcdata(tostring( val - or (type(env[key]) ~= "function" and env[key]) - or (scope and type(scope[key]) ~= "function" and scope[key]) - or "" )) - ) - else - return '' - end - end - - tpl.context.viewns = setmetatable({ - write = luci.http.write; - include = function(name) tpl.Template(name):render(getfenv(2)) end; - translate = i18n.translate; - translatef = i18n.translatef; - export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; - striptags = util.striptags; - pcdata = util.pcdata; - media = media; - theme = fs.basename(media); - resource = luci.config.main.resourcebase; - ifattr = function(...) return _ifattr(...) end; - attr = function(...) return _ifattr(true, ...) end; - }, {__index=function(table, key) - if key == "controller" then - return build_url() - elseif key == "REQUEST_URI" then - return build_url(unpack(ctx.requestpath)) - else - return rawget(table, key) or _G[key] - end - end}) - end - - track.dependent = (track.dependent ~= false) - assert(not track.dependent or not track.auto, - "Access Violation\nThe page at '" .. table.concat(request, "/") .. "/' " .. - "has no parent node so the access to this location has been denied.\n" .. - "This is a software bug, please report this message at " .. - "http://luci.subsignal.org/trac/newticket" - ) - - 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 - local verifytoken = false - if not sess then - sess = luci.http.getcookie("sysauth") - sess = sess and sess:match("^[a-f0-9]*$") - verifytoken = true - end - - local sdat = sauth.read(sess) - local user - - if sdat then - if not verifytoken or ctx.urltoken.stok == sdat.token then - user = sdat.user - end - else - local eu = http.getenv("HTTP_AUTH_USER") - local ep = http.getenv("HTTP_AUTH_PASS") - if eu and ep and luci.sys.user.checkpasswd(eu, ep) then - authen = function() return eu end - end - end - - if not util.contains(accs, user) then - if authen then - ctx.urltoken.stok = nil - local user, sess = authen(luci.sys.user.checkpasswd, accs, def) - if not user or not util.contains(accs, user) then - return - else - local sid = sess or luci.sys.uniqueid(16) - if not sess then - local token = luci.sys.uniqueid(16) - sauth.reap() - sauth.write(sid, { - user=user, - token=token, - secret=luci.sys.uniqueid(16) - }) - ctx.urltoken.stok = token - end - luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path="..build_url()) - ctx.authsession = sid - ctx.authuser = user - end - else - luci.http.status(403, "Forbidden") - return - end - else - ctx.authsession = sess - ctx.authuser = user - end - end - - if track.setgroup then - luci.sys.process.setgroup(track.setgroup) - end - - if track.setuser then - luci.sys.process.setuser(track.setuser) - end - - local target = nil - if c then - if type(c.target) == "function" then - target = c.target - elseif type(c.target) == "table" then - target = c.target.target - end - end - - if c and (c.index or type(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 type(target) == "function" then - util.copcall(function() - local oldenv = getfenv(target) - local module = require(c.module) - local env = setmetatable({}, {__index= - - function(tbl, key) - return rawget(tbl, key) or module[key] or oldenv[key] - end}) - - setfenv(target, env) - end) - - local ok, err - if type(c.target) == "table" then - ok, err = util.copcall(target, c.target, unpack(args)) - else - ok, err = util.copcall(target, unpack(args)) - end - assert(ok, - "Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. - " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. - "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) - else - local root = node() - if not root or not root.target then - error404("No root node was registered, this usually happens if no module was installed.\n" .. - "Install luci-mod-admin-full and retry. " .. - "If the module is already installed, try removing the /tmp/luci-indexcache file.") - else - error404("No page is registered at '/" .. table.concat(request, "/") .. "'.\n" .. - "If this url belongs to an extension, make sure it is properly installed.\n" .. - "If the extension was recently installed, try removing the /tmp/luci-indexcache file.") - end - end -end - ---- Generate the dispatching index using the best possible strategy. -function createindex() - local path = luci.util.libpath() .. "/controller/" - local suff = { ".lua", ".lua.gz" } - - if luci.util.copcall(require, "luci.fastindex") then - createindex_fastindex(path, suff) - else - createindex_plain(path, suff) - end -end - ---- Generate the dispatching index using the fastindex C-indexer. --- @param path Controller base directory --- @param suffixes Controller file suffixes -function createindex_fastindex(path, suffixes) - index = {} - - if not fi then - fi = luci.fastindex.new("index") - for _, suffix in ipairs(suffixes) do - fi.add(path .. "*" .. suffix) - fi.add(path .. "*/*" .. suffix) - end - end - fi.scan() - - for k, v in pairs(fi.indexes) do - index[v[2]] = v[1] - end -end - ---- Generate the dispatching index using the native file-cache based strategy. --- @param path Controller base directory --- @param suffixes Controller file suffixes -function createindex_plain(path, suffixes) - local controllers = { } - for _, suffix in ipairs(suffixes) do - nixio.util.consume((fs.glob(path .. "*" .. suffix)), controllers) - nixio.util.consume((fs.glob(path .. "*/*" .. suffix)), controllers) - end - - if indexcache then - local cachedate = fs.stat(indexcache, "mtime") - if cachedate then - local realdate = 0 - for _, obj in ipairs(controllers) do - local omtime = fs.stat(obj, "mtime") - realdate = (omtime and omtime > realdate) and omtime or realdate - end - - if cachedate > realdate then - assert( - sys.process.info("uid") == fs.stat(indexcache, "uid") - and fs.stat(indexcache, "modestr") == "rw-------", - "Fatal: Indexcache is not sane!" - ) - - index = loadfile(indexcache)() - return index - end - end - end - - index = {} - - for i,c in ipairs(controllers) do - local modname = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".") - for _, suffix in ipairs(suffixes) do - modname = modname:gsub(suffix.."$", "") - end - - local mod = require(modname) - assert(mod ~= true, - "Invalid controller file found\n" .. - "The file '" .. c .. "' contains an invalid module line.\n" .. - "Please verify whether the module name is set to '" .. modname .. - "' - It must correspond to the file path!") - - local idx = mod.index - assert(type(idx) == "function", - "Invalid controller file found\n" .. - "The file '" .. c .. "' contains no index() function.\n" .. - "Please make sure that the controller contains a valid " .. - "index function and verify the spelling!") - - index[modname] = idx - end - - if indexcache then - local f = nixio.open(indexcache, "w", 600) - f:writeall(util.get_bytecode(index)) - f:close() - end -end - ---- Create the dispatching tree from the index. --- Build the index before if it does not exist yet. -function createtree() - if not index then - createindex() - end - - local ctx = context - local tree = {nodes={}, inreq=true} - local modi = {} - - ctx.treecache = setmetatable({}, {__mode="v"}) - ctx.tree = tree - ctx.modifiers = modi - - -- Load default translation - require "luci.i18n".loadc("base") - - local scope = setmetatable({}, {__index = luci.dispatcher}) - - for k, v in pairs(index) do - scope._NAME = k - setfenv(v, scope) - v() - end - - local function modisort(a,b) - return modi[a].order < modi[b].order - end - - for _, v in util.spairs(modi, modisort) do - scope._NAME = v.module - setfenv(v.func, scope) - v.func() - end - - return tree -end - ---- Register a tree modifier. --- @param func Modifier function --- @param order Modifier order value (optional) -function modifier(func, order) - context.modifiers[#context.modifiers+1] = { - func = func, - order = order or 0, - module - = getfenv(2)._NAME - } -end - ---- Clone a node of the dispatching tree to another position. --- @param path Virtual path destination --- @param clone Virtual path source --- @param title Destination node title (optional) --- @param order Destination node order value (optional) --- @return Dispatching tree node -function assign(path, clone, title, order) - local obj = node(unpack(path)) - obj.nodes = nil - 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 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 - c.module = getfenv(2)._NAME - - return c -end - ---- Fetch or create a dispatching node without setting the target module or --- enabling the node. --- @param ... Virtual path --- @return Dispatching tree node -function get(...) - return _create_node({...}) -end - ---- Fetch or create a new dispatching node. --- @param ... Virtual path --- @return Dispatching tree node -function node(...) - local c = _create_node({...}) - - c.module = getfenv(2)._NAME - c.auto = nil - - return c -end - -function _create_node(path) - if #path == 0 then - return context.tree - end - - local name = table.concat(path, ".") - local c = context.treecache[name] - - if not c then - local last = table.remove(path) - local parent = _create_node(path) - - c = {nodes={}, auto=true} - -- the node is "in request" if the request path matches - -- at least up to the length of the node path - if parent.inreq and context.path[#path+1] == last then - c.inreq = true - end - parent.nodes[last] = c - context.treecache[name] = c - end - return c -end - --- Subdispatchers -- - -function _firstchild() - local path = { unpack(context.path) } - local name = table.concat(path, ".") - local node = context.treecache[name] - - local lowest - if node and node.nodes and next(node.nodes) then - local k, v - for k, v in pairs(node.nodes) do - if not lowest or - (v.order or 100) < (node.nodes[lowest].order or 100) - then - lowest = k - end - end - end - - assert(lowest ~= nil, - "The requested node contains no childs, unable to redispatch") - - path[#path+1] = lowest - dispatch(path) -end - ---- Alias the first (lowest order) page automatically -function firstchild() - return { type = "firstchild", target = _firstchild } -end - ---- Create a redirect to another dispatching node. --- @param ... Virtual path destination -function alias(...) - local req = {...} - return function(...) - for _, r in ipairs({...}) do - req[#req+1] = r - end - - dispatch(req) - end -end - ---- Rewrite the first x path values of the request. --- @param n Number of path values to replace --- @param ... Virtual path to replace removed path values with -function rewrite(n, ...) - local req = {...} - return function(...) - local dispatched = util.clone(context.dispatched) - - for i=1,n do - table.remove(dispatched, 1) - end - - for i, r in ipairs(req) do - table.insert(dispatched, i, r) - end - - for _, r in ipairs({...}) do - dispatched[#dispatched+1] = r - end - - dispatch(dispatched) - end -end - - -local function _call(self, ...) - local func = getfenv()[self.name] - assert(func ~= nil, - 'Cannot resolve function "' .. self.name .. '". Is it misspelled or local?') - - assert(type(func) == "function", - 'The symbol "' .. self.name .. '" does not refer to a function but data ' .. - 'of type "' .. type(func) .. '".') - - if #self.argv > 0 then - return func(unpack(self.argv), ...) - else - return func(...) - end -end - ---- Create a function-call dispatching target. --- @param name Target function of local controller --- @param ... Additional parameters passed to the function -function call(name, ...) - return {type = "call", argv = {...}, name = name, target = _call} -end - - -local _template = function(self, ...) - require "luci.template".render(self.view) -end - ---- Create a template render dispatching target. --- @param name Template to be rendered -function template(name) - return {type = "template", view = name, target = _template} -end - - -local function _cbi(self, ...) - local cbi = require "luci.cbi" - local tpl = require "luci.template" - local http = require "luci.http" - - local config = self.config or {} - local maps = cbi.load(self.model, ...) - - local state = nil - - for i, res in ipairs(maps) do - res.flow = config - local cstate = res:parse() - if cstate and (not state or cstate < state) then - state = cstate - end - end - - local function _resolve_path(path) - return type(path) == "table" and build_url(unpack(path)) or path - end - - if config.on_valid_to and state and state > 0 and state < 2 then - http.redirect(_resolve_path(config.on_valid_to)) - return - end - - if config.on_changed_to and state and state > 1 then - http.redirect(_resolve_path(config.on_changed_to)) - return - end - - if config.on_success_to and state and state > 0 then - http.redirect(_resolve_path(config.on_success_to)) - return - end - - if config.state_handler then - if not config.state_handler(state, maps) then - return - end - end - - http.header("X-CBI-State", state or 0) - - if not config.noheader then - tpl.render("cbi/header", {state = state}) - end - - local redirect - local messages - local applymap = false - local pageaction = true - local parsechain = { } - - for i, res in ipairs(maps) do - if res.apply_needed and res.parsechain then - local c - for _, c in ipairs(res.parsechain) do - parsechain[#parsechain+1] = c - end - applymap = true - end - - if res.redirect then - redirect = redirect or res.redirect - end - - if res.pageaction == false then - pageaction = false - end - - if res.message then - messages = messages or { } - messages[#messages+1] = res.message - end - end - - for i, res in ipairs(maps) do - res:render({ - firstmap = (i == 1), - applymap = applymap, - redirect = redirect, - messages = messages, - pageaction = pageaction, - parsechain = parsechain - }) - end - - if not config.nofooter then - tpl.render("cbi/footer", { - flow = config, - pageaction = pageaction, - redirect = redirect, - state = state, - autoapply = config.autoapply - }) - end -end - ---- Create a CBI model dispatching target. --- @param model CBI model to be rendered -function cbi(model, config) - return {type = "cbi", config = config, model = model, target = _cbi} -end - - -local function _arcombine(self, ...) - local argv = {...} - local target = #argv > 0 and self.targets[2] or self.targets[1] - setfenv(target.target, self.env) - target:target(unpack(argv)) -end - ---- Create a combined dispatching target for non argv and argv requests. --- @param trg1 Overview Target --- @param trg2 Detail Target -function arcombine(trg1, trg2) - return {type = "arcombine", env = getfenv(), target = _arcombine, targets = {trg1, trg2}} -end - - -local function _form(self, ...) - local cbi = require "luci.cbi" - local tpl = require "luci.template" - local http = require "luci.http" - - local maps = luci.cbi.load(self.model, ...) - local state = nil - - for i, res in ipairs(maps) do - local cstate = res:parse() - if cstate and (not state or cstate < state) then - state = cstate - end - end - - http.header("X-CBI-State", state or 0) - tpl.render("header") - for i, res in ipairs(maps) do - res:render() - end - tpl.render("footer") -end - ---- Create a CBI form model dispatching target. --- @param model CBI form model tpo be rendered -function form(model) - return {type = "cbi", model = model, target = _form} -end - ---- Access the luci.i18n translate() api. --- @class function --- @name translate --- @param text Text to translate -translate = i18n.translate - ---- No-op function used to mark translation entries for menu labels. --- This function does not actually translate the given argument but --- is used by build/i18n-scan.pl to find translatable entries. -function _(text) - return text -end diff --git a/libs/web/luasrc/http.lua b/libs/web/luasrc/http.lua deleted file mode 100644 index c53307a5a1..0000000000 --- a/libs/web/luasrc/http.lua +++ /dev/null @@ -1,344 +0,0 @@ ---[[ -LuCI - HTTP-Interaction - -Description: -HTTP-Header manipulator and form variable preprocessor - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -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 ipairs, pairs, next, type, tostring, error = - ipairs, pairs, next, type, tostring, error - ---- LuCI Web Framework high-level HTTP functions. -module "luci.http" - -context = util.threadlocal() - -Request = util.class() -function Request.__init__(self, env, sourcein, sinkerr) - self.input = sourcein - self.error = sinkerr - - - -- File handler - self.filehandler = function() end - - -- HTTP-Message table - self.message = { - env = env, - headers = {}, - params = protocol.urldecode_params(env.QUERY_STRING or ""), - } - - self.parsed_input = false -end - -function Request.formvalue(self, name, noparse) - if not noparse and not self.parsed_input then - self:_parse_input() - end - - if name then - return self.message.params[name] - else - return self.message.params - end -end - -function Request.formvaluetable(self, prefix) - local vals = {} - prefix = prefix and prefix .. "." or "." - - if not self.parsed_input then - self:_parse_input() - end - - local void = self.message.params[nil] - for k, v in pairs(self.message.params) do - if k:find(prefix, 1, true) == 1 then - vals[k:sub(#prefix + 1)] = tostring(v) - end - end - - return vals -end - -function Request.content(self) - if not self.parsed_input then - self:_parse_input() - end - - return self.message.content, self.message.content_length -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) -end - -function Request.getenv(self, name) - if name then - return self.message.env[name] - else - return self.message.env - end -end - -function Request.setfilehandler(self, callback) - self.filehandler = callback -end - -function Request._parse_input(self) - protocol.parse_message_body( - self.input, - self.message, - self.filehandler - ) - self.parsed_input = true -end - ---- Close the HTTP-Connection. -function close() - if not context.eoh then - context.eoh = true - coroutine.yield(3) - end - - if not context.closed then - context.closed = true - coroutine.yield(5) - end -end - ---- Return the request content if the request was of unknown type. --- @return HTTP request body --- @return HTTP request body length -function content() - return context.request:content() -end - ---- Get a certain HTTP input value or a table of all input values. --- @param name Name of the GET or POST variable to fetch --- @param noparse Don't parse POST data before getting the value --- @return HTTP input value or table of all input value -function formvalue(name, noparse) - return context.request:formvalue(name, noparse) -end - ---- Get a table of all HTTP input values with a certain prefix. --- @param prefix Prefix --- @return Table of all HTTP input values with given prefix -function formvaluetable(prefix) - return context.request:formvaluetable(prefix) -end - ---- Get the value of a certain HTTP-Cookie. --- @param name Cookie Name --- @return String containing cookie data -function getcookie(name) - return context.request:getcookie(name) -end - ---- Get the value of a certain HTTP environment variable --- or the environment table itself. --- @param name Environment variable --- @return HTTP environment value or environment table -function getenv(name) - return context.request:getenv(name) -end - ---- Set a handler function for incoming user file uploads. --- @param callback Handler function -function setfilehandler(callback) - return context.request:setfilehandler(callback) -end - ---- Send a HTTP-Header. --- @param key Header key --- @param value Header value -function header(key, value) - if not context.headers then - context.headers = {} - end - context.headers[key:lower()] = value - coroutine.yield(2, key, value) -end - ---- Set the mime type of following content data. --- @param mime Mimetype of following content -function prepare_content(mime) - if not context.headers or not context.headers["content-type"] then - if mime == "application/xhtml+xml" then - 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("Content-Type", mime) - end -end - ---- Get the RAW HTTP input source --- @return HTTP LTN12 source -function source() - return context.request.input -end - ---- Set the HTTP status code and status message. --- @param code Status code --- @param message Status message -function status(code, message) - code = code or 200 - message = message or "OK" - context.status = code - coroutine.yield(1, code, message) -end - ---- Send a chunk of content data to the client. --- This function is as a valid LTN12 sink. --- If the content chunk is nil this function will automatically invoke close. --- @param content Content chunk --- @param src_err Error object from source (optional) --- @see close -function write(content, src_err) - if not content then - if src_err then - error(src_err) - else - close() - end - return true - elseif #content == 0 then - return true - else - if not context.eoh then - if not context.status then - status() - end - if not context.headers or not context.headers["content-type"] then - header("Content-Type", "text/html; charset=utf-8") - end - if not context.headers["cache-control"] then - header("Cache-Control", "no-cache") - header("Expires", "0") - end - - - context.eoh = true - coroutine.yield(3) - end - coroutine.yield(4, content) - return true - end -end - ---- Splice data from a filedescriptor to the client. --- @param fp File descriptor --- @param size Bytes to splice (optional) -function splice(fd, size) - coroutine.yield(6, fd, size) -end - ---- Redirects the client to a new URL and closes the connection. --- @param url Target URL -function redirect(url) - status(302, "Found") - header("Location", url) - close() -end - ---- Create a querystring out of a table of key - value pairs. --- @param table Query string source table --- @return Encoded HTTP query string -function build_querystring(q) - local s = { "?" } - - 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) - end - - return table.concat(s, "") -end - ---- Return the URL-decoded equivalent of a string. --- @param str URL-encoded string --- @param no_plus Don't decode + to " " --- @return URL-decoded string --- @see urlencode -urldecode = protocol.urldecode - ---- Return the URL-encoded equivalent of a string. --- @param str Source string --- @return URL-encoded string --- @see urldecode -urlencode = protocol.urlencode - ---- Send the given data as JSON encoded string. --- @param data Data to send -function write_json(x) - if x == nil then - write("null") - elseif type(x) == "table" then - local k, v - if type(next(x)) == "number" then - write("[ ") - for k, v in ipairs(x) do - write_json(v) - if next(x, k) then - write(", ") - end - end - write(" ]") - else - write("{ ") - for k, v in pairs(x) do - write("%q: " % k) - write_json(v) - if next(x, k) then - write(", ") - end - end - write(" }") - end - elseif type(x) == "number" or type(x) == "boolean" then - if (x ~= x) then - -- NaN is the only value that doesn't equal to itself. - write("Number.NaN") - else - write(tostring(x)) - end - else - write('"%s"' % tostring(x):gsub('["%z\1-\31]', function(c) - return '\\u%04x' % c:byte(1) - end)) - end -end diff --git a/libs/web/luasrc/http/protocol.lua b/libs/web/luasrc/http/protocol.lua deleted file mode 100644 index 0d41550b23..0000000000 --- a/libs/web/luasrc/http/protocol.lua +++ /dev/null @@ -1,688 +0,0 @@ ---[[ - -HTTP protocol implementation for LuCI -(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI http protocol class. --- This class contains several functions useful for http message- and content --- decoding and to retrive form data from raw http messages. -module("luci.http.protocol", package.seeall) - -local ltn12 = require("luci.ltn12") - -HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size - ---- Decode an urlencoded string - optionally without decoding --- the "+" sign to " " - and return the decoded string. --- @param str Input string in x-www-urlencoded format --- @param no_plus Don't decode "+" signs to spaces --- @return The decoded string --- @see urlencode -function urldecode( str, no_plus ) - - local function __chrdec( hex ) - 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 - ---- Extract and split urlencoded data pairs, separated bei either "&" or ";" --- from given url or string. Returns a table with urldecoded values. --- Simple parameters are stored as string values associated with the parameter --- name within the table. Parameters with multiple values are stored as array --- containing the corresponding values. --- @param url The url or string which contains x-www-urlencoded form data --- @param tbl Use the given table for storing values (optional) --- @return Table containing the urldecoded parameters --- @see urlencode_params -function urldecode_params( url, tbl ) - - local params = tbl or { } - - 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 - ---- Encode given string to x-www-urlencoded format. --- @param str String to encode --- @return String containing the encoded data --- @see urldecode -function urlencode( str ) - - local function __chrenc( chr ) - 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 - ---- Encode each key-value-pair in given table to x-www-urlencoded format, --- separated by "&". Tables are encoded as parameters with multiple values by --- repeating the parameter name with each value. --- @param tbl Table with the values --- @return String containing encoded values --- @see urldecode_params -function urlencode_params( tbl ) - local enc = "" - - 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. --- @param tbl Table where parameter should be created --- @param key Parameter name --- @return Always nil -local function __initval( tbl, key ) - if tbl[key] == nil then - tbl[key] = "" - elseif type(tbl[key]) == "string" then - tbl[key] = { tbl[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. --- @param tbl Table containing the previously initialized parameter value --- @param key Parameter name --- @param chunk String containing the data to append --- @return Always nil --- @see __initval -local function __appendval( tbl, key, chunk ) - if type(tbl[key]) == "table" then - tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk - 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. --- @param tbl Table containing the previously initialized parameter value --- @param key Parameter name --- @param handler Function which transforms the parameter value --- @return Always nil --- @see __initval --- @see __appendval -local function __finishval( tbl, key, handler ) - if handler then - if type(tbl[key]) == "table" then - 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 - - ---- Creates a ltn12 source from the given socket. The source will return it's --- data line by line with the trailing \r\n stripped of. --- @param sock Readable network socket --- @return Ltn12 source function -function header_source( sock ) - return ltn12.source.simplify( function() - - 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 - ---- Decode a mime encoded http message body with multipart/form-data --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table withing the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. --- If an optional file callback function is given then it is feeded with the --- file contents chunk by chunk and only the extracted file name is stored --- within the params table. The callback function will be called subsequently --- with three arguments: --- o Table containing decoded (name, file) and raw (headers) mime header data --- o String value containing a chunk of the file data --- o Boolean which indicates wheather the current chunk is the last one (eof) --- @param src Ltn12 source function --- @param msg HTTP message object --- @param filecb File callback function (optional) --- @return Value indicating successful operation (not nil means "ok") --- @return String containing the error if unsuccessful --- @see parse_message_header -function mimedecode_message_body( src, msg, filecb ) - - if msg and msg.env.CONTENT_TYPE then - 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 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 - ---- Decode an urlencoded http message body with application/x-www-urlencoded --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table withing the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. --- @param src Ltn12 source function --- @param msg HTTP message object --- @return Value indicating successful operation (not nil means "ok") --- @return String containing the error if unsuccessful --- @see parse_message_header -function urldecode_message_body( src, msg ) - - local tlen = 0 - 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 - ---- Try to extract an http message header including information like protocol --- version, message headers and resulting CGI environment variables from the --- given ltn12 source. --- @param src Ltn12 source function --- @return HTTP message object --- @see parse_message_body -function parse_message_header( src ) - - local ok = true - 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 - ---- Try to extract and decode a http message body from the given ltn12 source. --- This function will examine the Content-Type within the given message object --- to select the appropriate content decoder. --- Currently the application/x-www-urlencoded and application/form-data --- mime types are supported. If the encountered content encoding can't be --- handled then the whole message body will be stored unaltered as "content" --- property within the given message object. --- @param src Ltn12 source function --- @param msg HTTP message object --- @param filecb File data callback (optional, see mimedecode_message_body()) --- @return Value indicating successful operation (not nil means "ok") --- @return String containing the error if unsuccessful --- @see parse_message_header -function parse_message_body( src, msg, filecb ) - -- Is it multipart/mime ? - if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and - 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 - sink = filecb - - -- ... else append to .content - else - msg.content = "" - msg.content_length = 0 - - sink = function( chunk, err ) - 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 err then - return true - end - end - - return true - end -end - ---- Table containing human readable messages for several http status codes. --- @class table -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/libs/web/luasrc/http/protocol/conditionals.lua b/libs/web/luasrc/http/protocol/conditionals.lua deleted file mode 100644 index 75e1f7b37c..0000000000 --- a/libs/web/luasrc/http/protocol/conditionals.lua +++ /dev/null @@ -1,153 +0,0 @@ ---[[ - -HTTP protocol implementation for LuCI - RFC2616 / 14.19, 14.24 - 14.28 -(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI http protocol implementation - HTTP/1.1 bits. --- This class provides basic ETag handling and implements most of the --- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 . -module("luci.http.protocol.conditionals", package.seeall) - -local date = require("luci.http.protocol.date") - - ---- Implement 14.19 / ETag. --- @param stat A file.stat structure --- @return String containing the generated tag suitable for ETag headers -function mk_etag( stat ) - if stat ~= nil then - return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime ) - end -end - ---- 14.24 / If-Match --- Test whether the given message object contains an "If-Match" header and --- compare it against the given stat object. --- @param req HTTP request message object --- @param stat A file.stat object --- @return Boolean indicating whether the precondition is ok --- @return Alternative status code if the precondition failed -function if_match( req, stat ) - local h = req.headers - local etag = mk_etag( stat ) - - -- 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 - ---- 14.25 / If-Modified-Since --- Test whether the given message object contains an "If-Modified-Since" header --- and compare it against the given stat object. --- @param req HTTP request message object --- @param stat A file.stat object --- @return Boolean indicating whether the precondition is ok --- @return Alternative status code if the precondition failed --- @return Table containing extra HTTP headers if the precondition failed -function if_modified_since( req, stat ) - local h = req.headers - - -- 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 - ---- 14.26 / If-None-Match --- Test whether the given message object contains an "If-None-Match" header and --- compare it against the given stat object. --- @param req HTTP request message object --- @param stat A file.stat object --- @return Boolean indicating whether the precondition is ok --- @return Alternative status code if the precondition failed --- @return Table containing extra HTTP headers if the precondition failed -function if_none_match( req, stat ) - local h = req.headers - local etag = mk_etag( stat ) - 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 - ---- 14.27 / If-Range --- The If-Range header is currently not implemented due to the lack of general --- byte range stuff in luci.http.protocol . This function will always return --- false, 412 to indicate a failed precondition. --- @param req HTTP request message object --- @param stat A file.stat object --- @return Boolean indicating whether the precondition is ok --- @return Alternative status code if the precondition failed -function if_range( req, stat ) - -- Sorry, no subranges (yet) - return false, 412 -end - ---- 14.28 / If-Unmodified-Since --- Test whether the given message object contains an "If-Unmodified-Since" --- header and compare it against the given stat object. --- @param req HTTP request message object --- @param stat A file.stat object --- @return Boolean indicating whether the precondition is ok --- @return Alternative status code if the precondition failed -function if_unmodified_since( req, stat ) - local h = req.headers - - -- 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/libs/web/luasrc/http/protocol/date.lua b/libs/web/luasrc/http/protocol/date.lua deleted file mode 100644 index 83d11e2c25..0000000000 --- a/libs/web/luasrc/http/protocol/date.lua +++ /dev/null @@ -1,115 +0,0 @@ ---[[ - -HTTP protocol implementation for LuCI - date handling -(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI http protocol implementation - date helper class. --- This class contains functions to parse, compare and format http dates. -module("luci.http.protocol.date", package.seeall) - -require("luci.sys.zoneinfo") - - -MONTHS = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" -} - ---- Return the time offset in seconds between the UTC and given time zone. --- @param tz Symbolic or numeric timezone specifier --- @return Time offset to UTC in seconds -function tz_offset(tz) - - if type(tz) == "string" then - - -- 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 - ---- Parse given HTTP date string and convert it to unix epoch time. --- @param data String containing the date --- @return Unix epoch time -function to_unix(date) - - local wd, day, mon, yr, hr, min, sec, tz = date:match( - "([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 - ---- Convert the given unix epoch time to valid HTTP date string. --- @param time Unix epoch time --- @return String containing the formatted date -function to_http(time) - return os.date( "%a, %d %b %Y %H:%M:%S GMT", time ) -end - ---- Compare two dates which can either be unix epoch times or HTTP date strings. --- @param d1 The first date or epoch time to compare --- @param d2 The first date or epoch time to compare --- @return -1 - if d1 is lower then d2 --- @return 0 - if both dates are equal --- @return 1 - if d1 is higher then d2 -function compare(d1, d2) - - if d1:match("[^0-9]") then d1 = to_unix(d1) end - 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/libs/web/luasrc/http/protocol/mime.lua b/libs/web/luasrc/http/protocol/mime.lua deleted file mode 100644 index c878160664..0000000000 --- a/libs/web/luasrc/http/protocol/mime.lua +++ /dev/null @@ -1,99 +0,0 @@ ---[[ - -HTTP protocol implementation for LuCI - mime handling -(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI http protocol implementation - mime helper class. --- This class provides functions to guess mime types from file extensions and --- vice versa. -module("luci.http.protocol.mime", package.seeall) - -require("luci.util") - ---- MIME mapping table containg extension - mimetype relations. --- @class table -MIME_TYPES = { - ["txt"] = "text/plain"; - ["js"] = "text/javascript"; - ["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"; -} - ---- Extract extension from a filename and return corresponding mime-type or --- "application/octet-stream" if the extension is unknown. --- @param filename The filename for which the mime type is guessed --- @return String containign the determined mime type -function to_mime(filename) - if type(filename) == "string" then - local ext = filename:match("[^%.]+$") - - if ext and MIME_TYPES[ext:lower()] then - return MIME_TYPES[ext:lower()] - end - end - - return "application/octet-stream" -end - ---- Return corresponding extension for a given mime type or nil if the --- given mime-type is unknown. --- @param mimetype The mimetype to retrieve the extension from --- @return String with the extension or nil for unknown type -function to_ext(mimetype) - if type(mimetype) == "string" then - for ext, type in luci.util.kspairs( MIME_TYPES ) do - if type == mimetype then - return ext - end - end - end - - return nil -end diff --git a/libs/web/luasrc/i18n.lua b/libs/web/luasrc/i18n.lua deleted file mode 100644 index 545a8aed93..0000000000 --- a/libs/web/luasrc/i18n.lua +++ /dev/null @@ -1,104 +0,0 @@ ---[[ -LuCI - Internationalisation - -Description: -A very minimalistic but yet effective internationalisation module - -FileId: -$Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - ---- LuCI translation library. -module("luci.i18n", package.seeall) -require("luci.util") - -local tparser = require "luci.template.parser" - -table = {} -i18ndir = luci.util.libpath() .. "/i18n/" -loaded = {} -context = luci.util.threadlocal() -default = "en" - ---- Clear the translation table. -function clear() -end - ---- Load a translation and copy its data into the translation table. --- @param file Language file --- @param lang Two-letter language code --- @param force Force reload even if already loaded (optional) --- @return Success status -function load(file, lang, force) -end - ---- Load a translation file using the default translation language. --- Alternatively load the translation of the fallback language. --- @param file Language file --- @param force Force reload even if already loaded (optional) -function loadc(file, force) -end - ---- Set the context default translation language. --- @param lang Two-letter language code -function setlanguage(lang) - context.lang = lang:gsub("_", "-") - context.parent = (context.lang:match("^([a-z][a-z])_")) - if not tparser.load_catalog(context.lang, i18ndir) then - if context.parent then - tparser.load_catalog(context.parent, i18ndir) - return context.parent - end - end - return context.lang -end - ---- Return the translated value for a specific translation key. --- @param key Default translation text --- @return Translated string -function translate(key) - return tparser.translate(key) or key -end - ---- Return the translated value for a specific translation key and use it as sprintf pattern. --- @param key Default translation text --- @param ... Format parameters --- @return Translated and formatted string -function translatef(key, ...) - return tostring(translate(key)):format(...) -end - ---- Return the translated value for a specific translation key --- and ensure that the returned value is a Lua string value. --- This is the same as calling <code>tostring(translate(...))</code> --- @param key Default translation text --- @return Translated string -function string(key) - return tostring(translate(key)) -end - ---- Return the translated value for a specific translation key and use it as sprintf pattern. --- Ensure that the returned value is a Lua string value. --- This is the same as calling <code>tostring(translatef(...))</code> --- @param key Default translation text --- @param ... Format parameters --- @return Translated and formatted string -function stringf(key, ...) - return tostring(translate(key)):format(...) -end diff --git a/libs/web/luasrc/sauth.lua b/libs/web/luasrc/sauth.lua deleted file mode 100644 index 32f172dcda..0000000000 --- a/libs/web/luasrc/sauth.lua +++ /dev/null @@ -1,127 +0,0 @@ ---[[ - -Session authentication -(c) 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - -]]-- - ---- LuCI session library. -module("luci.sauth", package.seeall) -require("luci.util") -require("luci.sys") -require("luci.config") -local nixio = require "nixio", require "nixio.util" -local fs = require "nixio.fs" - - -luci.config.sauth = luci.config.sauth or {} -sessionpath = luci.config.sauth.sessionpath -sessiontime = tonumber(luci.config.sauth.sessiontime) or 15 * 60 - ---- Prepare session storage by creating the session directory. -function prepare() - fs.mkdir(sessionpath, 700) - if not sane() then - error("Security Exception: Session path is not sane!") - end -end - -local function _read(id) - local blob = fs.readfile(sessionpath .. "/" .. id) - return blob -end - -local function _write(id, data) - local f = nixio.open(sessionpath .. "/" .. id, "w", 600) - f:writeall(data) - f:close() -end - -local function _checkid(id) - return not not (id and #id == 32 and id:match("^[a-fA-F0-9]+$")) -end - ---- Write session data to a session file. --- @param id Session identifier --- @param data Session data table -function write(id, data) - if not sane() then - prepare() - end - - assert(_checkid(id), "Security Exception: Session ID is invalid!") - assert(type(data) == "table", "Security Exception: Session data invalid!") - - data.atime = luci.sys.uptime() - - _write(id, luci.util.get_bytecode(data)) -end - ---- Read a session and return its content. --- @param id Session identifier --- @return Session data table or nil if the given id is not found -function read(id) - if not id or #id == 0 then - return nil - end - - assert(_checkid(id), "Security Exception: Session ID is invalid!") - - if not sane(sessionpath .. "/" .. id) then - return nil - end - - local blob = _read(id) - local func = loadstring(blob) - setfenv(func, {}) - - local sess = func() - assert(type(sess) == "table", "Session data invalid!") - - if sess.atime and sess.atime + sessiontime < luci.sys.uptime() then - kill(id) - return nil - end - - -- refresh atime in session - write(id, sess) - - return sess -end - ---- Check whether Session environment is sane. --- @return Boolean status -function sane(file) - return luci.sys.process.info("uid") - == fs.stat(file or sessionpath, "uid") - and fs.stat(file or sessionpath, "modestr") - == (file and "rw-------" or "rwx------") -end - ---- Kills a session --- @param id Session identifier -function kill(id) - assert(_checkid(id), "Security Exception: Session ID is invalid!") - fs.unlink(sessionpath .. "/" .. id) -end - ---- Remove all expired session data files -function reap() - if sane() then - local id - for id in nixio.fs.dir(sessionpath) do - if _checkid(id) then - -- reading the session will kill it if it is expired - read(id) - end - end - end -end diff --git a/libs/web/luasrc/template.lua b/libs/web/luasrc/template.lua deleted file mode 100644 index 72127d1df1..0000000000 --- a/libs/web/luasrc/template.lua +++ /dev/null @@ -1,107 +0,0 @@ ---[[ -LuCI - Template Parser - -Description: -A template parser supporting includes, translations, Lua code blocks -and more. It can be used either as a compiler or as an interpreter. - -FileId: $Id$ - -License: -Copyright 2008 Steven Barth <steven@midlink.org> - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -]]-- - -local util = require "luci.util" -local config = require "luci.config" -local tparser = require "luci.template.parser" - -local tostring, pairs, loadstring = tostring, pairs, loadstring -local setmetatable, loadfile = setmetatable, loadfile -local getfenv, setfenv, rawget = getfenv, setfenv, rawget -local assert, type, error = assert, type, error - ---- LuCI template library. -module "luci.template" - -config.template = config.template or {} -viewdir = config.template.viewdir or util.libpath() .. "/view" - - --- Define the namespace for template modules -context = util.threadlocal() - ---- Render a certain template. --- @param name Template name --- @param scope Scope to assign to template (optional) -function render(name, scope) - return Template(name):render(scope or getfenv(2)) -end - - --- Template class -Template = util.class() - --- Shared template cache to store templates in to avoid unnecessary reloading -Template.cache = setmetatable({}, {__mode = "v"}) - - --- Constructor - Reads and compiles the template on-demand -function Template.__init__(self, name) - - self.template = self.cache[name] - self.name = name - - -- Create a new namespace for this template - self.viewns = context.viewns - - -- If we have a cached template, skip compiling and loading - if not self.template then - - -- Compile template - local err - local sourcefile = viewdir .. "/" .. name .. ".htm" - - self.template, _, err = tparser.parse(sourcefile) - - -- If we have no valid template throw error, otherwise cache the template - if not self.template then - error("Failed to load template '" .. name .. "'.\n" .. - "Error while parsing template '" .. sourcefile .. "':\n" .. - (err or "Unknown syntax error")) - else - self.cache[name] = self.template - end - end -end - - --- Renders a template -function Template.render(self, scope) - scope = scope or getfenv(2) - - -- Put our predefined objects in the scope of the template - setfenv(self.template, setmetatable({}, {__index = - function(tbl, key) - return rawget(tbl, key) or self.viewns[key] or scope[key] - end})) - - -- Now finally render the thing - local stat, err = util.copcall(self.template) - if not stat then - error("Failed to execute template '" .. self.name .. "'.\n" .. - "A runtime error occured: " .. tostring(err or "(nil)")) - end -end diff --git a/libs/web/luasrc/view/cbi/apply_xhr.htm b/libs/web/luasrc/view/cbi/apply_xhr.htm deleted file mode 100644 index 1814c9393b..0000000000 --- a/libs/web/luasrc/view/cbi/apply_xhr.htm +++ /dev/null @@ -1,43 +0,0 @@ -<% export("cbi_apply_xhr", function(id, configs, redirect) -%> -<fieldset class="cbi-section" id="cbi-apply-<%=id%>"> - <legend><%:Applying changes%></legend> - <script type="text/javascript">//<![CDATA[ - var apply_xhr = new XHR(); - - apply_xhr.get('<%=luci.dispatcher.build_url("servicectl", "restart", table.concat(configs, ","))%>', null, - function() { - var checkfinish = function() { - apply_xhr.get('<%=luci.dispatcher.build_url("servicectl", "status")%>', null, - function(x) { - if( x.responseText == 'finish' ) - { - var e = document.getElementById('cbi-apply-<%=id%>-status'); - if( e ) - { - e.innerHTML = '<%:Configuration applied.%>'; - window.setTimeout(function() { - e.parentNode.style.display = 'none'; - <% if redirect then %>location.href='<%=redirect%>';<% end %> - }, 1000); - } - } - else - { - var e = document.getElementById('cbi-apply-<%=id%>-status'); - if( e && x.responseText ) e.innerHTML = x.responseText; - - window.setTimeout(checkfinish, 1000); - } - } - ); - } - - window.setTimeout(checkfinish, 1000); - } - ); - //]]></script> - - <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> - <span id="cbi-apply-<%=id%>-status"><%:Waiting for changes to be applied...%></span> -</fieldset> -<%- end) %> diff --git a/libs/web/luasrc/view/cbi/browser.htm b/libs/web/luasrc/view/cbi/browser.htm deleted file mode 100644 index e4a4077d55..0000000000 --- a/libs/web/luasrc/view/cbi/browser.htm +++ /dev/null @@ -1,7 +0,0 @@ -<% local v = self:cfgvalue(section) -%> -<%+cbi/valueheader%> - <input class="cbi-input-text" type="text"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> /> - <script type="text/javascript"> -cbi_browser_init('<%=cbid%>', '<%=resource%>', '<%=luci.dispatcher.build_url("admin", "filebrowser")%>'<%=self.default_path and ", '"..self.default_path.."'"%>); - </script> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/button.htm b/libs/web/luasrc/view/cbi/button.htm deleted file mode 100644 index 30f8ddfda5..0000000000 --- a/libs/web/luasrc/view/cbi/button.htm +++ /dev/null @@ -1,7 +0,0 @@ -<%+cbi/valueheader%> - <% if self:cfgvalue(section) ~= false then %> - <input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> - <% else %> - - - <% end %> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/cell_valuefooter.htm b/libs/web/luasrc/view/cbi/cell_valuefooter.htm deleted file mode 100644 index 220ebd42ba..0000000000 --- a/libs/web/luasrc/view/cbi/cell_valuefooter.htm +++ /dev/null @@ -1,20 +0,0 @@ -</div> -<div id="cbip-<%=self.config.."-"..section.."-"..self.option%>"></div> -</td> - -<% if #self.deps > 0 then -%> - <script type="text/javascript"> - <% for j, d in ipairs(self.deps) do -%> - cbi_d_add("cbi-<%=self.config.."-"..section.."-"..self.option..d.add%>", { - <%- - for k,v in pairs(d.deps) do - -%> - <%-=string.format('"cbid.%s.%s.%s"', self.config, section, k) .. ":" .. string.format("%q", v)-%> - <%-if next(d.deps, k) then-%>,<%-end-%> - <%- - end - -%> - }, "cbip-<%=self.config.."-"..section.."-"..self.option%>"); - <%- end %> - </script> -<%- end %> diff --git a/libs/web/luasrc/view/cbi/cell_valueheader.htm b/libs/web/luasrc/view/cbi/cell_valueheader.htm deleted file mode 100644 index 9e2e145ddb..0000000000 --- a/libs/web/luasrc/view/cbi/cell_valueheader.htm +++ /dev/null @@ -1,2 +0,0 @@ -<td class="cbi-value-field<% if self.error and self.error[section] then %> cbi-value-error<% end %>"> -<div id="cbi-<%=self.config.."-"..section.."-"..self.option%>"> diff --git a/libs/web/luasrc/view/cbi/compound.htm b/libs/web/luasrc/view/cbi/compound.htm deleted file mode 100644 index 12d02bb1d8..0000000000 --- a/libs/web/luasrc/view/cbi/compound.htm +++ /dev/null @@ -1 +0,0 @@ -<%- self:render_children() %> diff --git a/libs/web/luasrc/view/cbi/delegator.htm b/libs/web/luasrc/view/cbi/delegator.htm deleted file mode 100644 index 4fd19265d8..0000000000 --- a/libs/web/luasrc/view/cbi/delegator.htm +++ /dev/null @@ -1,24 +0,0 @@ -<%- self.active:render() %> - <div class="cbi-page-actions"> - <input type="hidden" name="cbi.delg.current" value="<%=self.current%>" /> -<% for _, x in ipairs(self.chain) do %> - <input type="hidden" name="cbi.delg.path" value="<%=x%>" /> -<% end %> -<% if not self.disallow_pageactions then %> -<% if self.allow_finish and not self:get_next(self.current) then %> - <input class="cbi-button cbi-button-finish" type="submit" value="<%:Finish%>" /> -<% elseif self:get_next(self.current) then %> - <input class="cbi-button cbi-button-next" type="submit" value="<%:Next »%>" /> -<% end %> -<% if self.allow_cancel then %> - <input class="cbi-button cbi-button-cancel" type="submit" name="cbi.cancel" value="<%:Cancel%>" /> -<% end %> -<% if self.allow_reset then %> - <input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" /> -<% end %> -<% if self.allow_back and self:get_prev(self.current) then %> - <input class="cbi-button cbi-button-back" type="submit" name="cbi.delg.back" value="<%:« Back%>" /> -<% end %> -<% end %> - <script type="text/javascript">cbi_d_update();</script> - </div> diff --git a/libs/web/luasrc/view/cbi/dvalue.htm b/libs/web/luasrc/view/cbi/dvalue.htm deleted file mode 100644 index 78e6f323d7..0000000000 --- a/libs/web/luasrc/view/cbi/dvalue.htm +++ /dev/null @@ -1,13 +0,0 @@ -<%+cbi/valueheader%> -<% if self.href then %><a href="<%=self.href%>"><% end -%> - <% - local val = self:cfgvalue(section) or self.default or "" - if not self.rawhtml then - write(pcdata(val)) - else - write(val) - end - %> -<%- if self.href then %></a><%end%> -<input type="hidden" id="<%=cbid%>" value="<%=pcdata(self:cfgvalue(section) or self.default or "")%>" /> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/dynlist.htm b/libs/web/luasrc/view/cbi/dynlist.htm deleted file mode 100644 index fd626a4ecf..0000000000 --- a/libs/web/luasrc/view/cbi/dynlist.htm +++ /dev/null @@ -1,26 +0,0 @@ -<%+cbi/valueheader%> -<div> -<% - local vals = self:cfgvalue(section) or {} - for i=1, #vals + 1 do - local val = vals[i] - if (val and #val > 0) or (i == 1) then -%> - <input class="cbi-input-text" value="<%=pcdata(val)%>" onchange="cbi_d_update(this.id)" type="text"<%= - attr("id", cbid .. "." .. i) .. attr("name", cbid) .. ifattr(self.size, "size") .. - ifattr(i == 1 and self.placeholder, "placeholder", self.placeholder) - %> /><br /> -<% end end %> -</div> -<script type="text/javascript"> -cbi_dynlist_init( - '<%=cbid%>', '<%=resource%>', '<%=self.datatype%>', - <%=tostring(self.optional or self.rmempty)%> - <%- if #self.keylist > 0 then -%>, [{ - <%- for i, k in ipairs(self.keylist) do -%> - <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%> - <%-if i<#self.keylist then-%>,<%-end-%> - <%- end -%> - }, '<%: -- custom -- %>']<% end -%>); -</script> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/filebrowser.htm b/libs/web/luasrc/view/cbi/filebrowser.htm deleted file mode 100644 index a79beebba7..0000000000 --- a/libs/web/luasrc/view/cbi/filebrowser.htm +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head> - <title>Filebrowser - LuCI</title> - <style type="text/css"> - #path, #listing { - font-size: 85%; - } - - ul { - padding-left: 0; - list-style-type: none; - } - - li img { - vertical-align: bottom; - margin-right: 0.2em; - } - </style> - - <script type="text/javascript"> - function callback(path) { - if( window.opener ) { - var input = window.opener.document.getElementById('<%=luci.http.formvalue('field')%>'); - if( input ) { - input.value = path; - window.close(); - } - } - } - </script> -</head> -<body> - <% - require("nixio.fs") - require("nixio.util") - require("luci.http") - require("luci.dispatcher") - - local field = luci.http.formvalue('field') - local request = luci.dispatcher.context.args - local path = { '' } - - for i = 1, #request do - if request[i] ~= '..' and #request[i] > 0 then - path[#path+1] = request[i] - end - end - - local filepath = table.concat( path, '/' ) - local filestat = nixio.fs.stat( filepath ) - local baseurl = luci.dispatcher.build_url('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 = '/' - else - filepath = filepath .. '/' - end - - local entries = nixio.util.consume((nixio.fs.dir(filepath))) - -%> - <div id="path"> - Location: - <% for i, dir in ipairs(path) do %> - <% if i == 1 then %> - <a href="<%=baseurl%>?field=<%=field%>">(root)</a> - <% elseif next(path, i) then %> - <% baseurl = baseurl .. '/' .. dir %> - / <a href="<%=baseurl%>?field=<%=field%>"><%=dir%></a> - <% else %> - <% baseurl = baseurl .. '/' .. dir %> - / <%=dir%> - <% end %> - <% end %> - </div> - - <hr /> - - <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 - -%> - <li class="dir"> - <img src="<%=resource%>/cbi/folder.gif" alt="<%:Directory%>" /> - <a href="<%=baseurl%>/<%=e%>?field=<%=field%>"><%=e%>/</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 - -%> - <li class="file"> - <img src="<%=resource%>/cbi/file.gif" alt="<%:File%>" /> - <a href="#" onclick="callback('<%=filepath..e%>')"><%=e%></a> - </li> - <% end end -%> - </ul> - </div> -</body> -</html> diff --git a/libs/web/luasrc/view/cbi/firewall_zoneforwards.htm b/libs/web/luasrc/view/cbi/firewall_zoneforwards.htm deleted file mode 100644 index 2a433b5696..0000000000 --- a/libs/web/luasrc/view/cbi/firewall_zoneforwards.htm +++ /dev/null @@ -1,59 +0,0 @@ -<%+cbi/valueheader%> - -<%- - local utl = require "luci.util" - local fwm = require "luci.model.firewall".init() - local nwm = require "luci.model.network".init() - - local zone, fwd, fz - local value = self:formvalue(section) - if not value or value == "-" then - value = self:cfgvalue(section) or self.default - end - - local def = fwm:get_defaults() - local zone = fwm:get_zone(value) - local empty = true --%> - -<% if zone then %> -<div style="white-space:nowrap"> - <label class="zonebadge" style="background-color:<%=zone:get_color()%>"> - <strong><%=zone:name()%>:</strong> - <%- - local zempty = true - for _, net in ipairs(zone:get_networks()) do - net = nwm:get_network(net) - if net then - zempty = false - -%> - <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: - <% - local nempty = true - for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do - nempty = false - %> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% end %> - <% if nempty then %><em><%:(empty)%></em><% end %> - </span> - <%- end end -%> - <%- if zempty then %><em><%:(empty)%></em><% end -%> - </label> -  ⇒  - <% for _, fwd in ipairs(zone:get_forwardings_by("src")) do - fz = fwd:dest_zone() - empty = false %> - <label class="zonebadge" style="background-color:<%=fz:get_color()%>"> - <strong><%=fz:name()%></strong> - </label>  - <% end %> - <% if empty then %> - <label class="zonebadge zonebadge-empty"> - <strong><%=zone:forward():upper()%></strong> - </label> - <% end %> -</div> -<% end %> - -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/firewall_zonelist.htm b/libs/web/luasrc/view/cbi/firewall_zonelist.htm deleted file mode 100644 index 7973437f40..0000000000 --- a/libs/web/luasrc/view/cbi/firewall_zonelist.htm +++ /dev/null @@ -1,89 +0,0 @@ -<%+cbi/valueheader%> - -<%- - local utl = require "luci.util" - local fwm = require "luci.model.firewall".init() - local nwm = require "luci.model.network".init() - - local zone, net, iface - local zones = fwm:get_zones() - local value = self:formvalue(section) - if not value or value == "-" then - value = self:cfgvalue(section) or self.default - end - - local selected = false - local checked = { } - - for value in utl.imatch(value) do - checked[value] = true - end - - if not next(checked) then - checked[""] = true - end --%> - -<ul style="margin:0; list-style-type:none; text-align:left"> - <% if self.allowlocal then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> - <strong><%:Device%></strong> - <% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %> - </label> - </li> - <% end %> - <% if self.allowany then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> - <strong><%:Any zone%></strong> - <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %> - </label> - </li> - <% end %> - <% - for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do - if zone:name() ~= self.exclude then - selected = selected or (value == zone:name()) - %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge"> - <strong><%=zone:name()%>:</strong> - <% - local zempty = true - for _, net in ipairs(zone:get_networks()) do - net = nwm:get_network(net) - if net then - zempty = false - %> - <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: - <% - local nempty = true - for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do - nempty = false - %> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% end %> - <% if nempty then %><em><%:(empty)%></em><% end %> - </span> - <% end end %> - <% if zempty then %><em><%:(empty)%></em><% end %> - </label> - </li> - <% end end %> - - <% if self.widget ~= "checkbox" and not self.nocreate then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> />   - <div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>"> - <em><%:unspecified -or- create:%> </em> - <input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> - </div> - </li> - <% end %> -</ul> - -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/footer.htm b/libs/web/luasrc/view/cbi/footer.htm deleted file mode 100644 index 2c34028e58..0000000000 --- a/libs/web/luasrc/view/cbi/footer.htm +++ /dev/null @@ -1,26 +0,0 @@ - <%- if pageaction then -%> - <div class="cbi-page-actions"> - <% if redirect then %> - <div style="float:left"> - <input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" /> - </div> - <% end %> - - <% if flow.skip then %> - <input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" /> - <% end %> - <% if not autoapply and not flow.hideapplybtn then %> - <input class="cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" /> - <% end %> - <% if not flow.hidesavebtn then %> - <input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" /> - <% end %> - <% if not flow.hideresetbtn then %> - <input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" /> - <% end %> - - <script type="text/javascript">cbi_d_update();</script> - </div> - <%- end -%> -</form> -<%+footer%> diff --git a/libs/web/luasrc/view/cbi/full_valuefooter.htm b/libs/web/luasrc/view/cbi/full_valuefooter.htm deleted file mode 100644 index 4876fbcc99..0000000000 --- a/libs/web/luasrc/view/cbi/full_valuefooter.htm +++ /dev/null @@ -1,59 +0,0 @@ - <% if self.description and #self.description > 0 then -%> - <% if not luci.util.instanceof(self, luci.cbi.DynamicList) and (not luci.util.instanceof(self, luci.cbi.Flag) or self.orientation == "horizontal") then -%> - <br /> - <%- end %> - <div class="cbi-value-description"> - <span class="cbi-value-helpicon"><img src="<%=resource%>/cbi/help.gif" alt="<%:help%>" /></span> - <%=self.description%> - </div> - <%- end %> - <%- if self.title and #self.title > 0 then -%> - </div> - <%- end -%> -</div> - - -<% if #self.deps > 0 or #self.subdeps > 0 then -%> - <script type="text/javascript" id="cbip-<%=self.config.."-"..section.."-"..self.option%>"> - <% for j, d in ipairs(self.subdeps) do -%> - cbi_d_add("cbi-<%=self.config.."-"..section.."-"..self.option..d.add%>", { - <%- - for k,v in pairs(d.deps) do - local depk - if k:find("!", 1, true) then - depk = string.format('"%s"', k) - elseif k:find(".", 1, true) then - depk = string.format('"cbid.%s"', k) - else - depk = string.format('"cbid.%s.%s.%s"', self.config, section, k) - end - -%> - <%-= depk .. ":" .. string.format("%q", v)-%> - <%-if next(d.deps, k) then-%>,<%-end-%> - <%- - end - -%> - }, "cbip-<%=self.config.."-"..section.."-"..self.option..d.add%>"); - <%- end %> - <% for j, d in ipairs(self.deps) do -%> - cbi_d_add("cbi-<%=self.config.."-"..section.."-"..self.option..d.add%>", { - <%- - for k,v in pairs(d.deps) do - local depk - if k:find("!", 1, true) then - depk = string.format('"%s"', k) - elseif k:find(".", 1, true) then - depk = string.format('"cbid.%s"', k) - else - depk = string.format('"cbid.%s.%s.%s"', self.config, section, k) - end - -%> - <%-= depk .. ":" .. string.format("%q", v)-%> - <%-if next(d.deps, k) then-%>,<%-end-%> - <%- - end - -%> - }, "cbip-<%=self.config.."-"..section.."-"..self.option..d.add%>"); - <%- end %> - </script> -<%- end %> diff --git a/libs/web/luasrc/view/cbi/full_valueheader.htm b/libs/web/luasrc/view/cbi/full_valueheader.htm deleted file mode 100644 index aaf085473a..0000000000 --- a/libs/web/luasrc/view/cbi/full_valueheader.htm +++ /dev/null @@ -1,9 +0,0 @@ -<div class="cbi-value<% if self.error and self.error[section] then %> cbi-value-error<% end %><% if self.last_child then %> cbi-value-last<% end %>" id="cbi-<%=self.config.."-"..section.."-"..self.option%>"> - <%- if self.title and #self.title > 0 then -%> - <label class="cbi-value-title"<%= attr("for", cbid) %>> - <%- if self.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=self.titleref%>"><%- end -%> - <%-=self.title-%> - <%- if self.titleref then -%></a><%- end -%> - </label> - <div class="cbi-value-field"> - <%- end -%> diff --git a/libs/web/luasrc/view/cbi/fvalue.htm b/libs/web/luasrc/view/cbi/fvalue.htm deleted file mode 100644 index a1e0808e8d..0000000000 --- a/libs/web/luasrc/view/cbi/fvalue.htm +++ /dev/null @@ -1,9 +0,0 @@ -<%+cbi/valueheader%> - <input type="hidden" value="1"<%= - attr("name", "cbi.cbe." .. self.config .. "." .. section .. "." .. self.option) - %> /> - <input class="cbi-input-checkbox" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)" type="checkbox"<%= - attr("id", cbid) .. attr("name", cbid) .. attr("value", self.enabled or 1) .. - ifattr((self:cfgvalue(section) or self.default) == self.enabled, "checked", "checked") - %> /> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/header.htm b/libs/web/luasrc/view/cbi/header.htm deleted file mode 100644 index 2bddaba61a..0000000000 --- a/libs/web/luasrc/view/cbi/header.htm +++ /dev/null @@ -1,7 +0,0 @@ -<%+header%> -<form method="post" name="cbi" action="<%=REQUEST_URI%>" enctype="multipart/form-data" onreset="return cbi_validate_reset(this)" onsubmit="return cbi_validate_form(this, '<%:Some fields are invalid, cannot save values!%>')"> - <div> - <script type="text/javascript" src="<%=resource%>/cbi.js"></script> - <input type="hidden" name="cbi.submit" value="1" /> - <input type="submit" value="<%:Save%>" class="hidden" /> - </div> diff --git a/libs/web/luasrc/view/cbi/lvalue.htm b/libs/web/luasrc/view/cbi/lvalue.htm deleted file mode 100644 index 8cc086db42..0000000000 --- a/libs/web/luasrc/view/cbi/lvalue.htm +++ /dev/null @@ -1,18 +0,0 @@ -<%+cbi/valueheader%> -<% if self.widget == "select" then %> - <select class="cbi-input-select" onchange="cbi_d_update(this.id)"<%= attr("id", cbid) .. attr("name", cbid) .. ifattr(self.size, "size") %>> - <% for i, key in pairs(self.keylist) do -%> - <option id="cbi-<%=self.config.."-"..section.."-"..self.option.."-"..key%>"<%= attr("value", key) .. ifattr(tostring(self:cfgvalue(section) or self.default) == key, "selected", "selected") %>><%=striptags(self.vallist[i])%></option> - <%- end %> - </select> -<% elseif self.widget == "radio" then - local c = 0 - for i, key in pairs(self.keylist) do - c = c + 1 -%> - <input class="cbi-input-radio" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)" type="radio"<%= attr("id", cbid..c) .. attr("name", cbid) .. attr("value", key) .. ifattr((self:cfgvalue(section) or self.default) == key, "checked", "checked") %> /> - <label<%= attr("for", cbid..c) %>><%=self.vallist[i]%></label> -<% if c == self.size then c = 0 %><% if self.orientation == "horizontal" then %> <% else %><br /><% end %> -<% end end %> -<% end %> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/map.htm b/libs/web/luasrc/view/cbi/map.htm deleted file mode 100644 index 053220d185..0000000000 --- a/libs/web/luasrc/view/cbi/map.htm +++ /dev/null @@ -1,13 +0,0 @@ -<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%> - <div class="errorbox"><%=pcdata(msg)%></div> -<%- end end -%> - -<%-+cbi/apply_xhr-%> - -<div class="cbi-map" id="cbi-<%=self.config%>"> - <% if self.title and #self.title > 0 then %><h2><a id="content" name="content"><%=self.title%></a></h2><% end %> - <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %> - <%- if firstmap and applymap then cbi_apply_xhr(self.config, parsechain, redirect) end -%> - <%- self:render_children() %> - <br /> -</div> diff --git a/libs/web/luasrc/view/cbi/mvalue.htm b/libs/web/luasrc/view/cbi/mvalue.htm deleted file mode 100644 index 6a0b3881d0..0000000000 --- a/libs/web/luasrc/view/cbi/mvalue.htm +++ /dev/null @@ -1,19 +0,0 @@ -<% local v = self:valuelist(section) or {} -%> -<%+cbi/valueheader%> -<% if self.widget == "select" then %> - <select class="cbi-input-select" multiple="multiple" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= attr("name", cbid) .. ifattr(self.size, "size") %>> - <% for i, key in pairs(self.keylist) do -%> - <option<%= attr("value", key) .. ifattr(luci.util.contains(v, key), "selected", "selected") %>><%=striptags(self.vallist[i])%></option> - <%- end %> - </select> -<% elseif self.widget == "checkbox" then - local c = 0; - for i, key in pairs(self.keylist) do - c = c + 1 -%> - <input class="cbi-input-checkbox" type="checkbox" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= attr("id", cbid..c) .. attr("name", cbid) .. attr("value", key) .. ifattr(luci.util.contains(v, key), "checked", "checked") %> /> - <label<%= attr("for", cbid..c) %>><%=self.vallist[i]%></label><br /> -<% if c == self.size then c = 0 %><br /> -<% end end %> -<% end %> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/network_ifacelist.htm b/libs/web/luasrc/view/cbi/network_ifacelist.htm deleted file mode 100644 index 643d849a50..0000000000 --- a/libs/web/luasrc/view/cbi/network_ifacelist.htm +++ /dev/null @@ -1,81 +0,0 @@ -<%+cbi/valueheader%> - -<%- - local utl = require "luci.util" - local net = require "luci.model.network".init() - local cbeid = luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option - - local iface - local ifaces = net:get_interfaces() - local value - - if self.map:formvalue(cbeid) == "1" then - value = self:formvalue(section) or self.default or "" - else - value = self:cfgvalue(section) or self.default - end - - local checked = { } - - if value then - for value in utl.imatch(value) do - checked[value] = true - end - else - local n = self.network and net:get_network(self.network) - if n then - local i - for _, i in ipairs(n:get_interfaces() or { n:get_interface() }) do - checked[i:name()] = true - end - end - end --%> - -<input type="hidden" name="<%=cbeid%>" value="1" /> -<ul style="margin:0; list-style-type:none"> - <% for _, iface in ipairs(ifaces) do - local link = iface:adminlink() - if (not self.nobridges or not iface:is_bridge()) and - (not self.noinactive or iface:is_up()) and - iface:name() ~= self.exclude - then %> - <li> - <input class="cbi-input-<%=self.widget or "radio"%>" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= - attr("type", self.widget or "radio") .. - attr("id", cbid .. "." .. iface:name()) .. - attr("name", cbid) .. attr("value", iface:name()) .. - ifattr(checked[iface:name()], "checked", "checked") - %> />   - <label<%=attr("for", cbid .. "." .. iface:name())%>> - <% if link then -%><a href="<%=link%>"><% end -%> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% if link then -%></a><% end -%> - <%=pcdata(iface:get_i18n())%> - <% local ns = iface:get_networks(); if #ns > 0 then %>( - <%- local i, n; for i, n in ipairs(ns) do -%> - <%-= (i>1) and ', ' -%> - <a href="<%=n:adminlink()%>"><%=n:name()%></a> - <%- end -%> - )<% end %> - </label> - </li> - <% end end %> - <% if not self.nocreate then %> - <li> - <input class="cbi-input-<%=self.widget or "radio"%>" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= - attr("type", self.widget or "radio") .. - attr("id", cbid .. "_custom") .. - attr("name", cbid) .. - attr("value", " ") - %> />   - <label<%=attr("for", cbid .. "_custom")%>> - <img title="<%:Custom Interface%>" style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/ethernet_disabled.png" /> - <%:Custom Interface%>: - </label> - <input type="text" style="width:50px" onfocus="document.getElementById('<%=cbid%>_custom').checked=true" onblur="var x=document.getElementById('<%=cbid%>_custom'); x.value=this.value; x.checked=true" /> - </li> - <% end %> -</ul> - -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/network_netinfo.htm b/libs/web/luasrc/view/cbi/network_netinfo.htm deleted file mode 100644 index 4fd84112a4..0000000000 --- a/libs/web/luasrc/view/cbi/network_netinfo.htm +++ /dev/null @@ -1,27 +0,0 @@ -<%+cbi/valueheader%> - -<%- - local value = self:formvalue(section) - if not value or value == "-" then - value = self:cfgvalue(section) or self.default - end - - local nwm = require "luci.model.network".init() - local net = nwm:get_network(value) --%> - -<% if net then %> -<span class="ifacebadge"><%=net:name()%>: - <% - local empty = true - for _, iface in ipairs(net:get_interfaces() or { net:get_interface() }) do - if not iface:is_bridge() then - empty = false - %> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% end end %> - <% if empty then %><em><%:(no interfaces attached)%></em><% end %> -</span> -<% end %> - -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/network_netlist.htm b/libs/web/luasrc/view/cbi/network_netlist.htm deleted file mode 100644 index 7e23d149a8..0000000000 --- a/libs/web/luasrc/view/cbi/network_netlist.htm +++ /dev/null @@ -1,81 +0,0 @@ -<%+cbi/valueheader%> - -<%- - local utl = require "luci.util" - local nwm = require "luci.model.network".init() - - local net, iface - local networks = nwm:get_networks() - local value = self:formvalue(section) - - self.cast = nil - - if not value or value == "-" then - value = self:cfgvalue(section) or self.default - end - - local checked = { } - for value in utl.imatch(value) do - checked[value] = true - end --%> - -<ul style="margin:0; list-style-type:none; text-align:left"> - <% for _, net in ipairs(networks) do - if (net:name() ~= "loopback") and - (net:name() ~= self.exclude) and - (not self.novirtual or not net:is_virtual()) - then %> - <li style="padding:0.25em 0"> - <input class="cbi-input-<%=self.widget or "radio"%>" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= - attr("type", self.widget or "radio") .. - attr("id", cbid .. "." .. net:name()) .. - attr("name", cbid) .. attr("value", net:name()) .. - ifattr(checked[net:name()], "checked", "checked") - %> />   - <label<%=attr("for", cbid .. "." .. net:name())%>> - <span class="ifacebadge"><%=net:name()%>: - <% - local empty = true - for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do - if not iface:is_bridge() then - empty = false - %> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% end end %> - <% if empty then %><em><%:(no interfaces attached)%></em><% end %> - </span> - </label> - </li> - <% end end %> - - <% if not self.nocreate then %> - <li style="padding:0.25em 0"> - <input class="cbi-input-<%=self.widget or "radio"%>" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not value and self.widget ~= "checkbox", "checked", "checked")%> />   - <div style="padding:0.5em; display:inline"> - <label<%=attr("for", cbid .. "_new")%>><em> - <%- if self.widget == "checkbox" then -%> - <%:create:%> - <%- else -%> - <%:unspecified -or- create:%> - <%- end -%> </em></label> - <input style="width:6em" type="text"<%=attr("name", cbid .. ".newnet")%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> - </div> - </li> - <% elseif self.widget ~= "checkbox" and self.unspecified then %> - <li style="padding:0.25em 0"> - <input class="cbi-input-<%=self.widget or "radio"%>" onclick="cbi_d_update(this.id)" onchange="cbi_d_update(this.id)"<%= - attr("type", self.widget or "radio") .. - attr("id", cbid .. "_uns") .. - attr("name", cbid) .. - attr("value", "") .. - ifattr(not value or #value == 0, "checked", "checked") - %> />   - <div style="padding:0.5em; display:inline"> - <label<%=attr("for", cbid .. "_uns")%>><em><%:unspecified%></em></label> - </div> - </li> - <% end %> -</ul> - -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/nsection.htm b/libs/web/luasrc/view/cbi/nsection.htm deleted file mode 100644 index 95e7658822..0000000000 --- a/libs/web/luasrc/view/cbi/nsection.htm +++ /dev/null @@ -1,31 +0,0 @@ -<% if self:cfgvalue(self.section) then section = self.section %> - <fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=section%>"> - <% if self.title and #self.title > 0 then -%> - <legend><%=self.title%></legend> - <%- end %> - <% if self.description and #self.description > 0 then -%> - <div class="cbi-section-descr"><%=self.description%></div> - <%- end %> - <% if self.addremove then -%> - <div class="cbi-section-remove right"> - <input type="submit" name="cbi.rns.<%=self.config%>.<%=section%>" value="<%:Delete%>" /> - </div> - <%- end %> - <%+cbi/tabmenu%> - <div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>"> - <%+cbi/ucisection%> - </div> - <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> - <%- end %> - <div class="cbi-section-descr"><%=self.description%></div> - <input type="submit" class="cbi-button-add" name="cbi.cns.<%=self.config%>.<%=self.section%>" value="<%:Add%>" /> - </fieldset> - <%- end %> -<% end %> -<!-- /nsection --> diff --git a/libs/web/luasrc/view/cbi/nullsection.htm b/libs/web/luasrc/view/cbi/nullsection.htm deleted file mode 100644 index bd48950958..0000000000 --- a/libs/web/luasrc/view/cbi/nullsection.htm +++ /dev/null @@ -1,38 +0,0 @@ -<fieldset class="cbi-section"> - <% if self.title and #self.title > 0 then -%> - <legend><%=self.title%></legend> - <%- end %> - <% if self.description and #self.description > 0 then -%> - <div class="cbi-section-descr"><%=self.description%></div> - <%- end %> - <div class="cbi-section-node" id="cbi-<%=self.config%>-<%=tostring(self):sub(8)%>"> - <div> - <% self:render_children(1, scope or {}) %> - </div> - <% if self.error and self.error[1] then -%> - <div class="cbi-section-error"> - <ul><% for _, e in ipairs(self.error[1]) do -%> - <li> - <%- if e == "invalid" then -%> - <%:One or more fields contain invalid values!%> - <%- elseif e == "missing" then -%> - <%:One or more required fields have no value!%> - <%- else -%> - <%=pcdata(e)%> - <%- end -%> - </li> - <%- end %></ul> - </div> - <%- end %> - </div> - <br /> -</fieldset> -<%- - if type(self.hidden) == "table" then - for k, v in pairs(self.hidden) do --%> - <input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" /> -<%- - end - end -%> diff --git a/libs/web/luasrc/view/cbi/simpleform.htm b/libs/web/luasrc/view/cbi/simpleform.htm deleted file mode 100644 index 5216cd50f1..0000000000 --- a/libs/web/luasrc/view/cbi/simpleform.htm +++ /dev/null @@ -1,57 +0,0 @@ -<% if not self.embedded then %> -<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>"> - <div> - <script type="text/javascript" src="<%=resource%>/cbi.js"></script> - <input type="hidden" name="cbi.submit" value="1" /> - </div> -<% end %> - <div class="cbi-map" id="cbi-<%=self.config%>"> - <% if self.title and #self.title > 0 then %><h2><a id="content" name="content"><%=self.title%></a></h2><% end %> - <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %> - <% self:render_children() %> - <br /> - </div> -<%- if self.message then %> - <div><%=self.message%></div> -<%- end %> -<%- if self.errmessage then %> - <div class="error"><%=self.errmessage%></div> -<%- end %> -<% if not self.embedded then %> - <div class="cbi-page-actions"> -<%- - if type(self.hidden) == "table" then - for k, v in pairs(self.hidden) do --%> - <input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" /> -<%- - end - end -%> -<% if redirect then %> - <div style="float:left"> - <input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" /> - </div> -<% end %> -<%- if self.flow and self.flow.skip then %> - <input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" /> -<% end %> -<%- if self.submit ~= false then %> - <input class="cbi-button cbi-button-save" type="submit" value=" - <%- if not self.submit then -%><%-:Submit-%><%-else-%><%=self.submit%><%end-%> - " /> -<% end %> -<%- if self.reset ~= false then %> - <input class="cbi-button cbi-button-reset" type="reset" value=" - <%- if not self.reset then -%><%-:Reset-%><%-else-%><%=self.reset%><%end-%> - " /> -<% end %> -<%- if self.cancel ~= false and self.on_cancel then %> - <input class="cbi-button cbi-button-reset" type="submit" name="cbi.cancel" value=" - <%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%> - " /> -<% end %> - <script type="text/javascript">cbi_d_update();</script> - </div> -</form> -<% end %> diff --git a/libs/web/luasrc/view/cbi/tabcontainer.htm b/libs/web/luasrc/view/cbi/tabcontainer.htm deleted file mode 100644 index 38c435d6a1..0000000000 --- a/libs/web/luasrc/view/cbi/tabcontainer.htm +++ /dev/null @@ -1,7 +0,0 @@ -<% for tab, data in pairs(self.tabs) do %> - <div class="cbi-tabcontainer" id="container.<%=self.config%>.<%=section%>.<%=tab%>"<% if tab ~= self.selected_tab then %> style="display:none"<% end %>> - <% if data.description then %><div class="cbi-tab-descr"><%=data.description%></div><% end %> - <% self:render_tab(tab, section, scope or {}) %> - </div> - <script type="text/javascript">cbi_t_add('<%=self.config%>.<%=section%>', '<%=tab%>')</script> -<% end %> diff --git a/libs/web/luasrc/view/cbi/tabmenu.htm b/libs/web/luasrc/view/cbi/tabmenu.htm deleted file mode 100644 index b96ac9ce4b..0000000000 --- a/libs/web/luasrc/view/cbi/tabmenu.htm +++ /dev/null @@ -1,13 +0,0 @@ -<%- if self.tabs then %> - <ul class="cbi-tabmenu"> - <%- self.selected_tab = luci.http.formvalue("tab." .. self.config .. "." .. section) %> - <%- for _, tab in ipairs(self.tab_names) do if #self.tabs[tab].childs > 0 then %> - <script type="text/javascript">cbi_c['container.<%=self.config%>.<%=section%>.<%=tab%>'] = <%=#self.tabs[tab].childs%>;</script> - <%- if not self.selected_tab then self.selected_tab = tab end %> - <li id="tab.<%=self.config%>.<%=section%>.<%=tab%>" class="cbi-tab<%=(tab == self.selected_tab) and '' or '-disabled'%>"> - <a onclick="this.blur(); return cbi_t_switch('<%=self.config%>.<%=section%>', '<%=tab%>')" href="<%=REQUEST_URI%>?tab.<%=self.config%>.<%=section%>=<%=tab%>"><%=self.tabs[tab].title%></a> - <% if tab == self.selected_tab then %><input type="hidden" id="tab.<%=self.config%>.<%=section%>" name="tab.<%=self.config%>.<%=section%>" value="<%=tab%>" /><% end %> - </li> - <% end end -%> - </ul> -<% end -%> diff --git a/libs/web/luasrc/view/cbi/tblsection.htm b/libs/web/luasrc/view/cbi/tblsection.htm deleted file mode 100644 index d928791167..0000000000 --- a/libs/web/luasrc/view/cbi/tblsection.htm +++ /dev/null @@ -1,146 +0,0 @@ -<%- -local rowcnt = 1 -function rowstyle() - rowcnt = rowcnt + 1 - return (rowcnt % 2) + 1 -end - -function width(o) - if o.width then - if type(o.width) == 'number' then - return ' style="width:%dpx"' % o.width - end - return ' style="width:%s"' % o.width - end - return '' -end --%> - -<!-- tblsection --> -<fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=self.sectiontype%>"> - <% if self.title and #self.title > 0 then -%> - <legend><%=self.title%></legend> - <%- end %> - <%- if self.sortable then -%> - <input type="hidden" id="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" name="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" value="" /> - <%- end -%> - <div class="cbi-section-descr"><%=self.description%></div> - <div class="cbi-section-node"> - <%- local count = 0 -%> - <table class="cbi-section-table"> - <tr class="cbi-section-table-titles"> - <%- if not self.anonymous then -%> - <%- if self.sectionhead then -%> - <th class="cbi-section-table-cell"><%=self.sectionhead%></th> - <%- else -%> - <th> </th> - <%- end -%> - <%- 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 -%> - <%-=k.title-%> - <%- if k.titleref then -%></a><%- 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 -%> - <th class="cbi-section-table-cell"> </th> - <%- count = count + 1; end -%> - </tr> - <tr class="cbi-section-table-descr"> - <%- if not self.anonymous then -%> - <%- if self.sectiondesc then -%> - <th class="cbi-section-table-cell"><%=self.sectiondesc%></th> - <%- else -%> - <th></th> - <%- end -%> - <%- end -%> - <%- for i, k in pairs(self.children) do if not k.optional then -%> - <th class="cbi-section-table-cell"<%=width(k)%>><%=k.description%></th> - <%- end; end; if self.sortable then -%> - <th class="cbi-section-table-cell"></th> - <%- end; if self.extedit or self.addremove then -%> - <th class="cbi-section-table-cell"></th> - <%- end -%> - </tr> - <%- local isempty = true - for i, k in ipairs(self:cfgsections()) do - section = k - isempty = false - scope = { valueheader = "cbi/cell_valueheader", valuefooter = "cbi/cell_valuefooter" } - -%> - <tr class="cbi-section-table-row<% if self.extedit or self.rowcolors then %> cbi-rowstyle-<%=rowstyle()%><% end %>" id="cbi-<%=self.config%>-<%=section%>"> - <% if not self.anonymous then -%> - <th><h3><%=(type(self.sectiontitle) == "function") and self:sectiontitle(section) or k%></h3></th> - <%- end %> - - - <%- - for k, node in ipairs(self.children) do - if not node.optional then - node:render(section, scope or {}) - end - end - -%> - - <%- if self.sortable then -%> - <td class="cbi-section-table-cell"> - <input class="cbi-button cbi-button-up" type="button" value="" onclick="return cbi_row_swap(this, true, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" alt="<%:Move up%>" title="<%:Move up%>" /> - <input class="cbi-button cbi-button-down" type="button" value="" onclick="return cbi_row_swap(this, false, 'cbi.sts.<%=self.config%>.<%=self.sectiontype%>')" alt="<%:Move down%>" title="<%:Move down%>" /> - </td> - <%- end -%> - - <%- if self.extedit or self.addremove then -%> - <td class="cbi-section-table-cell"> - <%- if self.extedit then -%> - <input class="cbi-button cbi-button-edit" type="button" value="<%:Edit%>" - <%- if type(self.extedit) == "string" then - %> onclick="location.href='<%=self.extedit:format(section)%>'" - <%- elseif type(self.extedit) == "function" then - %> onclick="location.href='<%=self:extedit(section)%>'" - <%- end - %> alt="<%:Edit%>" title="<%:Edit%>" /> - <%- end; if self.addremove then %> - <input class="cbi-button cbi-button-remove" type="submit" value="<%:Delete%>" onclick="this.form.cbi_state='del-section'; return true" name="cbi.rts.<%=self.config%>.<%=k%>" alt="<%:Delete%>" title="<%:Delete%>" /> - <%- end -%> - </td> - <%- end -%> - </tr> - <%- end -%> - - <%- if isempty then -%> - <tr class="cbi-section-table-row"> - <td colspan="<%=count%>"><em><br /><%:This section contains no values yet%></em></td> - </tr> - <%- end -%> - </table> - - <% if self.error then %> - <div class="cbi-section-error"> - <ul><% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%> - <li><%=pcdata(e):gsub("\n","<br />")%></li> - <%- end end %></ul> - </div> - <% end %> - - <%- if self.addremove then -%> - <% if self.template_addremove then include(self.template_addremove) else -%> - <div class="cbi-section-create cbi-tblsection-create"> - <% if self.anonymous then %> - <input class="cbi-button cbi-button-add" type="submit" value="<%:Add%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" title="<%:Add%>" /> - <% else %> - <% if self.invalid_cts then -%><div class="cbi-section-error"><% end %> - <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" /> - <script type="text/javascript">cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');</script> - <input class="cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" /> - <% if self.invalid_cts then -%> - <br /><%:Invalid%></div> - <%- end %> - <% end %> - </div> - <%- end %> - <%- end -%> - </div> -</fieldset> -<!-- /tblsection --> diff --git a/libs/web/luasrc/view/cbi/tsection.htm b/libs/web/luasrc/view/cbi/tsection.htm deleted file mode 100644 index 087548bf28..0000000000 --- a/libs/web/luasrc/view/cbi/tsection.htm +++ /dev/null @@ -1,48 +0,0 @@ -<fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=self.sectiontype%>"> - <% if self.title and #self.title > 0 then -%> - <legend><%=self.title%></legend> - <%- end %> - <div class="cbi-section-descr"><%=self.description%></div> - <% local isempty = true for i, k in ipairs(self:cfgsections()) do -%> - <% if self.addremove then -%> - <div class="cbi-section-remove right"> - <input type="submit" name="cbi.rts.<%=self.config%>.<%=k%>" onclick="this.form.cbi_state='del-section'; return true" value="<%:Delete%>" class="cbi-button" /> - </div> - <%- end %> - - <%- section = k; isempty = false -%> - - <% if not self.anonymous then -%> - <h3><%=section:upper()%></h3> - <%- end %> - - <%+cbi/tabmenu%> - - <fieldset class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>"> - <%+cbi/ucisection%> - </fieldset> - <br /> - <%- end %> - - <% if isempty then -%> - <em><%:This section contains no values yet%><br /><br /></em> - <%- 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%>.<%=section%>" value="<%:Add%>" /> - <%- else -%> - <% if self.invalid_cts then -%><div class="cbi-section-error"><% end %> - <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" /> - <script type="text/javascript">cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');</script> - <input type="submit" class="cbi-button cbi-button-add" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" /> - <% if self.invalid_cts then -%> - <br /><%:Invalid%></div> - <%- end %> - <%- end %> - </div> - <%- end %> - <%- end %> -</fieldset> diff --git a/libs/web/luasrc/view/cbi/tvalue.htm b/libs/web/luasrc/view/cbi/tvalue.htm deleted file mode 100644 index fcf7a6c94c..0000000000 --- a/libs/web/luasrc/view/cbi/tvalue.htm +++ /dev/null @@ -1,5 +0,0 @@ -<%+cbi/valueheader%> - <textarea class="cbi-input-textarea" <% if not self.size then %> style="width: 100%"<% else %> cols="<%=self.size%>"<% end %> onchange="cbi_d_update(this.id)"<%= attr("name", cbid) .. attr("id", cbid) .. ifattr(self.rows, "rows") .. ifattr(self.wrap, "wrap") %>> - <%-=pcdata(self:cfgvalue(section))-%> - </textarea> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/ucisection.htm b/libs/web/luasrc/view/cbi/ucisection.htm deleted file mode 100644 index 3b69f12f2e..0000000000 --- a/libs/web/luasrc/view/cbi/ucisection.htm +++ /dev/null @@ -1,75 +0,0 @@ -<%- - if type(self.hidden) == "table" then - for k, v in pairs(self.hidden) do --%> - <input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" /> -<%- - end - end -%> - -<% if self.tabs then %> - <%+cbi/tabcontainer%> -<% else %> - <% self:render_children(section, scope or {}) %> -<% end %> - -<% if self.error and self.error[section] then -%> - <div class="cbi-section-error"> - <ul><% for _, e in ipairs(self.error[section]) do -%> - <li> - <%- if e == "invalid" then -%> - <%:One or more fields contain invalid values!%> - <%- elseif e == "missing" then -%> - <%:One or more required fields have no value!%> - <%- else -%> - <%=pcdata(e)%> - <%- end -%> - </li> - <%- end %></ul> - </div> -<%- end %> - -<% if self.optionals[section] and #self.optionals[section] > 0 or self.dynamic then %> - <div class="cbi-optionals"> - <% if self.dynamic then %> - <input type="text" id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>" /> - <% if self.optionals[section] and #self.optionals[section] > 0 then %> - <script type="text/javascript"> - cbi_combobox_init('cbi.opt.<%=self.config%>.<%=section%>', { - <%- - for i, val in pairs(self.optionals[section]) do - -%> - <%-=string.format("%q", val.option) .. ":" .. string.format("%q", striptags(val.title))-%> - <%-if next(self.optionals[section], i) then-%>,<%-end-%> - <%- - end - -%> - }, '', '<%-: -- custom -- -%>'); - </script> - <% end %> - <% else %> - <select id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>"> - <option><%: -- Additional Field -- %></option> - <% for key, val in pairs(self.optionals[section]) do -%> - <option id="cbi-<%=self.config.."-"..section.."-"..val.option%>" value="<%=val.option%>"><%=striptags(val.title)%></option> - <%- end %> - </select> - <script type="text/javascript"><% for key, val in pairs(self.optionals[section]) do %> - <% if #val.deps > 0 then %><% for j, d in ipairs(val.deps) do -%> - cbi_d_add("cbi-<%=self.config.."-"..section.."-"..val.option..d.add%>", { - <%- - for k,v in pairs(d.deps) do - -%> - <%-=string.format('"cbid.%s.%s.%s"', self.config, section, k) .. ":" .. string.format("%q", v)-%> - <%-if next(d.deps, k) then-%>,<%-end-%> - <%- - end - -%> - }); - <%- end %><% end %> - <% end %></script> - <% end %> - <input type="submit" class="cbi-button cbi-button-fieldadd" value="<%:Add%>" /> - </div> -<% end %> diff --git a/libs/web/luasrc/view/cbi/upload.htm b/libs/web/luasrc/view/cbi/upload.htm deleted file mode 100644 index 7770934111..0000000000 --- a/libs/web/luasrc/view/cbi/upload.htm +++ /dev/null @@ -1,14 +0,0 @@ -<% - local t = require("luci.tools.webadmin") - local v = self:cfgvalue(section) - local s = v and nixio.fs.stat(v) --%> -<%+cbi/valueheader%> - <% if s then %> - <%:Uploaded File%> (<%=t.byte_format(s.size)%>) - <input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> /> - <input class="cbi-button cbi-input-image" type="image" value="<%:Replace entry%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:Replace entry%>" title="<%:Replace entry%>" src="<%=resource%>/cbi/reload.gif" /> - <% else %> - <input class="cbi-input-file" type="file"<%= attr("name", cbid) .. attr("id", cbid) %> /> - <% end %> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/value.htm b/libs/web/luasrc/view/cbi/value.htm deleted file mode 100644 index d1a7bea5c6..0000000000 --- a/libs/web/luasrc/view/cbi/value.htm +++ /dev/null @@ -1,35 +0,0 @@ -<%+cbi/valueheader%> - <input type="<%=self.password and 'password" class="cbi-input-password' or 'text" class="cbi-input-text' %>" onchange="cbi_d_update(this.id)"<%= - attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) .. - ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder") - %> /> - <% if self.password then %><img src="<%=resource%>/cbi/reload.gif" style="vertical-align:middle" title="<%:Reveal/hide password%>" onclick="var e = document.getElementById('<%=cbid%>'); e.type = (e.type=='password') ? 'text' : 'password';" /><% end %> - <% if #self.keylist > 0 or self.datatype then -%> - <script type="text/javascript">//<![CDATA[ - <% if #self.keylist > 0 then -%> - cbi_combobox_init('<%=cbid%>', { - <%- - for i, k in ipairs(self.keylist) do - -%> - <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%> - <%-if i<#self.keylist then-%>,<%-end-%> - <%- - end - -%> - }, '<%- if not self.rmempty and not self.optional then -%> - <%-: -- Please choose -- -%> - <%- elseif self.placeholder then -%> - <%-= pcdata(self.placeholder) -%> - <%- end -%>', ' - <%- if self.combobox_manual then -%> - <%-=self.combobox_manual-%> - <%- else -%> - <%-: -- custom -- -%> - <%- end -%>'); - <%- end %> - <% if self.datatype then -%> - cbi_validate_field('<%=cbid%>', <%=tostring((self.optional or self.rmempty) == true)%>, '<%=self.datatype:gsub("'", "\\'")%>'); - <%- end %> - //]]></script> - <% end -%> -<%+cbi/valuefooter%> diff --git a/libs/web/luasrc/view/cbi/valuefooter.htm b/libs/web/luasrc/view/cbi/valuefooter.htm deleted file mode 100644 index 805312e451..0000000000 --- a/libs/web/luasrc/view/cbi/valuefooter.htm +++ /dev/null @@ -1 +0,0 @@ -<% include( valuefooter or "cbi/full_valuefooter" ) %> diff --git a/libs/web/luasrc/view/cbi/valueheader.htm b/libs/web/luasrc/view/cbi/valueheader.htm deleted file mode 100644 index 761a54aed0..0000000000 --- a/libs/web/luasrc/view/cbi/valueheader.htm +++ /dev/null @@ -1 +0,0 @@ -<% include( valueheader or "cbi/full_valueheader" ) %> diff --git a/libs/web/root/etc/config/luci b/libs/web/root/etc/config/luci deleted file mode 100644 index c503a8f1e0..0000000000 --- a/libs/web/root/etc/config/luci +++ /dev/null @@ -1,24 +0,0 @@ -config core main - option lang auto - option mediaurlbase /luci-static/openwrt.org - option resourcebase /luci-static/resources - -config extern flash_keep - option uci "/etc/config/" - option dropbear "/etc/dropbear/" - option openvpn "/etc/openvpn/" - option passwd "/etc/passwd" - option opkg "/etc/opkg.conf" - option firewall "/etc/firewall.user" - option uploads "/lib/uci/upload/" - -config internal languages - -config internal sauth - option sessionpath "/tmp/luci-sessions" - option sessiontime 3600 - -config internal ccache - option enable 1 - -config internal themes diff --git a/libs/web/root/lib/uci/upload/.gitignore b/libs/web/root/lib/uci/upload/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/libs/web/root/lib/uci/upload/.gitignore +++ /dev/null diff --git a/libs/web/src/po2lmo.c b/libs/web/src/po2lmo.c deleted file mode 100644 index 0da792b680..0000000000 --- a/libs/web/src/po2lmo.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * lmo - Lua Machine Objects - PO to LMO conversion tool - * - * Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "template_lmo.h" - -static void die(const char *msg) -{ - fprintf(stderr, "Error: %s\n", msg); - exit(1); -} - -static void usage(const char *name) -{ - fprintf(stderr, "Usage: %s input.po output.lmo\n", name); - exit(1); -} - -static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - if( fwrite(ptr, size, nmemb, stream) == 0 ) - die("Failed to write stdout"); -} - -static int extract_string(const char *src, char *dest, int len) -{ - int pos = 0; - int esc = 0; - int off = -1; - - for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ ) - { - if( (off == -1) && (src[pos] == '"') ) - { - off = pos + 1; - } - else if( off >= 0 ) - { - if( esc == 1 ) - { - switch (src[pos]) - { - case '"': - case '\\': - off++; - break; - } - dest[pos-off] = src[pos]; - esc = 0; - } - else if( src[pos] == '\\' ) - { - dest[pos-off] = src[pos]; - esc = 1; - } - else if( src[pos] != '"' ) - { - dest[pos-off] = src[pos]; - } - else - { - dest[pos-off] = '\0'; - break; - } - } - } - - return (off > -1) ? strlen(dest) : -1; -} - -static int cmp_index(const void *a, const void *b) -{ - uint32_t x = ((const lmo_entry_t *)a)->key_id; - uint32_t y = ((const lmo_entry_t *)b)->key_id; - - if (x < y) - return -1; - else if (x > y) - return 1; - - return 0; -} - -static void print_uint32(uint32_t x, FILE *out) -{ - uint32_t y = htonl(x); - print(&y, sizeof(uint32_t), 1, out); -} - -static void print_index(void *array, int n, FILE *out) -{ - lmo_entry_t *e; - - qsort(array, n, sizeof(*e), cmp_index); - - for (e = array; n > 0; n--, e++) - { - print_uint32(e->key_id, out); - print_uint32(e->val_id, out); - print_uint32(e->offset, out); - print_uint32(e->length, out); - } -} - -int main(int argc, char *argv[]) -{ - char line[4096]; - char key[4096]; - char val[4096]; - char tmp[4096]; - int state = 0; - int offset = 0; - int length = 0; - int n_entries = 0; - void *array = NULL; - lmo_entry_t *entry = NULL; - uint32_t key_id, val_id; - - FILE *in; - FILE *out; - - if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) - usage(argv[0]); - - memset(line, 0, sizeof(key)); - memset(key, 0, sizeof(val)); - memset(val, 0, sizeof(val)); - - while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) - { - if( state == 0 && strstr(line, "msgid \"") == line ) - { - switch(extract_string(line, key, sizeof(key))) - { - case -1: - die("Syntax error in msgid"); - case 0: - state = 1; - break; - default: - state = 2; - } - } - else if( state == 1 || state == 2 ) - { - if( strstr(line, "msgstr \"") == line || state == 2 ) - { - switch(extract_string(line, val, sizeof(val))) - { - case -1: - state = 4; - break; - default: - state = 3; - } - } - else - { - switch(extract_string(line, tmp, sizeof(tmp))) - { - case -1: - state = 2; - break; - default: - strcat(key, tmp); - } - } - } - else if( state == 3 ) - { - switch(extract_string(line, tmp, sizeof(tmp))) - { - case -1: - state = 4; - break; - default: - strcat(val, tmp); - } - } - - if( state == 4 ) - { - if( strlen(key) > 0 && strlen(val) > 0 ) - { - key_id = sfh_hash(key, strlen(key)); - val_id = sfh_hash(val, strlen(val)); - - if( key_id != val_id ) - { - n_entries++; - array = realloc(array, n_entries * sizeof(lmo_entry_t)); - entry = (lmo_entry_t *)array + n_entries - 1; - - if (!array) - die("Out of memory"); - - entry->key_id = key_id; - entry->val_id = val_id; - entry->offset = offset; - entry->length = strlen(val); - - length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); - - print(val, length, 1, out); - offset += length; - } - } - - state = 0; - memset(key, 0, sizeof(key)); - memset(val, 0, sizeof(val)); - } - - memset(line, 0, sizeof(line)); - } - - print_index(array, n_entries, out); - - if( offset > 0 ) - { - print_uint32(offset, out); - fsync(fileno(out)); - fclose(out); - } - else - { - fclose(out); - unlink(argv[2]); - } - - fclose(in); - return(0); -} diff --git a/libs/web/src/template_lmo.c b/libs/web/src/template_lmo.c deleted file mode 100644 index 27205a7228..0000000000 --- a/libs/web/src/template_lmo.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * lmo - Lua Machine Objects - Base functions - * - * Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "template_lmo.h" - -/* - * Hash function from http://www.azillionmonkeys.com/qed/hash.html - * Copyright (C) 2004-2008 by Paul Hsieh - */ - -uint32_t sfh_hash(const char *data, int len) -{ - uint32_t hash = len, tmp; - int rem; - - if (len <= 0 || data == NULL) return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) { - hash += sfh_get16(data); - tmp = (sfh_get16(data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof(uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: hash += sfh_get16(data); - hash ^= hash << 16; - hash ^= data[sizeof(uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += sfh_get16(data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -uint32_t lmo_canon_hash(const char *str, int len) -{ - char res[4096]; - char *ptr, prev; - int off; - - if (!str || len >= sizeof(res)) - return 0; - - for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++) - { - if (isspace(*str)) - { - if (!isspace(prev)) - *ptr++ = ' '; - } - else - { - *ptr++ = *str; - } - } - - if ((ptr > res) && isspace(*(ptr-1))) - ptr--; - - return sfh_hash(res, ptr - res); -} - -lmo_archive_t * lmo_open(const char *file) -{ - int in = -1; - uint32_t idx_offset = 0; - struct stat s; - - lmo_archive_t *ar = NULL; - - if (stat(file, &s) == -1) - goto err; - - if ((in = open(file, O_RDONLY)) == -1) - goto err; - - if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL) - { - memset(ar, 0, sizeof(*ar)); - - ar->fd = in; - ar->size = s.st_size; - - fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC); - - if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED) - goto err; - - idx_offset = ntohl(*((const uint32_t *) - (ar->mmap + ar->size - sizeof(uint32_t)))); - - if (idx_offset >= ar->size) - goto err; - - ar->index = (lmo_entry_t *)(ar->mmap + idx_offset); - ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t); - ar->end = ar->mmap + ar->size; - - return ar; - } - -err: - if (in > -1) - close(in); - - if (ar != NULL) - { - if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) - munmap(ar->mmap, ar->size); - - free(ar); - } - - return NULL; -} - -void lmo_close(lmo_archive_t *ar) -{ - if (ar != NULL) - { - if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) - munmap(ar->mmap, ar->size); - - close(ar->fd); - free(ar); - - ar = NULL; - } -} - - -lmo_catalog_t *_lmo_catalogs = NULL; -lmo_catalog_t *_lmo_active_catalog = NULL; - -int lmo_load_catalog(const char *lang, const char *dir) -{ - DIR *dh = NULL; - char pattern[16]; - char path[PATH_MAX]; - struct dirent *de = NULL; - - lmo_archive_t *ar = NULL; - lmo_catalog_t *cat = NULL; - - if (!lmo_change_catalog(lang)) - return 0; - - if (!dir || !(dh = opendir(dir))) - goto err; - - if (!(cat = malloc(sizeof(*cat)))) - goto err; - - memset(cat, 0, sizeof(*cat)); - - snprintf(cat->lang, sizeof(cat->lang), "%s", lang); - snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang); - - while ((de = readdir(dh)) != NULL) - { - if (!fnmatch(pattern, de->d_name, 0)) - { - snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); - ar = lmo_open(path); - - if (ar) - { - ar->next = cat->archives; - cat->archives = ar; - } - } - } - - closedir(dh); - - cat->next = _lmo_catalogs; - _lmo_catalogs = cat; - - if (!_lmo_active_catalog) - _lmo_active_catalog = cat; - - return 0; - -err: - if (dh) closedir(dh); - if (cat) free(cat); - - return -1; -} - -int lmo_change_catalog(const char *lang) -{ - lmo_catalog_t *cat; - - for (cat = _lmo_catalogs; cat; cat = cat->next) - { - if (!strncmp(cat->lang, lang, sizeof(cat->lang))) - { - _lmo_active_catalog = cat; - return 0; - } - } - - return -1; -} - -static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash) -{ - unsigned int m, l, r; - uint32_t k; - - l = 0; - r = ar->length - 1; - - while (1) - { - m = l + ((r - l) / 2); - - if (r < l) - break; - - k = ntohl(ar->index[m].key_id); - - if (k == hash) - return &ar->index[m]; - - if (k > hash) - { - if (!m) - break; - - r = m - 1; - } - else - { - l = m + 1; - } - } - - return NULL; -} - -int lmo_translate(const char *key, int keylen, char **out, int *outlen) -{ - uint32_t hash; - lmo_entry_t *e; - lmo_archive_t *ar; - - if (!key || !_lmo_active_catalog) - return -2; - - hash = lmo_canon_hash(key, keylen); - - for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) - { - if ((e = lmo_find_entry(ar, hash)) != NULL) - { - *out = ar->mmap + ntohl(e->offset); - *outlen = ntohl(e->length); - return 0; - } - } - - return -1; -} - -void lmo_close_catalog(const char *lang) -{ - lmo_archive_t *ar, *next; - lmo_catalog_t *cat, *prev; - - for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next) - { - if (!strncmp(cat->lang, lang, sizeof(cat->lang))) - { - if (prev) - prev->next = cat->next; - else - _lmo_catalogs = cat->next; - - for (ar = cat->archives; ar; ar = next) - { - next = ar->next; - lmo_close(ar); - } - - free(cat); - break; - } - } -} diff --git a/libs/web/src/template_lmo.h b/libs/web/src/template_lmo.h deleted file mode 100644 index 57f59aa56b..0000000000 --- a/libs/web/src/template_lmo.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * lmo - Lua Machine Objects - General header - * - * Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _TEMPLATE_LMO_H_ -#define _TEMPLATE_LMO_H_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <arpa/inet.h> -#include <unistd.h> -#include <errno.h> -#include <fnmatch.h> -#include <dirent.h> -#include <ctype.h> -#include <limits.h> - -#if (defined(__GNUC__) && defined(__i386__)) -#define sfh_get16(d) (*((const uint16_t *) (d))) -#else -#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif - - -struct lmo_entry { - uint32_t key_id; - uint32_t val_id; - uint32_t offset; - uint32_t length; -} __attribute__((packed)); - -typedef struct lmo_entry lmo_entry_t; - - -struct lmo_archive { - int fd; - int length; - uint32_t size; - lmo_entry_t *index; - char *mmap; - char *end; - struct lmo_archive *next; -}; - -typedef struct lmo_archive lmo_archive_t; - - -struct lmo_catalog { - char lang[6]; - struct lmo_archive *archives; - struct lmo_catalog *next; -}; - -typedef struct lmo_catalog lmo_catalog_t; - - -uint32_t sfh_hash(const char *data, int len); -uint32_t lmo_canon_hash(const char *data, int len); - -lmo_archive_t * lmo_open(const char *file); -void lmo_close(lmo_archive_t *ar); - - -extern lmo_catalog_t *_lmo_catalogs; -extern lmo_catalog_t *_lmo_active_catalog; - -int lmo_load_catalog(const char *lang, const char *dir); -int lmo_change_catalog(const char *lang); -int lmo_translate(const char *key, int keylen, char **out, int *outlen); -void lmo_close_catalog(const char *lang); - -#endif diff --git a/libs/web/src/template_lualib.c b/libs/web/src/template_lualib.c deleted file mode 100644 index 0d43641041..0000000000 --- a/libs/web/src/template_lualib.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * LuCI Template - Lua binding - * - * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "template_lualib.h" - -int template_L_parse(lua_State *L) -{ - const char *file = luaL_checkstring(L, 1); - struct template_parser *parser = template_open(file); - int lua_status, rv; - - if (!parser) - { - lua_pushnil(L); - lua_pushinteger(L, errno); - lua_pushstring(L, strerror(errno)); - return 3; - } - - lua_status = lua_load(L, template_reader, parser, file); - - if (lua_status == 0) - rv = 1; - else - rv = template_error(L, parser); - - template_close(parser); - - return rv; -} - -int template_L_utf8(lua_State *L) -{ - size_t len = 0; - const char *str = luaL_checklstring(L, 1, &len); - char *res = utf8(str, len); - - if (res != NULL) - { - lua_pushstring(L, res); - free(res); - - return 1; - } - - return 0; -} - -int template_L_pcdata(lua_State *L) -{ - size_t len = 0; - const char *str = luaL_checklstring(L, 1, &len); - char *res = pcdata(str, len); - - if (res != NULL) - { - lua_pushstring(L, res); - free(res); - - return 1; - } - - return 0; -} - -int template_L_striptags(lua_State *L) -{ - size_t len = 0; - const char *str = luaL_checklstring(L, 1, &len); - char *res = striptags(str, len); - - if (res != NULL) - { - lua_pushstring(L, res); - free(res); - - return 1; - } - - return 0; -} - -static int template_L_load_catalog(lua_State *L) { - const char *lang = luaL_optstring(L, 1, "en"); - const char *dir = luaL_optstring(L, 2, NULL); - lua_pushboolean(L, !lmo_load_catalog(lang, dir)); - return 1; -} - -static int template_L_close_catalog(lua_State *L) { - const char *lang = luaL_optstring(L, 1, "en"); - lmo_close_catalog(lang); - return 0; -} - -static int template_L_change_catalog(lua_State *L) { - const char *lang = luaL_optstring(L, 1, "en"); - lua_pushboolean(L, !lmo_change_catalog(lang)); - return 1; -} - -static int template_L_translate(lua_State *L) { - size_t len; - char *tr; - int trlen; - const char *key = luaL_checklstring(L, 1, &len); - - switch (lmo_translate(key, len, &tr, &trlen)) - { - case 0: - lua_pushlstring(L, tr, trlen); - return 1; - - case -1: - return 0; - } - - lua_pushnil(L); - lua_pushstring(L, "no catalog loaded"); - return 2; -} - -static int template_L_hash(lua_State *L) { - size_t len; - const char *key = luaL_checklstring(L, 1, &len); - lua_pushinteger(L, sfh_hash(key, len)); - return 1; -} - - -/* module table */ -static const luaL_reg R[] = { - { "parse", template_L_parse }, - { "utf8", template_L_utf8 }, - { "pcdata", template_L_pcdata }, - { "striptags", template_L_striptags }, - { "load_catalog", template_L_load_catalog }, - { "close_catalog", template_L_close_catalog }, - { "change_catalog", template_L_change_catalog }, - { "translate", template_L_translate }, - { "hash", template_L_hash }, - { NULL, NULL } -}; - -LUALIB_API int luaopen_luci_template_parser(lua_State *L) { - luaL_register(L, TEMPLATE_LUALIB_META, R); - return 1; -} diff --git a/libs/web/src/template_lualib.h b/libs/web/src/template_lualib.h deleted file mode 100644 index 1b659be126..0000000000 --- a/libs/web/src/template_lualib.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * LuCI Template - Lua library header - * - * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _TEMPLATE_LUALIB_H_ -#define _TEMPLATE_LUALIB_H_ - -#include "template_parser.h" -#include "template_utils.h" -#include "template_lmo.h" - -#define TEMPLATE_LUALIB_META "template.parser" - -LUALIB_API int luaopen_luci_template_parser(lua_State *L); - -#endif diff --git a/libs/web/src/template_parser.c b/libs/web/src/template_parser.c deleted file mode 100644 index 6054451315..0000000000 --- a/libs/web/src/template_parser.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * LuCI Template - Parser implementation - * - * Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "template_parser.h" -#include "template_utils.h" -#include "template_lmo.h" - - -/* leading and trailing code for different types */ -const char *gen_code[9][2] = { - { NULL, NULL }, - { "write(\"", "\")" }, - { NULL, NULL }, - { "write(tostring(", " or \"\"))" }, - { "include(\"", "\")" }, - { "write(\"", "\")" }, - { "write(\"", "\")" }, - { NULL, " " }, - { NULL, NULL }, -}; - -/* Simple strstr() like function that takes len arguments for both haystack and needle. */ -static char *strfind(char *haystack, int hslen, const char *needle, int ndlen) -{ - int match = 0; - int i, j; - - for( i = 0; i < hslen; i++ ) - { - if( haystack[i] == needle[0] ) - { - match = ((ndlen == 1) || ((i + ndlen) <= hslen)); - - for( j = 1; (j < ndlen) && ((i + j) < hslen); j++ ) - { - if( haystack[i+j] != needle[j] ) - { - match = 0; - break; - } - } - - if( match ) - return &haystack[i]; - } - } - - return NULL; -} - -struct template_parser * template_open(const char *file) -{ - struct stat s; - static struct template_parser *parser; - - if (!(parser = malloc(sizeof(*parser)))) - goto err; - - memset(parser, 0, sizeof(*parser)); - parser->fd = -1; - parser->file = file; - - if (stat(file, &s)) - goto err; - - if ((parser->fd = open(file, O_RDONLY)) < 0) - goto err; - - parser->size = s.st_size; - parser->mmap = mmap(NULL, parser->size, PROT_READ, MAP_PRIVATE, - parser->fd, 0); - - if (parser->mmap != MAP_FAILED) - { - parser->off = parser->mmap; - parser->cur_chunk.type = T_TYPE_INIT; - parser->cur_chunk.s = parser->mmap; - parser->cur_chunk.e = parser->mmap; - - return parser; - } - -err: - template_close(parser); - return NULL; -} - -void template_close(struct template_parser *parser) -{ - if (!parser) - return; - - if (parser->gc != NULL) - free(parser->gc); - - if ((parser->mmap != NULL) && (parser->mmap != MAP_FAILED)) - munmap(parser->mmap, parser->size); - - if (parser->fd >= 0) - close(parser->fd); - - free(parser); -} - -void template_text(struct template_parser *parser, const char *e) -{ - const char *s = parser->off; - - if (s < (parser->mmap + parser->size)) - { - if (parser->strip_after) - { - while ((s <= e) && isspace(*s)) - s++; - } - - parser->cur_chunk.type = T_TYPE_TEXT; - } - else - { - parser->cur_chunk.type = T_TYPE_EOF; - } - - parser->cur_chunk.line = parser->line; - parser->cur_chunk.s = s; - parser->cur_chunk.e = e; -} - -void template_code(struct template_parser *parser, const char *e) -{ - const char *s = parser->off; - - parser->strip_before = 0; - parser->strip_after = 0; - - if (*s == '-') - { - parser->strip_before = 1; - for (s++; (s <= e) && (*s == ' ' || *s == '\t'); s++); - } - - if (*(e-1) == '-') - { - parser->strip_after = 1; - for (e--; (e >= s) && (*e == ' ' || *e == '\t'); e--); - } - - switch (*s) - { - /* comment */ - case '#': - s++; - parser->cur_chunk.type = T_TYPE_COMMENT; - break; - - /* include */ - case '+': - s++; - parser->cur_chunk.type = T_TYPE_INCLUDE; - break; - - /* translate */ - case ':': - s++; - parser->cur_chunk.type = T_TYPE_I18N; - break; - - /* translate raw */ - case '_': - s++; - parser->cur_chunk.type = T_TYPE_I18N_RAW; - break; - - /* expr */ - case '=': - s++; - parser->cur_chunk.type = T_TYPE_EXPR; - break; - - /* code */ - default: - parser->cur_chunk.type = T_TYPE_CODE; - break; - } - - parser->cur_chunk.line = parser->line; - parser->cur_chunk.s = s; - parser->cur_chunk.e = e; -} - -static const char * -template_format_chunk(struct template_parser *parser, size_t *sz) -{ - const char *s, *p; - const char *head, *tail; - struct template_chunk *c = &parser->prv_chunk; - struct template_buffer *buf; - - *sz = 0; - s = parser->gc = NULL; - - if (parser->strip_before && c->type == T_TYPE_TEXT) - { - while ((c->e > c->s) && isspace(*(c->e - 1))) - c->e--; - } - - /* empty chunk */ - if (c->s == c->e) - { - if (c->type == T_TYPE_EOF) - { - *sz = 0; - s = NULL; - } - else - { - *sz = 1; - s = " "; - } - } - - /* format chunk */ - else if ((buf = buf_init(c->e - c->s)) != NULL) - { - if ((head = gen_code[c->type][0]) != NULL) - buf_append(buf, head, strlen(head)); - - switch (c->type) - { - case T_TYPE_TEXT: - luastr_escape(buf, c->s, c->e - c->s, 0); - break; - - case T_TYPE_EXPR: - buf_append(buf, c->s, c->e - c->s); - for (p = c->s; p < c->e; p++) - parser->line += (*p == '\n'); - break; - - case T_TYPE_INCLUDE: - luastr_escape(buf, c->s, c->e - c->s, 0); - break; - - case T_TYPE_I18N: - luastr_translate(buf, c->s, c->e - c->s, 1); - break; - - case T_TYPE_I18N_RAW: - luastr_translate(buf, c->s, c->e - c->s, 0); - break; - - case T_TYPE_CODE: - buf_append(buf, c->s, c->e - c->s); - for (p = c->s; p < c->e; p++) - parser->line += (*p == '\n'); - break; - } - - if ((tail = gen_code[c->type][1]) != NULL) - buf_append(buf, tail, strlen(tail)); - - *sz = buf_length(buf); - s = parser->gc = buf_destroy(buf); - - if (!*sz) - { - *sz = 1; - s = " "; - } - } - - return s; -} - -const char *template_reader(lua_State *L, void *ud, size_t *sz) -{ - struct template_parser *parser = ud; - int rem = parser->size - (parser->off - parser->mmap); - char *tag; - - parser->prv_chunk = parser->cur_chunk; - - /* free previous string */ - if (parser->gc) - { - free(parser->gc); - parser->gc = NULL; - } - - /* before tag */ - if (!parser->in_expr) - { - if ((tag = strfind(parser->off, rem, "<%", 2)) != NULL) - { - template_text(parser, tag); - parser->off = tag + 2; - parser->in_expr = 1; - } - else - { - template_text(parser, parser->mmap + parser->size); - parser->off = parser->mmap + parser->size; - } - } - - /* inside tag */ - else - { - if ((tag = strfind(parser->off, rem, "%>", 2)) != NULL) - { - template_code(parser, tag); - parser->off = tag + 2; - parser->in_expr = 0; - } - else - { - /* unexpected EOF */ - template_code(parser, parser->mmap + parser->size); - - *sz = 1; - return "\033"; - } - } - - return template_format_chunk(parser, sz); -} - -int template_error(lua_State *L, struct template_parser *parser) -{ - const char *err = luaL_checkstring(L, -1); - const char *off = parser->prv_chunk.s; - const char *ptr; - char msg[1024]; - int line = 0; - int chunkline = 0; - - if ((ptr = strfind((char *)err, strlen(err), "]:", 2)) != NULL) - { - chunkline = atoi(ptr + 2) - parser->prv_chunk.line; - - while (*ptr) - { - if (*ptr++ == ' ') - { - err = ptr; - break; - } - } - } - - if (strfind((char *)err, strlen(err), "'char(27)'", 10) != NULL) - { - off = parser->mmap + parser->size; - err = "'%>' expected before end of file"; - chunkline = 0; - } - - for (ptr = parser->mmap; ptr < off; ptr++) - if (*ptr == '\n') - line++; - - snprintf(msg, sizeof(msg), "Syntax error in %s:%d: %s", - parser->file, line + chunkline, err ? err : "(unknown error)"); - - lua_pushnil(L); - lua_pushinteger(L, line + chunkline); - lua_pushstring(L, msg); - - return 3; -} diff --git a/libs/web/src/template_parser.h b/libs/web/src/template_parser.h deleted file mode 100644 index d1c606272e..0000000000 --- a/libs/web/src/template_parser.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * LuCI Template - Parser header - * - * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _TEMPLATE_PARSER_H_ -#define _TEMPLATE_PARSER_H_ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> - - -/* code types */ -#define T_TYPE_INIT 0 -#define T_TYPE_TEXT 1 -#define T_TYPE_COMMENT 2 -#define T_TYPE_EXPR 3 -#define T_TYPE_INCLUDE 4 -#define T_TYPE_I18N 5 -#define T_TYPE_I18N_RAW 6 -#define T_TYPE_CODE 7 -#define T_TYPE_EOF 8 - - -struct template_chunk { - const char *s; - const char *e; - int type; - int line; -}; - -/* parser state */ -struct template_parser { - int fd; - uint32_t size; - char *mmap; - char *off; - char *gc; - int line; - int in_expr; - int strip_before; - int strip_after; - struct template_chunk prv_chunk; - struct template_chunk cur_chunk; - const char *file; -}; - -struct template_parser * template_open(const char *file); -void template_close(struct template_parser *parser); - -const char *template_reader(lua_State *L, void *ud, size_t *sz); -int template_error(lua_State *L, struct template_parser *parser); - -#endif diff --git a/libs/web/src/template_utils.c b/libs/web/src/template_utils.c deleted file mode 100644 index 80542bd4f3..0000000000 --- a/libs/web/src/template_utils.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * LuCI Template - Utility functions - * - * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "template_utils.h" -#include "template_lmo.h" - -/* initialize a buffer object */ -struct template_buffer * buf_init(int size) -{ - struct template_buffer *buf; - - if (size <= 0) - size = 1024; - - buf = (struct template_buffer *)malloc(sizeof(struct template_buffer)); - - if (buf != NULL) - { - buf->fill = 0; - buf->size = size; - buf->data = malloc(buf->size); - - if (buf->data != NULL) - { - buf->dptr = buf->data; - buf->data[0] = 0; - - return buf; - } - - free(buf); - } - - return NULL; -} - -/* grow buffer */ -int buf_grow(struct template_buffer *buf, int size) -{ - unsigned int off = (buf->dptr - buf->data); - char *data; - - if (size <= 0) - size = 1024; - - data = realloc(buf->data, buf->size + size); - - if (data != NULL) - { - buf->data = data; - buf->dptr = data + off; - buf->size += size; - - return buf->size; - } - - return 0; -} - -/* put one char into buffer object */ -int buf_putchar(struct template_buffer *buf, char c) -{ - if( ((buf->fill + 1) >= buf->size) && !buf_grow(buf, 0) ) - return 0; - - *(buf->dptr++) = c; - *(buf->dptr) = 0; - - buf->fill++; - return 1; -} - -/* append data to buffer */ -int buf_append(struct template_buffer *buf, const char *s, int len) -{ - if ((buf->fill + len + 1) >= buf->size) - { - if (!buf_grow(buf, len + 1)) - return 0; - } - - memcpy(buf->dptr, s, len); - buf->fill += len; - buf->dptr += len; - - *(buf->dptr) = 0; - - return len; -} - -/* read buffer length */ -int buf_length(struct template_buffer *buf) -{ - return buf->fill; -} - -/* destroy buffer object and return pointer to data */ -char * buf_destroy(struct template_buffer *buf) -{ - char *data = buf->data; - - free(buf); - return data; -} - - -/* calculate the number of expected continuation chars */ -static inline int mb_num_chars(unsigned char c) -{ - if ((c & 0xE0) == 0xC0) - return 2; - else if ((c & 0xF0) == 0xE0) - return 3; - else if ((c & 0xF8) == 0xF0) - return 4; - else if ((c & 0xFC) == 0xF8) - return 5; - else if ((c & 0xFE) == 0xFC) - return 6; - - return 1; -} - -/* test whether the given byte is a valid continuation char */ -static inline int mb_is_cont(unsigned char c) -{ - return ((c >= 0x80) && (c <= 0xBF)); -} - -/* test whether the byte sequence at the given pointer with the given - * length is the shortest possible representation of the code point */ -static inline int mb_is_shortest(unsigned char *s, int n) -{ - switch (n) - { - case 2: - /* 1100000x (10xxxxxx) */ - return !(((*s >> 1) == 0x60) && - ((*(s+1) >> 6) == 0x02)); - - case 3: - /* 11100000 100xxxxx (10xxxxxx) */ - return !((*s == 0xE0) && - ((*(s+1) >> 5) == 0x04) && - ((*(s+2) >> 6) == 0x02)); - - case 4: - /* 11110000 1000xxxx (10xxxxxx 10xxxxxx) */ - return !((*s == 0xF0) && - ((*(s+1) >> 4) == 0x08) && - ((*(s+2) >> 6) == 0x02) && - ((*(s+3) >> 6) == 0x02)); - - case 5: - /* 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) */ - return !((*s == 0xF8) && - ((*(s+1) >> 3) == 0x10) && - ((*(s+2) >> 6) == 0x02) && - ((*(s+3) >> 6) == 0x02) && - ((*(s+4) >> 6) == 0x02)); - - case 6: - /* 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) */ - return !((*s == 0xF8) && - ((*(s+1) >> 2) == 0x20) && - ((*(s+2) >> 6) == 0x02) && - ((*(s+3) >> 6) == 0x02) && - ((*(s+4) >> 6) == 0x02) && - ((*(s+5) >> 6) == 0x02)); - } - - return 1; -} - -/* test whether the byte sequence at the given pointer with the given - * length is an UTF-16 surrogate */ -static inline int mb_is_surrogate(unsigned char *s, int n) -{ - return ((n == 3) && (*s == 0xED) && (*(s+1) >= 0xA0) && (*(s+1) <= 0xBF)); -} - -/* test whether the byte sequence at the given pointer with the given - * length is an illegal UTF-8 code point */ -static inline int mb_is_illegal(unsigned char *s, int n) -{ - return ((n == 3) && (*s == 0xEF) && (*(s+1) == 0xBF) && - (*(s+2) >= 0xBE) && (*(s+2) <= 0xBF)); -} - - -/* scan given source string, validate UTF-8 sequence and store result - * in given buffer object */ -static int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf) -{ - unsigned char *ptr = *s; - unsigned int o = 0, v, n; - - /* ascii byte without null */ - if ((*(ptr+0) >= 0x01) && (*(ptr+0) <= 0x7F)) - { - if (!buf_putchar(buf, *ptr++)) - return 0; - - o = 1; - } - - /* multi byte sequence */ - else if ((n = mb_num_chars(*ptr)) > 1) - { - /* count valid chars */ - for (v = 1; (v <= n) && ((o+v) < l) && mb_is_cont(*(ptr+v)); v++); - - switch (n) - { - case 6: - case 5: - /* five and six byte sequences are always invalid */ - if (!buf_putchar(buf, '?')) - return 0; - - break; - - default: - /* if the number of valid continuation bytes matches the - * expected number and if the sequence is legal, copy - * the bytes to the destination buffer */ - if ((v == n) && mb_is_shortest(ptr, n) && - !mb_is_surrogate(ptr, n) && !mb_is_illegal(ptr, n)) - { - /* copy sequence */ - if (!buf_append(buf, (char *)ptr, n)) - return 0; - } - - /* the found sequence is illegal, skip it */ - else - { - /* invalid sequence */ - if (!buf_putchar(buf, '?')) - return 0; - } - - break; - } - - /* advance beyound the last found valid continuation char */ - o = v; - ptr += v; - } - - /* invalid byte (0x00) */ - else - { - if (!buf_putchar(buf, '?')) /* or 0xEF, 0xBF, 0xBD */ - return 0; - - o = 1; - ptr++; - } - - *s = ptr; - return o; -} - -/* sanitize given string and replace all invalid UTF-8 sequences with "?" */ -char * utf8(const char *s, unsigned int l) -{ - struct template_buffer *buf = buf_init(l); - unsigned char *ptr = (unsigned char *)s; - unsigned int v, o; - - if (!buf) - return NULL; - - for (o = 0; o < l; o++) - { - /* ascii char */ - if ((*ptr >= 0x01) && (*ptr <= 0x7F)) - { - if (!buf_putchar(buf, (char)*ptr++)) - break; - } - - /* invalid byte or multi byte sequence */ - else - { - if (!(v = _validate_utf8(&ptr, l - o, buf))) - break; - - o += (v - 1); - } - } - - return buf_destroy(buf); -} - -/* Sanitize given string and strip all invalid XML bytes - * Validate UTF-8 sequences - * Escape XML control chars */ -char * pcdata(const char *s, unsigned int l) -{ - struct template_buffer *buf = buf_init(l); - unsigned char *ptr = (unsigned char *)s; - unsigned int o, v; - char esq[8]; - int esl; - - if (!buf) - return NULL; - - for (o = 0; o < l; o++) - { - /* Invalid XML bytes */ - if (((*ptr >= 0x00) && (*ptr <= 0x08)) || - ((*ptr >= 0x0B) && (*ptr <= 0x0C)) || - ((*ptr >= 0x0E) && (*ptr <= 0x1F)) || - (*ptr == 0x7F)) - { - ptr++; - } - - /* Escapes */ - else if ((*ptr == 0x26) || - (*ptr == 0x27) || - (*ptr == 0x22) || - (*ptr == 0x3C) || - (*ptr == 0x3E)) - { - esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr); - - if (!buf_append(buf, esq, esl)) - break; - - ptr++; - } - - /* ascii char */ - else if (*ptr <= 0x7F) - { - buf_putchar(buf, (char)*ptr++); - } - - /* multi byte sequence */ - else - { - if (!(v = _validate_utf8(&ptr, l - o, buf))) - break; - - o += (v - 1); - } - } - - return buf_destroy(buf); -} - -char * striptags(const char *s, unsigned int l) -{ - struct template_buffer *buf = buf_init(l); - unsigned char *ptr = (unsigned char *)s; - unsigned char *end = ptr + l; - unsigned char *tag; - unsigned char prev; - char esq[8]; - int esl; - - for (prev = ' '; ptr < end; ptr++) - { - if ((*ptr == '<') && ((ptr + 2) < end) && - ((*(ptr + 1) == '/') || isalpha(*(ptr + 1)))) - { - for (tag = ptr; tag < end; tag++) - { - if (*tag == '>') - { - if (!isspace(prev)) - buf_putchar(buf, ' '); - - ptr = tag; - prev = ' '; - break; - } - } - } - else if (isspace(*ptr)) - { - if (!isspace(prev)) - buf_putchar(buf, *ptr); - - prev = *ptr; - } - else - { - switch(*ptr) - { - case '"': - case '\'': - case '<': - case '>': - case '&': - esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr); - buf_append(buf, esq, esl); - break; - - default: - buf_putchar(buf, *ptr); - break; - } - - prev = *ptr; - } - } - - return buf_destroy(buf); -} - -void luastr_escape(struct template_buffer *out, const char *s, unsigned int l, - int escape_xml) -{ - int esl; - char esq[8]; - char *ptr; - - for (ptr = (char *)s; ptr < (s + l); ptr++) - { - switch (*ptr) - { - case '\\': - buf_append(out, "\\\\", 2); - break; - - case '"': - if (escape_xml) - buf_append(out, """, 5); - else - buf_append(out, "\\\"", 2); - break; - - case '\n': - buf_append(out, "\\n", 2); - break; - - case '\'': - case '&': - case '<': - case '>': - if (escape_xml) - { - esl = snprintf(esq, sizeof(esq), "&#%i;", *ptr); - buf_append(out, esq, esl); - break; - } - - default: - buf_putchar(out, *ptr); - } - } -} - -void luastr_translate(struct template_buffer *out, const char *s, unsigned int l, - int escape_xml) -{ - char *tr; - int trlen; - - switch (lmo_translate(s, l, &tr, &trlen)) - { - case 0: - luastr_escape(out, tr, trlen, escape_xml); - break; - - case -1: - luastr_escape(out, s, l, escape_xml); - break; - - default: - /* no catalog loaded */ - break; - } -} diff --git a/libs/web/src/template_utils.h b/libs/web/src/template_utils.h deleted file mode 100644 index c54af757c5..0000000000 --- a/libs/web/src/template_utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * LuCI Template - Utility header - * - * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _TEMPLATE_UTILS_H_ -#define _TEMPLATE_UTILS_H_ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - - -/* buffer object */ -struct template_buffer { - char *data; - char *dptr; - unsigned int size; - unsigned int fill; -}; - -struct template_buffer * buf_init(int size); -int buf_grow(struct template_buffer *buf, int size); -int buf_putchar(struct template_buffer *buf, char c); -int buf_append(struct template_buffer *buf, const char *s, int len); -int buf_length(struct template_buffer *buf); -char * buf_destroy(struct template_buffer *buf); - -char * utf8(const char *s, unsigned int l); -char * pcdata(const char *s, unsigned int l); -char * striptags(const char *s, unsigned int l); - -void luastr_escape(struct template_buffer *out, const char *s, unsigned int l, int escape_xml); -void luastr_translate(struct template_buffer *out, const char *s, unsigned int l, int escape_xml); - -#endif diff --git a/libs/web/standalone.mk b/libs/web/standalone.mk deleted file mode 100644 index 66a0e5a2e7..0000000000 --- a/libs/web/standalone.mk +++ /dev/null @@ -1,56 +0,0 @@ -LUAC = luac -LUAC_OPTIONS = -s -LUA_TARGET ?= source - -LUA_MODULEDIR = /usr/local/share/lua/5.1 -LUA_LIBRARYDIR = /usr/local/lib/lua/5.1 - -OS ?= $(shell uname) - -LUA_SHLIBS = $(shell pkg-config --silence-errors --libs lua5.1 || pkg-config --silence-errors --libs lua-5.1 || pkg-config --silence-errors --libs lua) -LUA_LIBS = $(if $(LUA_SHLIBS),$(LUA_SHLIBS),$(firstword $(wildcard /usr/lib/liblua.a /usr/local/lib/liblua.a /opt/local/lib/liblua.a))) -LUA_CFLAGS = $(shell pkg-config --silence-errors --cflags lua5.1 || pkg-config --silence-errors --cflags lua-5.1 || pkg-config --silence-errors --cflags lua) - -CC = gcc -AR = ar -RANLIB = ranlib -CFLAGS = -O2 -FPIC = -fPIC -EXTRA_CFLAGS = --std=gnu99 -WFLAGS = -Wall -Werror -pedantic -CPPFLAGS = -COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $(WFLAGS) -ifeq ($(OS),Darwin) - SHLIB_FLAGS = -bundle -undefined dynamic_lookup -else - SHLIB_FLAGS = -shared -endif -LINK = $(CC) $(LDFLAGS) - -.PHONY: all build compile luacompile luasource clean luaclean - -all: build - -build: luabuild gccbuild - -luabuild: lua$(LUA_TARGET) - -gccbuild: compile -compile: - -clean: luaclean - -luasource: - mkdir -p dist$(LUA_MODULEDIR) - cp -pR root/* dist 2>/dev/null || true - cp -pR lua/* dist$(LUA_MODULEDIR) 2>/dev/null || true - for i in $$(find dist -name .svn); do rm -rf $$i || true; done - -luastrip: luasource - for i in $$(find dist -type f -name '*.lua'); do perl -e 'undef $$/; open( F, "< $$ARGV[0]" ) || die $$!; $$src = <F>; close F; $$src =~ s/--\[\[.*?\]\](--)?//gs; $$src =~ s/^\s*--.*?\n//gm; open( F, "> $$ARGV[0]" ) || die $$!; print F $$src; close F' $$i; done - -luacompile: luasource - for i in $$(find dist -name *.lua -not -name debug.lua); do $(LUAC) $(LUAC_OPTIONS) -o $$i $$i; done - -luaclean: - rm -rf dist |