diff --git a/1_1.mi_Lua/Posix.lua b/1_1.mi_Lua/Posix.lua new file mode 100644 index 0000000..7536a2a --- /dev/null +++ b/1_1.mi_Lua/Posix.lua @@ -0,0 +1,113 @@ +local base = _G +local string = require("string") +local M = require "posix" + +function M.timeradd (x,y) + local sec, usec = 0, 0 + if x.sec then sec = sec + x.sec end + if y.sec then sec = sec + y.sec end + if x.usec then usec = usec + x.usec end + if y.usec then usec = usec + y.usec end + if usec > 1000000 then + sec = sec + 1 + usec = usec - 1000000 + end + + return { sec = sec, usec = usec } +end + + +function M.timercmp (x, y) + local x = { sec = x.sec or 0, usec = x.usec or 0 } + local y = { sec = y.sec or 0, usec = y.usec or 0 } + if x.sec ~= y.sec then + return x.sec - y.sec + else + return x.usec - y.usec + end +end + + +function M.timersub (x,y) + local sec, usec = 0, 0 + if x.sec then sec = x.sec end + if y.sec then sec = sec - y.sec end + if x.usec then usec = x.usec end + if y.usec then usec = usec - y.usec end + if usec < 0 then + sec = sec - 1 + usec = usec + 1000000 + end + + return { sec = sec, usec = usec } +end + +function M.timesleep (x) + local sec, nsec = 0, 0 + y = M.gettimeofday(); + if( M.timercmp(x, y) > 0 ) then + sec = x.sec - y.sec + nsec = (x.usec - y.usec) * 1000 + if nsec < 0 then + sec = sec - 1 + nsec = nsec + 1000000000 + end + M.nanosleep(sec, nsec) + end +end + +function M.strsplit(str, delim, maxNb) + -- Eliminate bad cases... + if string.find(str, delim) == nil then + return { str } + end + if maxNb == nil or maxNb < 1 then + maxNb = 0 -- No limit + end + local result = {} + local pat = "(.-)" .. delim .. "()" + local nb = 0 + local lastPos + for part, pos in string.gfind(str, pat) do + nb = nb + 1 + result[nb] = part + lastPos = pos + if nb == maxNb then break end + end + -- Handle the last field + if nb ~= maxNb then + result[nb + 1] = string.sub(str, lastPos) + end + return result +end + +function M.var_dump(data, max_level, prefix) + if type(prefix) ~= "string" then + prefix = "" + end + if type(data) ~= "table" then + print(prefix .. tostring(data)) + else + print(data) + if max_level ~= 0 then + local prefix_next = prefix .. " " + print(prefix .. "{") + for k,v in pairs(data) do + io.stdout:write(prefix_next .. k .. " = ") + if type(v) ~= "table" or (type(max_level) == "number" and max_level <= 1) then + print(v) + else + if max_level == nil then + M.var_dump(v, nil, prefix_next) + else + M.var_dump(v, max_level - 1, prefix_next) + end + end + end + print(prefix .. "}") + end + end +end + + +return M diff --git a/1_1.mi_Lua/bit.lua b/1_1.mi_Lua/bit.lua new file mode 100644 index 0000000..cdfecb1 --- /dev/null +++ b/1_1.mi_Lua/bit.lua @@ -0,0 +1,15 @@ +--[[ +nixio - Linux I/O library for lua + +Copyright 2009 Steven Barth + +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$ +]]-- + +return require "nixio".bit \ No newline at end of file diff --git a/1_1.mi_Lua/cjson.so b/1_1.mi_Lua/cjson.so new file mode 100644 index 0000000..723d8a2 Binary files /dev/null and b/1_1.mi_Lua/cjson.so differ diff --git a/1_1.mi_Lua/iproute.so b/1_1.mi_Lua/iproute.so new file mode 100644 index 0000000..43b0c9b Binary files /dev/null and b/1_1.mi_Lua/iproute.so differ diff --git a/1_1.mi_Lua/iwinfo.so b/1_1.mi_Lua/iwinfo.so new file mode 100644 index 0000000..71befa1 Binary files /dev/null and b/1_1.mi_Lua/iwinfo.so differ diff --git a/1_1.mi_Lua/json.lua b/1_1.mi_Lua/json.lua new file mode 100644 index 0000000..0e61274 --- /dev/null +++ b/1_1.mi_Lua/json.lua @@ -0,0 +1,376 @@ +----------------------------------------------------------------------------- +-- JSON4Lua: JSON encoding / decoding support for the Lua language. +-- json Module. +-- Author: Craig Mason-Jones +-- Homepage: http://json.luaforge.net/ +-- Version: 0.9.40 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +-- USAGE: +-- This module exposes two functions: +-- encode(o) +-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string. +-- decode(json_string) +-- Returns a Lua object populated with the data encoded in the JSON string json_string. +-- +-- REQUIREMENTS: +-- compat-5.1 if using Lua 5.0 +-- +-- CHANGELOG +-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix). +-- Fixed Lua 5.1 compatibility issues. +-- Introduced json.null to have null values in associative arrays. +-- encode() performance improvement (more than 50%) through table.concat rather than .. +-- Introduced decode ability to ignore /**/ comments in the JSON string. +-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays. +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Imports and dependencies +----------------------------------------------------------------------------- +local math = require('math') +local string = require("string") +local table = require("table") + +local base = _G + +----------------------------------------------------------------------------- +-- Module declaration +----------------------------------------------------------------------------- +module("json") + +-- Public functions + +-- Private functions +local decode_scanArray +local decode_scanComment +local decode_scanConstant +local decode_scanNumber +local decode_scanObject +local decode_scanString +local decode_scanWhitespace +local encodeString +local isArray +local isEncodable + +----------------------------------------------------------------------------- +-- PUBLIC FUNCTIONS +----------------------------------------------------------------------------- +--- Encodes an arbitrary Lua object / variable. +-- @param v The Lua object / variable to be JSON encoded. +-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode) +function encode (v) + -- Handle nil values + if v==nil then + return "null" + end + + local vtype = base.type(v) + + -- Handle strings + if vtype=='string' then + return '"' .. encodeString(v) .. '"' -- Need to handle encoding in string + end + + -- Handle booleans + if vtype=='number' or vtype=='boolean' then + return base.tostring(v) + end + + -- Handle tables + if vtype=='table' then + local rval = {} + -- Consider arrays separately + local bArray, maxCount = isArray(v) + if bArray then + for i = 1,maxCount do + table.insert(rval, encode(v[i])) + end + else -- An object, not an array + for i,j in base.pairs(v) do + if isEncodable(i) and isEncodable(j) then + table.insert(rval, '"' .. encodeString(i) .. '":' .. encode(j)) + end + end + end + if bArray then + return '[' .. table.concat(rval,',') ..']' + else + return '{' .. table.concat(rval,',') .. '}' + end + end + + -- Handle null values + if vtype=='function' and v==null then + return 'null' + end + + base.assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. base.tostring(v)) +end + + +--- Decodes a JSON string and returns the decoded value as a Lua data structure / value. +-- @param s The string to scan. +-- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1. +-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil, +-- and the position of the first character after +-- the scanned JSON object. +function decode(s, startPos) + startPos = startPos and startPos or 1 + startPos = decode_scanWhitespace(s,startPos) + base.assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']') + local curChar = string.sub(s,startPos,startPos) + -- Object + if curChar=='{' then + return decode_scanObject(s,startPos) + end + -- Array + if curChar=='[' then + return decode_scanArray(s,startPos) + end + -- Number + if string.find("+-0123456789.e", curChar, 1, true) then + return decode_scanNumber(s,startPos) + end + -- String + if curChar==[["]] or curChar==[[']] then + return decode_scanString(s,startPos) + end + if string.sub(s,startPos,startPos+1)=='/*' then + return decode(s, decode_scanComment(s,startPos)) + end + -- Otherwise, it must be a constant + return decode_scanConstant(s,startPos) +end + +--- The null function allows one to specify a null value in an associative array (which is otherwise +-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null } +function null() + return null -- so json.null() will also return null ;-) +end +----------------------------------------------------------------------------- +-- Internal, PRIVATE functions. +-- Following a Python-like convention, I have prefixed all these 'PRIVATE' +-- functions with an underscore. +----------------------------------------------------------------------------- + +--- Scans an array from JSON into a Lua object +-- startPos begins at the start of the array. +-- Returns the array and the next starting position +-- @param s The string being scanned. +-- @param startPos The starting position for the scan. +-- @return table, int The scanned array as a table, and the position of the next character to scan. +function decode_scanArray(s,startPos) + local array = {} -- The return value + local stringLen = string.len(s) + base.assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s ) + startPos = startPos + 1 + -- Infinite loop for array elements + repeat + startPos = decode_scanWhitespace(s,startPos) + base.assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.') + local curChar = string.sub(s,startPos,startPos) + if (curChar==']') then + return array, startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + base.assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.') + object, startPos = decode(s,startPos) + table.insert(array,object) + until false +end + +--- Scans a comment and discards the comment. +-- Returns the position of the next character following the comment. +-- @param string s The JSON string to scan. +-- @param int startPos The starting position of the comment +function decode_scanComment(s, startPos) + base.assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos) + local endPos = string.find(s,'*/',startPos+2) + base.assert(endPos~=nil, "Unterminated comment in string at " .. startPos) + return endPos+2 +end + +--- Scans for given constants: true, false or null +-- Returns the appropriate Lua type, and the position of the next character to read. +-- @param s The string being scanned. +-- @param startPos The position in the string at which to start scanning. +-- @return object, int The object (true, false or nil) and the position at which the next character should be +-- scanned. +function decode_scanConstant(s, startPos) + local consts = { ["true"] = true, ["false"] = false, ["null"] = nil } + local constNames = {"true","false","null"} + + for i,k in base.pairs(constNames) do + --print ("[" .. string.sub(s,startPos, startPos + string.len(k) -1) .."]", k) + if string.sub(s,startPos, startPos + string.len(k) -1 )==k then + return consts[k], startPos + string.len(k) + end + end + base.assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos) +end + +--- Scans a number from the JSON encoded string. +-- (in fact, also is able to scan numeric +- eqns, which is not +-- in the JSON spec.) +-- Returns the number, and the position of the next character +-- after the number. +-- @param s The string being scanned. +-- @param startPos The position at which to start scanning. +-- @return number, int The extracted number and the position of the next character to scan. +function decode_scanNumber(s,startPos) + local endPos = startPos+1 + local stringLen = string.len(s) + local acceptableChars = "+-0123456789.e" + while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true) + and endPos<=stringLen + ) do + endPos = endPos + 1 + end + local stringValue = 'return ' .. string.sub(s,startPos, endPos-1) + local stringEval = base.loadstring(stringValue) + base.assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos) + return stringEval(), endPos +end + +--- Scans a JSON object into a Lua object. +-- startPos begins at the start of the object. +-- Returns the object and the next starting position. +-- @param s The string being scanned. +-- @param startPos The starting position of the scan. +-- @return table, int The scanned object as a table and the position of the next character to scan. +function decode_scanObject(s,startPos) + local object = {} + local stringLen = string.len(s) + local key, value + base.assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s) + startPos = startPos + 1 + repeat + startPos = decode_scanWhitespace(s,startPos) + base.assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.') + local curChar = string.sub(s,startPos,startPos) + if (curChar=='}') then + return object,startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + base.assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.') + -- Scan the key + key, startPos = decode(s,startPos) + base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + startPos = decode_scanWhitespace(s,startPos) + base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + base.assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos) + startPos = decode_scanWhitespace(s,startPos+1) + base.assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + value, startPos = decode(s,startPos) + object[key]=value + until false -- infinite loop while key-value pairs are found +end + +--- Scans a JSON string from the opening inverted comma or single quote to the +-- end of the string. +-- Returns the string extracted as a Lua string, +-- and the position of the next non-string character +-- (after the closing inverted comma or single quote). +-- @param s The string being scanned. +-- @param startPos The starting position of the scan. +-- @return string, int The extracted string as a Lua string, and the next character to parse. +function decode_scanString(s,startPos) + base.assert(startPos, 'decode_scanString(..) called without start position') + local startChar = string.sub(s,startPos,startPos) + base.assert(startChar==[[']] or startChar==[["]],'decode_scanString called for a non-string') + local escaped = false + local endPos = startPos + 1 + local bEnded = false + local stringLen = string.len(s) + repeat + local curChar = string.sub(s,endPos,endPos) + -- Character escaping is only used to escape the string delimiters + if not escaped then + if curChar==[[\]] then + escaped = true + else + bEnded = curChar==startChar + end + else + -- If we're escaped, we accept the current character come what may + escaped = false + end + endPos = endPos + 1 + base.assert(endPos <= stringLen+1, "String decoding failed: unterminated string at position " .. endPos) + until bEnded + local stringValue = 'return ' .. string.sub(s, startPos, endPos-1) + local stringEval = base.loadstring(stringValue) + base.assert(stringEval, 'Failed to load string [ ' .. stringValue .. '] in JSON4Lua.decode_scanString at position ' .. startPos .. ' : ' .. endPos) + return stringEval(), endPos +end + +--- Scans a JSON string skipping all whitespace from the current start position. +-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached. +-- @param s The string being scanned +-- @param startPos The starting position where we should begin removing whitespace. +-- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string +-- was reached. +function decode_scanWhitespace(s,startPos) + local whitespace=" \n\r\t" + local stringLen = string.len(s) + while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do + startPos = startPos + 1 + end + return startPos +end + +--- Encodes a string to be JSON-compatible. +-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-) +-- @param s The string to return as a JSON encoded (i.e. backquoted string) +-- @return The string appropriately escaped. +function encodeString(s) + s = string.gsub(s,'\\','\\\\') + s = string.gsub(s,'"','\\"') + s = string.gsub(s,"'","\\'") + s = string.gsub(s,'\n','\\n') + s = string.gsub(s,'\t','\\t') + return s +end + +-- Determines whether the given Lua type is an array or a table / dictionary. +-- We consider any table an array if it has indexes 1..n for its n items, and no +-- other data in the table. +-- I think this method is currently a little 'flaky', but can't think of a good way around it yet... +-- @param t The table to evaluate as an array +-- @return boolean, number True if the table can be represented as an array, false otherwise. If true, +-- the second returned value is the maximum +-- number of indexed elements in the array. +function isArray(t) + -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable + -- (with the possible exception of 'n') + local maxIndex = 0 + for k,v in base.pairs(t) do + if (base.type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair + if (not isEncodable(v)) then return false end -- All array elements must be encodable + maxIndex = math.max(maxIndex,k) + else + if (k=='n') then + if v ~= table.getn(t) then return false end -- False if n does not hold the number of elements + else -- Else of (k=='n') + if isEncodable(v) then return false end + end -- End of (k~='n') + end -- End of k,v not an indexed pair + end -- End of loop across all pairs + return true, maxIndex +end + +--- Determines whether the given Lua object / table / variable can be JSON encoded. The only +-- types that are JSON encodable are: string, boolean, number, nil, table and json.null. +-- In this implementation, all other types are ignored. +-- @param o The object to examine. +-- @return boolean True if the object should be JSON encoded, false if it should be ignored. +function isEncodable(o) + local t = base.type(o) + return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null) +end diff --git a/1_1.mi_Lua/logging.lua b/1_1.mi_Lua/logging.lua new file mode 100644 index 0000000..f1f7062 --- /dev/null +++ b/1_1.mi_Lua/logging.lua @@ -0,0 +1,201 @@ +------------------------------------------------------------------------------- +-- includes a new tostring function that handles tables recursively +-- +-- @author Danilo Tuler (tuler@ideais.com.br) +-- @author Andre Carregal (info@keplerproject.org) +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +------------------------------------------------------------------------------- + +local type, table, string, _tostring, tonumber = type, table, string, tostring, tonumber +local select = select +local error = error +local format = string.format +local pairs = pairs +local ipairs = ipairs + +local logging = { + +-- Meta information +_COPYRIGHT = "Copyright (C) 2004-2013 Kepler Project", +_DESCRIPTION = "A simple API to use logging features in Lua", +_VERSION = "LuaLogging 1.3.0", + +-- The DEBUG Level designates fine-grained instring.formational events that are most +-- useful to debug an application +DEBUG = "DEBUG", + +-- The INFO level designates instring.formational messages that highlight the +-- progress of the application at coarse-grained level +INFO = "INFO", + +-- The WARN level designates potentially harmful situations +WARN = "WARN", + +-- The ERROR level designates error events that might still allow the +-- application to continue running +ERROR = "ERROR", + +-- The FATAL level designates very severe error events that will presumably +-- lead the application to abort +FATAL = "FATAL", +} + +local LEVEL = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL"} +local MAX_LEVELS = #LEVEL +-- make level names to order +for i=1,MAX_LEVELS do + LEVEL[LEVEL[i]] = i +end + +-- private log function, with support for formating a complex log message. +local function LOG_MSG(self, level, fmt, ...) + local f_type = type(fmt) + if f_type == 'string' then + if select('#', ...) > 0 then + return self:append(level, format(fmt, ...)) + else + -- only a single string, no formating needed. + return self:append(level, fmt) + end + elseif f_type == 'function' then + -- fmt should be a callable function which returns the message to log + return self:append(level, fmt(...)) + end + -- fmt is not a string and not a function, just call tostring() on it. + return self:append(level, logging.tostring(fmt)) +end + +-- create the proxy functions for each log level. +local LEVEL_FUNCS = {} +for i=1,MAX_LEVELS do + local level = LEVEL[i] + LEVEL_FUNCS[i] = function(self, ...) + -- no level checking needed here, this function will only be called if it's level is active. + return LOG_MSG(self, level, ...) + end +end + +-- do nothing function for disabled levels. +local function disable_level() end + +-- improved assertion function. +local function assert(exp, ...) + -- if exp is true, we are finished so don't do any processing of the parameters + if exp then return exp, ... end + -- assertion failed, raise error + error(format(...), 2) +end + +------------------------------------------------------------------------------- +-- Creates a new logger object +-- @param append Function used by the logger to append a message with a +-- log-level to the log stream. +-- @return Table representing the new logger object. +------------------------------------------------------------------------------- +function logging.new(append) + if type(append) ~= "function" then + return nil, "Appender must be a function." + end + + local logger = {} + logger.append = append + + logger.setLevel = function (self, level) + local order = LEVEL[level] + assert(order, "undefined level `%s'", _tostring(level)) + if self.level then + self:log(logging.WARN, "Logger: changing loglevel from %s to %s", self.level, level) + end + self.level = level + self.level_order = order + -- enable/disable levels + for i=1,MAX_LEVELS do + local name = LEVEL[i]:lower() + if i >= order then + self[name] = LEVEL_FUNCS[i] + else + self[name] = disable_level + end + end + end + + -- generic log function. + logger.log = function (self, level, ...) + local order = LEVEL[level] + assert(order, "undefined level `%s'", _tostring(level)) + if order < self.level_order then + return + end + return LOG_MSG(self, level, ...) + end + + -- initialize log level. + logger:setLevel(logging.DEBUG) + return logger +end + + +------------------------------------------------------------------------------- +-- Prepares the log message +------------------------------------------------------------------------------- +function logging.prepareLogMsg(pattern, dt, level, message) + local logMsg = pattern or "%date %level %message\n" + message = string.gsub(message, "%%", "%%%%") + logMsg = string.gsub(logMsg, "%%date", dt) + logMsg = string.gsub(logMsg, "%%level", level) + logMsg = string.gsub(logMsg, "%%message", message) + return logMsg +end + + +------------------------------------------------------------------------------- +-- Converts a Lua value to a string +-- +-- Converts Table fields in alphabetical order +------------------------------------------------------------------------------- +local function tostring(value) + local str = '' + + if (type(value) ~= 'table') then + if (type(value) == 'string') then + str = string.format("%q", value) + else + str = _tostring(value) + end + else + local auxTable = {} + for key in pairs(value) do + if (tonumber(key) ~= key) then + table.insert(auxTable, key) + else + table.insert(auxTable, tostring(key)) + end + end + table.sort(auxTable) + + str = str..'{' + local separator = "" + local entry = "" + for _, fieldName in ipairs(auxTable) do + if ((tonumber(fieldName)) and (tonumber(fieldName) > 0)) then + entry = tostring(value[tonumber(fieldName)]) + else + entry = fieldName.." = "..tostring(value[fieldName]) + end + str = str..separator..entry + separator = ", " + end + str = str..'}' + end + return str +end +logging.tostring = tostring + +if _VERSION ~= 'Lua 5.2' then + -- still create 'logging' global for Lua versions < 5.2 + _G.logging = logging +end + +return logging diff --git a/1_1.mi_Lua/logging/console.lua b/1_1.mi_Lua/logging/console.lua new file mode 100644 index 0000000..433c4d8 --- /dev/null +++ b/1_1.mi_Lua/logging/console.lua @@ -0,0 +1,20 @@ +------------------------------------------------------------------------------- +-- Prints logging information to console +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +-- +------------------------------------------------------------------------------- + +local logging = require"logging" + +function logging.console(logPattern) + return logging.new( function(self, level, message) + io.stdout:write(logging.prepareLogMsg(logPattern, os.date(), level, message)) + return true + end) +end + +return logging.console + diff --git a/1_1.mi_Lua/logging/email.lua b/1_1.mi_Lua/logging/email.lua new file mode 100644 index 0000000..ae2ee8a --- /dev/null +++ b/1_1.mi_Lua/logging/email.lua @@ -0,0 +1,43 @@ +------------------------------------------------------------------------------- +-- Emails logging information to the given recipient +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +-- +------------------------------------------------------------------------------- + +local logging = require"logging" +local smtp = require"socket.smtp" + +function logging.email(params) + params = params or {} + params.headers = params.headers or {} + + if params.from == nil then + return nil, "'from' parameter is required" + end + if params.rcpt == nil then + return nil, "'rcpt' parameter is required" + end + + return logging.new( function(self, level, message) + local s = logging.prepareLogMsg(params.logPattern, os.date(), level, message) + if params.headers.subject then + params.headers.subject = + logging.prepareLogMsg(params.headers.subject, os.date(), level, message) + end + local msg = { headers = params.headers, body = s } + params.source = smtp.message(msg) + + local r, e = smtp.send(params) + if not r then + return nil, e + end + + return true + end) +end + +return logging.email + diff --git a/1_1.mi_Lua/logging/file.lua b/1_1.mi_Lua/logging/file.lua new file mode 100644 index 0000000..aade0b5 --- /dev/null +++ b/1_1.mi_Lua/logging/file.lua @@ -0,0 +1,49 @@ +------------------------------------------------------------------------------- +-- Saves logging information in a file +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +-- +------------------------------------------------------------------------------- + +local logging = require"logging" + +local lastFileNameDatePattern +local lastFileHandler + +local openFileLogger = function (filename, datePattern) + local filename = string.format(filename, os.date(datePattern)) + if (lastFileNameDatePattern ~= filename) then + local f = io.open(filename, "a") + if (f) then + f:setvbuf ("line") + lastFileNameDatePattern = filename + lastFileHandler = f + return f + else + return nil, string.format("file `%s' could not be opened for writing", filename) + end + else + return lastFileHandler + end +end + +function logging.file(filename, datePattern, logPattern) + if type(filename) ~= "string" then + filename = "lualogging.log" + end + + return logging.new( function(self, level, message) + local f, msg = openFileLogger(filename, datePattern) + if not f then + return nil, msg + end + local s = logging.prepareLogMsg(logPattern, os.date(), level, message) + f:write(s) + return true + end) +end + +return logging.file + diff --git a/1_1.mi_Lua/logging/rolling_file.lua b/1_1.mi_Lua/logging/rolling_file.lua new file mode 100644 index 0000000..3095671 --- /dev/null +++ b/1_1.mi_Lua/logging/rolling_file.lua @@ -0,0 +1,79 @@ +--------------------------------------------------------------------------- +-- RollingFileAppender is a FileAppender that rolls over the logfile +-- once it has reached a certain size limit. It also mantains a +-- maximum number of log files. +-- +-- @author Tiago Cesar Katcipis (tiagokatcipis@gmail.com) +-- +-- @copyright 2004-2013 Kepler Project +--------------------------------------------------------------------------- + +local logging = require"logging" + +local function openFile(self) + self.file = io.open(self.filename, "a") + if not self.file then + return nil, string.format("file `%s' could not be opened for writing", self.filename) + end + self.file:setvbuf ("line") + return self.file +end + +local rollOver = function (self) + for i = self.maxIndex - 1, 1, -1 do + -- files may not exist yet, lets ignore the possible errors. + os.rename(self.filename.."."..i, self.filename.."."..i+1) + end + + self.file:close() + self.file = nil + + local _, msg = os.rename(self.filename, self.filename..".".."1") + + if msg then + return nil, string.format("error %s on log rollover", msg) + end + + return openFile(self) +end + + +local openRollingFileLogger = function (self) + if not self.file then + return openFile(self) + end + + local filesize = self.file:seek("end", 0) + + if (filesize < self.maxSize) then + return self.file + end + + return rollOver(self) +end + + +function logging.rolling_file(filename, maxFileSize, maxBackupIndex, logPattern) + if type(filename) ~= "string" then + filename = "lualogging.log" + end + + local obj = { + filename = filename, + maxSize = maxFileSize, + maxIndex = maxBackupIndex or 1 + } + + return logging.new( function(self, level, message) + local f, msg = openRollingFileLogger(obj) + if not f then + return nil, msg + end + local s = logging.prepareLogMsg(logPattern, os.date(), level, message) + f:write(s) + return true + end) +end + +return logging.rolling_file + diff --git a/1_1.mi_Lua/logging/socket.lua b/1_1.mi_Lua/logging/socket.lua new file mode 100644 index 0000000..74b01d7 --- /dev/null +++ b/1_1.mi_Lua/logging/socket.lua @@ -0,0 +1,33 @@ +------------------------------------------------------------------------------- +-- Sends the logging information through a socket using luasocket +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +-- +------------------------------------------------------------------------------- + +local logging = require"logging" +local socket = require"socket" + +function logging.socket(address, port, logPattern) + return logging.new( function(self, level, message) + local s = logging.prepareLogMsg(logPattern, os.date(), level, message) + + local socket, err = socket.connect(address, port) + if not socket then + return nil, err + end + + local cond, err = socket:send(s) + if not cond then + return nil, err + end + socket:close() + + return true + end) +end + +return logging.socket + diff --git a/1_1.mi_Lua/logging/sql.lua b/1_1.mi_Lua/logging/sql.lua new file mode 100644 index 0000000..e78ac9f --- /dev/null +++ b/1_1.mi_Lua/logging/sql.lua @@ -0,0 +1,62 @@ +------------------------------------------------------------------------------- +-- Saves the logging information in a table using luasql +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2013 Kepler Project +-- +------------------------------------------------------------------------------- + +local logging = require"logging" + +function logging.sql(params) + params = params or {} + params.tablename = params.tablename or "LogTable" + params.logdatefield = params.logdatefield or "LogDate" + params.loglevelfield = params.loglevelfield or "LogLevel" + params.logmessagefield = params.logmessagefield or "LogMessage" + + if params.connectionfactory == nil or type(params.connectionfactory) ~= "function" then + return nil, "No specified connection factory function" + end + + local con, err + if params.keepalive then + con, err = params.connectionfactory() + end + + return logging.new( function(self, level, message) + if (not params.keepalive) or (con == nil) then + con, err = params.connectionfactory() + if not con then + return nil, err + end + end + + local logDate = os.date("%Y-%m-%d %H:%M:%S") + local insert = string.format("INSERT INTO %s (%s, %s, %s) VALUES ('%s', '%s', '%s')", + params.tablename, params.logdatefield, params.loglevelfield, + params.logmessagefield, logDate, level, string.gsub(message, "'", "''")) + + local ret, err = pcall(con.execute, con, insert) + if not ret then + con, err = params.connectionfactory() + if not con then + return nil, err + end + ret, err = con:execute(insert) + if not ret then + return nil, err + end + end + + if not params.keepalive then + con:close() + end + + return true + end) +end + +return logging.sql + diff --git a/1_1.mi_Lua/lsqlite3.so b/1_1.mi_Lua/lsqlite3.so new file mode 100644 index 0000000..2482a8c Binary files /dev/null and b/1_1.mi_Lua/lsqlite3.so differ diff --git a/1_1.mi_Lua/ltn12.lua b/1_1.mi_Lua/ltn12.lua new file mode 100644 index 0000000..b42689a --- /dev/null +++ b/1_1.mi_Lua/ltn12.lua @@ -0,0 +1,292 @@ +----------------------------------------------------------------------------- +-- LTN12 - Filters, sources, sinks and pumps. +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local table = require("table") +local base = _G +module("ltn12") + +filter = {} +source = {} +sink = {} +pump = {} + +-- 2048 seems to be better in windows... +BLOCKSIZE = 2048 +_VERSION = "LTN12 1.0.1" + +----------------------------------------------------------------------------- +-- Filter stuff +----------------------------------------------------------------------------- +-- returns a high level filter that cycles a low-level 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 + +-- chains a bunch of filters together +-- (thanks to Wim Couwenberg) +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 +----------------------------------------------------------------------------- +-- create an empty source +local function empty() + return nil +end + +function source.empty() + return empty +end + +-- returns a source that just outputs an error +function source.error(err) + return function() + return nil, err + end +end + +-- creates a file 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 + +-- turns a fancy source into a simple 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 + +-- creates string 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 +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 + table.insert(t, chunk) + end + end +end + +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 + +-- creates a source that produces contents of several sources, one after the +-- other, as if they were concatenated +-- (thanks to Wim Couwenberg) +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 +----------------------------------------------------------------------------- +-- creates a sink that stores into a table +function sink.table(t) + t = t or {} + local f = function(chunk, err) + if chunk then table.insert(t, chunk) end + return 1 + end + return f, t +end + +-- turns a fancy sink into a simple 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 + +-- creates a file 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 + +function sink.null() + return null +end + +-- creates a sink that just returns an error +function sink.error(err) + return function() + return nil, err + end +end + +-- chains a sink with a filter +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 +----------------------------------------------------------------------------- +-- pumps one chunk from the source to the sink +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 + +-- pumps all data from a source to a sink, using a step function +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/1_1.mi_Lua/luci/cacheloader.lua b/1_1.mi_Lua/luci/cacheloader.lua new file mode 100644 index 0000000..942c4b7 --- /dev/null +++ b/1_1.mi_Lua/luci/cacheloader.lua @@ -0,0 +1,23 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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/1_1.mi_Lua/luci/cbi.lua b/1_1.mi_Lua/luci/cbi.lua new file mode 100644 index 0000000..c84d3a0 --- /dev/null +++ b/1_1.mi_Lua/luci/cbi.lua @@ -0,0 +1,1850 @@ +--[[ +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: cbi.lua 9558 2012-12-18 13:58:22Z jow $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/cbi/datatypes.lua b/1_1.mi_Lua/luci/cbi/datatypes.lua new file mode 100644 index 0000000..ce031d0 --- /dev/null +++ b/1_1.mi_Lua/luci/cbi/datatypes.lua @@ -0,0 +1,345 @@ +--[[ + +LuCI - Configuration Bind Interface - Datatype Tests +(c) 2010 Jo-Philipp Wich + +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: datatypes.lua 9352 2012-10-06 23:50:52Z jow $ + +]]-- + +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/1_1.mi_Lua/luci/ccache.lua b/1_1.mi_Lua/luci/ccache.lua new file mode 100644 index 0000000..56ccbc3 --- /dev/null +++ b/1_1.mi_Lua/luci/ccache.lua @@ -0,0 +1,87 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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/1_1.mi_Lua/luci/config.lua b/1_1.mi_Lua/luci/config.lua new file mode 100644 index 0000000..bc3d533 --- /dev/null +++ b/1_1.mi_Lua/luci/config.lua @@ -0,0 +1,42 @@ +--[[ +LuCI - Configuration + +Description: +Some LuCI configuration values read from uci file "luci" + + +FileId: +$Id: config.lua 3856 2008-12-05 15:36:44Z Cyrus $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/controller/api/index.lua b/1_1.mi_Lua/luci/controller/api/index.lua new file mode 100644 index 0000000..8b39426 --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/index.lua @@ -0,0 +1,10 @@ +module("luci.controller.api.index", package.seeall) +function index() + local page = node("api") + page.target = firstchild() + page.title = _("") + page.order = 10 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true +end diff --git a/1_1.mi_Lua/luci/controller/api/xqdatacenter.lua b/1_1.mi_Lua/luci/controller/api/xqdatacenter.lua new file mode 100644 index 0000000..b4d98b6 --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqdatacenter.lua @@ -0,0 +1,336 @@ +module("luci.controller.api.xqdatacenter", package.seeall) + +function index() + local page = node("api","xqdatacenter") + page.target = firstchild() + page.title = ("") + page.order = 300 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqdatacenter"}, firstchild(), _(""), 300) + entry({"api", "xqdatacenter", "request"}, call("tunnelRequest"), _(""), 301) + entry({"api", "xqdatacenter", "identify_device"}, call("identifyDevice"), _(""), 302, 0x08) + entry({"api", "xqdatacenter", "download"}, call("download"), _(""), 303) + entry({"api", "xqdatacenter", "upload"}, call("upload"), _(""), 304) + entry({"api", "xqdatacenter", "thumb"}, call("getThumb"), _(""), 305) + entry({"api", "xqdatacenter", "device_id"}, call("getDeviceId"), _(""), 306) + entry({"api", "xqdatacenter", "check_file_exist"}, call("checkFileExist"), _(""), 307) + entry({"api", "xqdatacenter", "plugin_ssh"}, call("pluginSSH"), _(""), 308) + entry({"api", "xqdatacenter", "plugin_ssh_status"}, call("pluginSSHStatus"), _(""), 309) +end + +local LuciHttp = require("luci.http") +local LuciJson = require("json") +local XQConfigs = require("xiaoqiang.common.XQConfigs") +local XQFunction = require("xiaoqiang.common.XQFunction") +local XQErrorUtil = require("xiaoqiang.util.XQErrorUtil") + +function tunnelRequest() + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = XQCryptoUtil.binaryBase64Enc(LuciHttp.formvalue("payload")) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_DATACENTER % payload + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function identifyDevice() + local cmd = XQConfigs.THRIFT_TO_MQTT_IDENTIFY_DEVICE + local LuciUtil = require("luci.util") + local result = {} + result["code"] = 0 + result["info"] = LuciUtil.exec(cmd) + LuciHttp.write_json(result) +end + +function getDeviceId() + local cmd = XQConfigs.THRIFT_TO_MQTT_GET_DEVICEID + local LuciUtil = require("luci.util") + local result = {} + result["code"] = 0 + result["deviceId"] = LuciUtil.exec(cmd) + LuciHttp.write_json(result) +end + +function download() + local fs = require("nixio.fs") + local mime = require("luci.http.protocol.mime") + local ltn12 = require("luci.ltn12") + local log = require("xiaoqiang.XQLog") + + local path = LuciHttp.formvalue("path") + if XQFunction.isStrNil(path) then + LuciHttp.status(404, _("no Such file")) + return + end + + local constPrefix1 = "/userdisk/data/" + local constPrefix2 = "/extdisks/" + local constPrefix3 = "/userdisk/privacyData/" + if (string.sub(path, 1, string.len(constPrefix1)) ~= constPrefix1) and (string.sub(path, 1, string.len(constPrefix2)) ~= constPrefix2) and (string.sub(path, 1, string.len(constPrefix3)) ~= constPrefix3) then + LuciHttp.status(403, _("no permission")) + return + end + + -- check privacy disk permission by md5 device mac address + --[[if string.sub(path, 1, string.len(constPrefix3)) == constPrefix3 then + local secret = LuciHttp.formvalue("secret") + if XQFunction.isStrNil(secret) then + LuciHttp.status(403, _("no permission")) + return + end + + log.log(3, "=============secret = " .. secret) + + local access = false + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local macfilterInfoList = XQDeviceUtil.getMacfilterInfoList() + for _,value in ipairs(macfilterInfoList) do + if XQFunction.isStrNil(value.mac) == false then + log.log(3, "=============mac = " .. value.mac) + if string.lower(XQCryptoUtil.md5Str(string.lower(value.mac))) == string.lower(secret) then + log.log(3, "=============device found") + if value.pridisk then + access = true + end + break + end + end + end + if access == false then + LuciHttp.status(403, _("no permission")) + return + end + end]] + + log.log(3, "=============path = " .. path) + local stat = fs.stat(path) + if not stat then + LuciHttp.status(404, _("no Such file")) + return + end + + LuciHttp.header("Accept-Ranges", "bytes") + LuciHttp.header("Content-Type", mime.to_mime(path)) + local range = LuciHttp.getenv("HTTP_RANGE") + -- format: bytes=123- + if range then + LuciHttp.status(206) + range = string.gsub(range, "bytes=", "") + range = string.gsub(range, "-", "") + else + range = 0 + end + log.log(3, "=============range = " .. range) + -- format: bytes 123-456/457 + local contentRange = "bytes " .. range .. "-" .. (stat.size - 1) .. "/" .. stat.size + log.log(3, "=============contentRange = " .. contentRange) + LuciHttp.header("Content-Length", stat.size - range) + LuciHttp.header("Content-Range", contentRange) + LuciHttp.header("Content-Disposition", "attachment; filename=" .. fs.basename(path)) + + if string.sub(path, 1, string.len(constPrefix1)) == constPrefix1 then + LuciHttp.header("X-Accel-Redirect", "/download-userdisk/" .. string.sub(path, string.len(constPrefix1) + 1, string.len(path))) + elseif string.sub(path, 1, string.len(constPrefix2)) == constPrefix2 then + LuciHttp.header("X-Accel-Redirect", "/download-extdisks/" .. string.sub(path, string.len(constPrefix2) + 1, string.len(path))) + elseif string.sub(path, 1, string.len(constPrefix3)) == constPrefix3 then + LuciHttp.header("X-Accel-Redirect", "/download-pridisk/" .. string.sub(path, string.len(constPrefix3) + 1, string.len(path))) + end + + --local file = io.open(path, "r") + --local position = file:seek("set", range) + --log.log(3, "=============position = " .. position) + --ltn12.pump.all(ltn12.source.file(file), LuciHttp.write) +end + +function upload() + local fp + local log = require("xiaoqiang.XQLog") + local fs = require("luci.fs") + local tmpfile = "/userdisk/upload.tmp" + if fs.isfile(tmpfile) then + fs.unlink(tmpfile) + end + local filename + LuciHttp.setfilehandler( + function(meta, chunk, eof) + if not fp then + if meta and meta.name == "file" then + fp = io.open(tmpfile, "w") + filename = meta.file + filename = string.gsub(filename, "+", " ") + filename = string.gsub(filename, "%%(%x%x)", + function(h) + return string.char(tonumber(h, 16)) + end) + filename = filename.gsub(filename, "\r\n", "\n") + end + end + if chunk then + fp:write(chunk) + end + if eof then + fp:close() + end + end + ) + + local path = LuciHttp.formvalue("target") + if string.match(path, "\/$") == nil then + path = path .. "/" + end + fs.mkdir(path, true) + + local savename = filename + if fs.isfile(path .. savename) then + local basename = savename + local index = basename:match(".+()%.%w+$") + if index then + basename = basename:sub(1, index - 1) + end + local extension = savename:match(".+%.(%w+)$") + for i = 1, 100, 1 do + local tmpname = basename .. "(" .. i .. ")" + if extension then + tmpname = tmpname .. "." .. extension + end + if not fs.isfile(path .. tmpname) then + savename = tmpname + break + end + end + end + + local dest = path .. savename + log.log(3, "dest=" .. dest) + fs.rename(tmpfile, dest) + + local result = {} + result["code"] = 0 + LuciHttp.write_json(result) +end + +function getThumb() + local LuciUtil = require("luci.util") + local fs = require("nixio.fs") + local mime = require("luci.http.protocol.mime") + local ltn12 = require("luci.ltn12") + local log = require("xiaoqiang.XQLog") + + local realPath = LuciHttp.formvalue("filePath") + log.log(3, "realPath = ", realPath) + if (realPath == nil) then + LuciHttp.status(404, _("no Such file")) + return + end + + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = "{\"api\":10, \"files\":[\"" ..realPath.. "\"]}" + local thumbResponse = XQFunction.thrift_tunnel_to_datacenter(payload) + if thumbResponse and thumbResponse.code == 0 then + local thumbPath = thumbResponse.thumbnails[1] + local stat = fs.stat(thumbPath) + LuciHttp.header("Content-Type", mime.to_mime(thumbPath)) + LuciHttp.header("Content-Length", stat.size) + ltn12.pump.all(ltn12.source.file(io.open(thumbPath, "r")), LuciHttp.write) + else + LuciHttp.status(404, _("no Such thumb file")) + end +end + +function checkFileExist() + local fs = require("nixio.fs") + + local exist = true + local path = LuciHttp.formvalue("filePath") + if XQFunction.isStrNil(path) then + exist = false + else + local stat = fs.stat(path) + if not stat then + exist = false + end + end + + local result = {} + result["code"] = 0 + result['exist'] = exist + LuciHttp.write_json(result) +end + +function pluginSSH() + local LuciUtil = require("luci.util") + local XQLog = require("xiaoqiang.XQLog") + local code = 0 + local result = {} + local pluginID = LuciHttp.formvalue("pluginID") + local capabilitystr = LuciHttp.formvalue("capability") + local open = tonumber(LuciHttp.formvalue("open") or 0) + XQLog.check(0, XQLog.KEY_FUNC_PLUGIN, 1) + if open and open == 1 then + if pluginID and capabilitystr then + local payload = { + ["api"] = 611, + ["pluginID"] = pluginID, + ["capability"] = LuciUtil.split(capabilitystr, ",") + } + local datacenter = XQFunction.thrift_tunnel_to_datacenter(LuciJson.encode(payload)) + if datacenter and datacenter.code ~= 0 then + code = 1595 + end + else + code = 1537 + end + else + local payload = { + ["api"] = 613 + } + local datacenter = XQFunction.thrift_tunnel_to_datacenter(LuciJson.encode(payload)) + if datacenter and datacenter.code == 0 then + code = 0 + else + code = 1601 + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function pluginSSHStatus() + local code = 0 + local result = {} + local datacenter = XQFunction.thrift_tunnel_to_datacenter([[{"api":612}]]) + local capability = XQFunction.thrift_tunnel_to_datacenter([[{"api":621}]]) + if datacenter and datacenter.code == 0 and capability and datacenter.code == 0 then + local capabilitylist = {} + result["enable"] = datacenter.status == 1 and 1 or 0 + local encapability = {} + if result.enable == 1 then + local pluginSSH = datacenter.plugin_ssh_status + result["pluginID"] = pluginSSH.pluginID + encapability = pluginSSH.capability + end + for _, item in ipairs(capability.list) do + item.enable = 0 + for _, capa in ipairs(encapability) do + if item.key == capa then + item.enable = 1 + break + end + end + table.insert(capabilitylist, item) + end + result["capability"] = capabilitylist + else + code = 1600 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end diff --git a/1_1.mi_Lua/luci/controller/api/xqnetdetect.lua b/1_1.mi_Lua/luci/controller/api/xqnetdetect.lua new file mode 100644 index 0000000..a1995fa --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqnetdetect.lua @@ -0,0 +1,293 @@ +module("luci.controller.api.xqnetdetect", package.seeall) + +function index() + local page = node("api","xqnetdetect") + page.target = firstchild() + page.title = ("") + page.order = 350 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqnetdetect"}, firstchild(), _(""), 350) + entry({"api", "xqnetdetect", "wan_status"}, call("getWanStatus"), _(""), 351, 0x01) + entry({"api", "xqnetdetect", "sys_info"}, call("getSysInfo"), (""), 352, 0x01) + entry({"api", "xqnetdetect", "ping_test"}, call("pingTest"), (""), 353, 0x01) + entry({"api", "xqnetdetect", "detect"}, call("systemDiagnostics"), (""), 354, 0x01) + entry({"api", "xqnetdetect", "sys_status"}, call("systemStatus"), (""), 355, 0x01) + entry({"api", "xqnetdetect", "netspeed"}, call("netspeed"), (""), 356) + entry({"api", "xqnetdetect", "uploadspeed"}, call("uploadSpeed"), (""), 357) +end + +local LuciHttp = require("luci.http") +local XQFunction = require("xiaoqiang.common.XQFunction") +local XQErrorUtil = require("xiaoqiang.util.XQErrorUtil") + +function getWanStatus() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = {} + local wanType = XQLanWanUtil.getAutoWanType() + local wanInfo = XQLanWanUtil.getLanWanInfo("wan") + local wanMonitor = XQLanWanUtil.getWanMonitorStat() + result["code"] = 0 + result["wanLink"] = wanType == 99 and 0 or 1 + result["wanType"] = wanType + result["wanInfo"] = wanInfo + result["wanMonitor"] = wanMonitor + LuciHttp.write_json(result) +end + +function getSysInfo() + local LuciSys = require("luci.sys") + local result = {} + local cpu = {} + local mem = {} + local system, model, memtotal, memcached, membuffers, memfree, bogomips = LuciSys.sysinfo() + cpu["info"] = system + mem["total"] = memtotal + mem["free"] = memfree + result["code"] = 0 + result["cpuInfo"] = cpu + result["memInfo"] = mem + LuciHttp.write_json(result) +end + +function pingTest() + local LuciSys = require("luci.sys") + local pingUrl = LuciHttp.formvalue("url") + local ping = LuciSys.net.pingtest(pingUrl) + local result = {} + result["code"] = 0 + result["result"] = ping == 0 and 1 or 0 + LuciHttp.write_json(result) +end + +--[[ + simple : 0/1/2 (正常模式,时间长上传log/简单模式,时间短,不上传log/简单模式,时间短,上传log) +]]-- +function systemDiagnostics() + local XQLog = require("xiaoqiang.XQLog") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + + local lan = XQDeviceUtil.getWanLanNetworkStatistics("lan") + local wan = XQDeviceUtil.getWanLanNetworkStatistics("wan") + local speed = {} + speed["lan"] = tonumber(lan.downspeed) + speed["wan"] = tonumber(wan.downspeed) + + local simple = tonumber(LuciHttp.formvalue("simple") or 0) + local target = LuciHttp.formvalue("target") + local result = {} + local code = 0 + local status = 0 + local count = 0 + local cpuTemperature = XQSysUtil.getCpuTemperature() + local network = XQSysUtil.getNetworkDetectInfo(simple,target) + XQSysUtil.setDetectionTimestamp() + + local wifiInfo = XQWifiUtil.getAllWifiInfo() + local same = false + local strong = true + local wifi = {} + for i=1, #wifiInfo do + if XQSecureUtil.checkPlaintextPwd("admin", wifiInfo[i].password) then + same = true + end + if XQSecureUtil.checkStrong(wifiInfo[i].password) < 2 then + strong = false + end + end + wifi["same"] = same and 1 or 0 + wifi["strong"] = strong and 1 or 0 + + local disk = {} + local diskinfo = XQFunction.thrift_tunnel_to_datacenter([[{"api":26}]]) + if diskinfo and diskinfo.code == 0 then + local capacity = tonumber(diskinfo.capacity) + local free = tonumber(diskinfo.free) + disk["Used"] = string.format("%.3fG", (capacity - free)/1073741824) + disk["Available"] = string.format("%.3fG", free/1073741824) + end + + if network then + local cputemp = {} + cputemp["temperature"] = cpuTemperature + if cpuTemperature > 70 then + count = count + 1 + status = 1 + cputemp["status"] = 0 + else + cputemp["status"] = 1 + end + local cpuavg = {} + cpuavg["loadavg"] = network.cpu + if tonumber(network.cpu) > 90 then + count = count + 1 + status = 1 + cpuavg["status"] = 0 + else + cpuavg["status"] = 1 + end + local memoryuse = {} + memoryuse["use"] = network.memory + if tonumber(network.memory) > 90 then + count = count + 1 + status = 1 + memoryuse["status"] = 0 + else + memoryuse["status"] = 1 + end + local link = {} + if network.wanLink ~= 1 then + count = count + 1 + status = 2 + link["status"] = 0 + else + link["status"] = 1 + end + local wan = {} + wan["type"] = network.wanType + if tonumber(network.wanLink) ~= 1 then + count = count + 1 + status = 2 + wan["status"] = 0 + else + wan["status"] = 1 + end + local gateway = {} + gateway["lost"] = network.gw + if tonumber(network.gw) > 80 then + count = count + 1 + status = 1 + gateway["status"] = 0 + else + gateway["status"] = 1 + end + local dnsstatus = {} + if tonumber(network.dns) ~= 1 then + count = count + 1 + status = 2 + dnsstatus["status"] = 0 + else + dnsstatus["status"] = 1 + end + local ping = {} + ping["lost"] = network.pingLost + if tonumber(network.pingLost) > 80 then + count = count + 1 + status = 2 + ping["status"] = 0 + else + ping["status"] = 1 + end + result = network + result["count"] = count + result["status"] = status + result["cpuavg"] = cpuavg + result["memoryuse"] = memoryuse + result["cputemp"] = cputemp + result["link"] = link + result["wan"] = wan + result["gateway"] = gateway + result["dnsstatus"] = dnsstatus + result["ping"] = ping + result["cpuTemperature"] = cpuTemperature + result["wifi"] = wifi + result["speed"] = speed + result["disk"] = disk + if count > 0 then + XQLog.check(0, XQLog.KEY_DETECT_ERROR, 1) + end + else + code = 1567 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + else + local XQPushHelper = require("xiaoqiang.XQPushHelper") + local LuciJson = require("json") + local payload = { + ["type"] = 6, + ["data"] = { + ["lan"] = speed.lan, + ["wan"] = speed.wan + } + } + XQPushHelper.push_request(LuciJson.encode(payload)) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function systemStatus() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local count = 0 + local result = {} + local status = XQSysUtil.checkSystemStatus() + result["code"] = 0 + result["status"] = 0 + if (status.cpu and status.cpu > 90) then + count = count + 1 + result["status"] = 1 + end + if (status.mem and status.mem > 90) then + count = count + 1 + result["status"] = 1 + end + if (status.tmp and status.tmp > 70) then + count = count + 1 + result["status"] = 1 + end + if not status.wan or not status.link then + count = count + 1 + result["status"] = 2 + end + result["count"] = count + LuciHttp.write_json(result) +end + +function netspeed() + local XQPreference = require("xiaoqiang.XQPreference") + local XQNSTUtil = require("xiaoqiang.module.XQNetworkSpeedTest") + local code = 0 + local result = {} + local history = LuciHttp.formvalue("history") + if history then + result["bandwidth"] = tonumber(XQPreference.get("BANDWIDTH", 0, "xiaoqiang")) + result["download"] = tonumber(string.format("%.2f", 128 * result.bandwidth)) + else + local download = XQNSTUtil.downloadSpeedTest() + if download then + result["download"] = download + result["bandwidth"] = tonumber(string.format("%.2f", 8 * download/1024)) + XQPreference.set("BANDWIDTH", tostring(result.bandwidth), "xiaoqiang") + else + code = 1588 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + end + result["code"] = code + LuciHttp.write_json(result) +end + +function uploadSpeed() + local XQNSTUtil = require("xiaoqiang.module.XQNetworkSpeedTest") + local code = 0 + local result = {} + local upload = XQNSTUtil.uploadSpeedTest() + if upload then + result["upload"] = upload + result["bandwidth"] = tonumber(string.format("%.2f", 8 * upload/1024)) + else + code = 1588 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end \ No newline at end of file diff --git a/1_1.mi_Lua/luci/controller/api/xqnetwork.lua b/1_1.mi_Lua/luci/controller/api/xqnetwork.lua new file mode 100644 index 0000000..4c7555d --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqnetwork.lua @@ -0,0 +1,1310 @@ +module("luci.controller.api.xqnetwork", package.seeall) + +function index() + local page = node("api","xqnetwork") + page.target = firstchild() + page.title = ("") + page.order = 200 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqnetwork"}, firstchild(), (""), 200) + entry({"api", "xqnetwork", "wifi_status"}, call("getWifiStatus"), (""), 201) + entry({"api", "xqnetwork", "wifi_detail"}, call("getWifiInfo"), (""), 202) + entry({"api", "xqnetwork", "wifi_detail_all"}, call("getAllWifiInfo"), (""), 202) + entry({"api", "xqnetwork", "wifi_connect_devices"}, call("getWifiConDev"), (""), 203) + entry({"api", "xqnetwork", "wifi_txpwr_channel"}, call("getWifiChTx"), (""), 204) + -- entry({"api", "xqnetwork", "set_wifi_txpwr_channel"}, call("setWifiChTx"), (""), 205) + entry({"api", "xqnetwork", "set_wifi_txpwr"}, call("setWifiTxpwr"), (""), 205) + entry({"api", "xqnetwork", "wifi_up"}, call("turnOnWifi"), (""), 206) + entry({"api", "xqnetwork", "wifi_down"}, call("shutDownWifi"), (""), 207) + entry({"api", "xqnetwork", "set_wifi"}, call("setWifi"), (""), 208) + --entry({"api", "xqnetwork", "get_scan_list"}, call("get_scan_list"), (""), 209, true) + --entry({"api", "xqnetwork", "wifi_ctl_scan"}, call("wifi_ctl_scan"), (""), 210) + --entry({"api", "xqnetwork", "get_bridge"}, call("get_bridge"), (""), 211, true) + --entry({"api", "xqnetwork", "set_bridge"}, call("set_bridge"), (""), 212) + entry({"api", "xqnetwork", "lan_info"}, call("getLanInfo"), (""), 213) + entry({"api", "xqnetwork", "wan_info"}, call("getWanInfo"), (""), 214) + entry({"api", "xqnetwork", "lan_dhcp"}, call("getLanDhcp"), (""), 215) + entry({"api", "xqnetwork", "wan_down"}, call("wanDown"), (""), 216) + entry({"api", "xqnetwork", "wan_up"}, call("wanUp"), (""), 217) + entry({"api", "xqnetwork", "check_wan_type"}, call("getAutoWanType"), (""), 218, 0x08) + entry({"api", "xqnetwork", "wan_statistics"}, call("getWanStatistics"), (""), 219) + -- + entry({"api", "xqnetwork", "devices_statistics"}, call("getDevsStatistics"), (""), 220) + entry({"api", "xqnetwork", "device_statistics"}, call("getDevStatistics"), (""), 221) + -- + entry({"api", "xqnetwork", "set_lan_ip"}, call("setLanIp"), (""), 222) + entry({"api", "xqnetwork", "set_wan"}, call("setWan"), (""), 223, 0x08) + entry({"api", "xqnetwork", "set_lan_dhcp"}, call("setLanDhcp"), (""), 224) + entry({"api", "xqnetwork", "mac_clone"}, call("setWanMac"), (""), 225) + entry({"api", "xqnetwork", "set_all_wifi"}, call("setAllWifi"), (""), 226) + entry({"api", "xqnetwork", "avaliable_channels"}, call("getChannels"), (""), 227) + -- WiFi macfilter + entry({"api", "xqnetwork", "wifi_macfilter_info"}, call("getWifiMacfilterInfo"), (""), 228) + entry({"api", "xqnetwork", "set_wifi_macfilter"}, call("setWifiMacfilter"), (""), 229) + entry({"api", "xqnetwork", "edit_device"}, call("editDevice"), (""), 230) + -- Mac bind + entry({"api", "xqnetwork", "mac_bind"}, call("macBind"), (""), 231) + entry({"api", "xqnetwork", "mac_unbind"}, call("macUnbind"), (""), 232) + entry({"api", "xqnetwork", "savebind"}, call("saveBind"), (""), 233) + entry({"api", "xqnetwork", "unbindall"}, call("unbindAll"), (""), 234) + entry({"api", "xqnetwork", "macbind_info"}, call("getMacBindInfo"), (""), 235) + -- PPPoE + entry({"api", "xqnetwork", "pppoe_status"}, call("pppoeStatus"), (""), 236) + entry({"api", "xqnetwork", "pppoe_stop"}, call("pppoeStop"), (""), 237) + entry({"api", "xqnetwork", "pppoe_start"}, call("pppoeStart"), (""), 238) + -- QoS + entry({"api", "xqnetwork", "qos_info"}, call("getQosInfo"), (""), 239) + entry({"api", "xqnetwork", "qos_switch"}, call("qosSwitch"), (""), 240) + entry({"api", "xqnetwork", "qos_mode"}, call("qosMode"), (""), 241) + entry({"api", "xqnetwork", "qos_limit"}, call("qosLimit"), (""), 242) + entry({"api", "xqnetwork", "qos_offlimit"}, call("qosOffLimit"), (""), 243) + entry({"api", "xqnetwork", "set_band"}, call("setBand"), (""), 244) + -- NAT + entry({"api", "xqnetwork", "portforward"}, call("portForward"), (""), 245) + entry({"api", "xqnetwork", "add_redirect"}, call("addRedirect"), (""), 246) + entry({"api", "xqnetwork", "add_range_redirect"}, call("addRangeRedirect"), (""), 247) + entry({"api", "xqnetwork", "delete_redirect"}, call("deleteRedirect"), (""), 248) + entry({"api", "xqnetwork", "redirect_apply"}, call("redirectApply"), (""), 249) + -- DMZ + entry({"api", "xqnetwork", "dmz"}, call("getDMZInfo"), (""), 250) + entry({"api", "xqnetwork", "set_dmz"}, call("setDMZ"), (""), 251) + entry({"api", "xqnetwork", "dmz_off"}, call("closeDMZ"), (""), 252) + entry({"api", "xqnetwork", "dmz_reload"}, call("reloadDMZ"), (""), 252) + -- DDNS + entry({"api", "xqnetwork", "ddns"}, call("ddnsStatus"), (""), 253) + entry({"api", "xqnetwork", "ddns_switch"}, call("ddnsSwitch"), (""), 254) + entry({"api", "xqnetwork", "add_server"}, call("addServer"), (""), 255) + entry({"api", "xqnetwork", "del_server"}, call("deleteServer"), (""), 256) + entry({"api", "xqnetwork", "server_switch"}, call("serverSwitch"), (""), 258) + entry({"api", "xqnetwork", "ddns_reload"}, call("ddnsReload"), (""), 259) + entry({"api", "xqnetwork", "ddns_edit"}, call("ddnsEdit"), (""), 260) + entry({"api", "xqnetwork", "get_server"}, call("getServer"), (""), 261) +end + +local LuciHttp = require("luci.http") +local XQErrorUtil = require("xiaoqiang.util.XQErrorUtil") + +function getWifiStatus() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local status = {} + table.insert(status,XQWifiUtil.getWifiStatus(1)) + table.insert(status,XQWifiUtil.getWifiStatus(2)) + result["code"] = 0 + result["status"] = status + LuciHttp.write_json(result) +end + +function getWifiInfo() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local code = 0 + local index = tonumber(LuciHttp.formvalue("wifiIndex")) + if index and index < 3 then + result["info"] = XQWifiUtil.getAllWifiInfo()[index] + else + code = 1523 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function getAllWifiInfo() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local code = 0 + result["info"] = XQWifiUtil.getAllWifiInfo() + result["code"] = code + LuciHttp.write_json(result) +end + +function getWifiConDev() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + result["code"] = 0 + result["list"] = XQWifiUtil.getAllWifiConnetDeviceList() + LuciHttp.write_json(result) +end + +function getWifiChTx() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + result["code"] = 0 + result["list"] = XQWifiUtil.getWifiChannelTxpwrList() + LuciHttp.write_json(result) +end + +function setWifiChTx() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code = 0 + local channel1 = LuciHttp.formvalue("channel1") + local txpwr1 = LuciHttp.formvalue("txpwr1") + local channel2 = LuciHttp.formvalue("channel2") + local txpwr2 = LuciHttp.formvalue("txpwr2") + if XQFunction.isStrNil(channel1) and XQFunction.isStrNil(channel2) and XQFunction.isStrNil(txpwr1) and XQFunction.isStrNil(txpwr2) then + code = 1502 + else + XQWifiUtil.setWifiChannelTxpwr(channel1,txpwr1,channel2,txpwr2) + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + XQFunction.forkRestartWifi() + end +end + +function setWifiTxpwr() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code = 0 + local txpwr = LuciHttp.formvalue("txpwr") + if XQFunction.isStrNil(txpwr) then + code = 1502 + else + XQWifiUtil.setWifiTxpwr(txpwr) + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + XQFunction.forkRestartWifi() + end +end + +function turnOnWifi() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local code = 0 + local index = tonumber(LuciHttp.formvalue("wifiIndex")) + if index and index < 3 then + XQWifiUtil.turnWifiOn(index) + else + code = 1523 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function shutDownWifi() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local code = 0 + local index = tonumber(LuciHttp.formvalue("wifiIndex")) + if index and index < 3 then + XQWifiUtil.turnWifiOff(index) + else + code = 1523 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function setWifi() + local XQLog = require("xiaoqiang.XQLog") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code = 0 + local index = tonumber(LuciHttp.formvalue("wifiIndex")) + local ssid = LuciHttp.formvalue("ssid") + local password = LuciHttp.formvalue("pwd") + local encryption = LuciHttp.formvalue("encryption") + local channel = LuciHttp.formvalue("channel") + local bandwidth = LuciHttp.formvalue("bandwidth") + local txpwr = LuciHttp.formvalue("txpwr") + local hidden = LuciHttp.formvalue("hidden") + local on = LuciHttp.formvalue("on") + if on ~= nil then + on = tonumber(on) + end + if channel == "0" then + bandwidth = "0" + end + if index == 1 then + if channel then + XQLog.check(0, XQLog.KEY_FUNC_2G_CHANNEL, channel) + end + if txpwr then + XQLog.check(0, XQLog.KEY_FUNC_2G_SIGNAL, txpwr) + end + elseif index == 2 then + if channel then + XQLog.check(0, XQLog.KEY_FUNC_5G_CHANNEL, channel) + end + if txpwr then + XQLog.check(0, XQLog.KEY_FUNC_5G_SIGNAL, txpwr) + end + elseif index == 3 then + -- todo: Guest wifi + end + local wifirestart = true + code = XQWifiUtil.checkSSID(ssid,31) + if code == 0 then + if index == 1 or index == 2 then + local succeed = XQWifiUtil.setWifiBasicInfo(index, ssid, password, encryption, channel, txpwr, hidden, on, bandwidth) + if succeed == false then + code = XQWifiUtil.checkWifiPasswd(password,encryption) + end + elseif index == 3 then + local XQGuestWifi = require("xiaoqiang.module.XQGuestWifi") + local succeed = XQGuestWifi.setGuestWifi(1, ssid, encryption, password, 1, on) + if succeed == false then + code = 1615 + else + wifirestart = false + end + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + if wifirestart then + XQFunction.forkRestartWifi() + end + end +end + +function setAllWifi() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code = 0 + local code1 = 0 + local code2 = 0 + local details = {} + local on1 = LuciHttp.formvalue("on1") + local ssid1 = LuciHttp.formvalue("ssid1") + local password1 = LuciHttp.formvalue("pwd1") + local encryption1 = LuciHttp.formvalue("encryption1") + local channel1 = LuciHttp.formvalue("channel1") + local txpwr1 = LuciHttp.formvalue("txpwr1") + local hidden1 = LuciHttp.formvalue("hidden1") + local bandwidth1 = LuciHttp.formvalue("bandwidth1") + + local on2 = LuciHttp.formvalue("on2") + local ssid2 = LuciHttp.formvalue("ssid2") + local password2 = LuciHttp.formvalue("pwd2") + local encryption2 = LuciHttp.formvalue("encryption2") + local channel2 = LuciHttp.formvalue("channel2") + local txpwr2 = LuciHttp.formvalue("txpwr2") + local hidden2 = LuciHttp.formvalue("hidden2") + local bandwidth2 = LuciHttp.formvalue("bandwidth2") + + local on3 = LuciHttp.formvalue("on3") + local ssid3 = LuciHttp.formvalue("ssid3") + local password3 = LuciHttp.formvalue("pwd3") + local encryption3 = LuciHttp.formvalue("encryption3") + + if on1 ~= nil then + on1 = tonumber(on1) + end + if on2 ~= nil then + on2 = tonumber(on2) + end + if channel1 == "0" then + bandwidth1 = "0" + end + if channel2 == "0" then + bandwidth2 = "0" + end + local code1 = XQWifiUtil.checkSSID(ssid1,31) + local code2 = XQWifiUtil.checkSSID(ssid2,31) + if on1 ~= 0 and not XQFunction.isStrNil(ssid1) then + XQSysUtil.setRouterName(ssid1) + end + local succeed + if on1 == 0 then + succeed = XQWifiUtil.setWifiBasicInfo(1, nil, nil, nil, nil, nil, nil, on1, nil) + else + code1 = XQWifiUtil.checkSSID(ssid1,31) + if code1 == 0 then + succeed = XQWifiUtil.setWifiBasicInfo(1, ssid1, password1, encryption1, channel1, txpwr1, hidden1, on1, bandwidth1) + else + code = code1 + end + end + if succeed == false then + local error1 = {} + code1 = XQWifiUtil.checkWifiPasswd(password1,encryption1) + error1["code"] = code1 + error1["msg"] = XQErrorUtil.getErrorMessage(code1) + table.insert(details,error1) + end + if on2 == 0 then + succeed = XQWifiUtil.setWifiBasicInfo(2, nil, nil, nil, nil, nil, nil, on2, nil) + else + code2 = XQWifiUtil.checkSSID(ssid2,31) + if code2 == 0 then + succeed = XQWifiUtil.setWifiBasicInfo(2, ssid2, password2, encryption2, channel2, txpwr2, hidden2, on2, bandwidth2) + else + code = code2 + end + end + if succeed == false then + local error2 = {} + code2 = XQWifiUtil.checkWifiPasswd(password2,encryption2) + error2["code"] = code2 + error2["msg"] = XQErrorUtil.getErrorMessage(code2) + table.insert(details,error2) + end + if code1+code2 > 0 and code == 0 then + code = 1516 + end + local wifirestart = true + if on3 then + local XQGuestWifi = require("xiaoqiang.module.XQGuestWifi") + if not XQGuestWifi.setGuestWifi(1, ssid3, encryption3, password3, 1, on3) then + code = 1615 + else + wifirestart = false + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + result["errorDetails"] = details + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + if wifirestart then + XQFunction.forkRestartWifi() + end + end +end + +function getLanInfo() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local lan = XQLanWanUtil.getLanWanInfo("lan") + local linkList = XQLanWanUtil.getLanLinkList() + local result = {} + result["code"] = 0 + result["info"] = lan + result["linkList"] = linkList + LuciHttp.write_json(result) +end + +function getWanInfo() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local wan = XQLanWanUtil.getLanWanInfo("wan") + local result = {} + result["code"] = 0 + result["info"] = wan + LuciHttp.write_json(result) +end + +function getWanStatistics() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local wan = XQDeviceUtil.getWanLanNetworkStatistics("wan") + local result = {} + result["code"] = 0 + result["statistics"] = wan + LuciHttp.write_json(result) +end + +function getDevsStatistics() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local dev = XQDeviceUtil.getDevNetStatisticsList() + local result = {} + result["code"] = 0 + result["statistics"] = dev + LuciHttp.write_json(result) +end + +function getDevStatistics() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local mac = LuciHttp.formvalue("mac") + local dict = XQDeviceUtil.getDevNetStatisticsDict() + local statistics = dict[XQFunction.macFormat(mac)] + result["code"] = 0 + result["statistics"] = statistics + LuciHttp.write_json(result) +end + +function getAutoWanType() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQPreference = require("xiaoqiang.XQPreference") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + local code = 0 + local wanType = XQLanWanUtil.getAutoWanType() + if wanType == false then + code = 1524 + else + result["wanType"] = wanType + result["pppoeName"] = XQPreference.get(XQConfigs.PREF_PPPOE_NAME, "") + result["pppoePassword"] = XQPreference.get(XQConfigs.PREF_PPPOE_PASSWORD, "") + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function getLanDhcp() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = {} + local lanDhcp = XQLanWanUtil.getLanDHCPService() + result["code"] = 0 + result["info"] = lanDhcp + LuciHttp.write_json(result) +end + +function getChannels() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local wifiIndex = tonumber(LuciHttp.formvalue("wifiIndex")) + local result = {} + result["code"] = 0 + result["list"] = XQWifiUtil.getDefaultWifiChannels(wifiIndex) + LuciHttp.write_json(result) +end + +function wanDown() + luci.sys.call("env -i /sbin/ifdown wan") + local result = {code=0} + LuciHttp.write_json(result) +end + +function wanUp() + luci.sys.call("env -i /sbin/ifup wan") + local result = {code=0} + LuciHttp.write_json(result) +end + +function setLanIp() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local LuciDatatypes = require("luci.cbi.datatypes") + local LuciIp = require("luci.ip") + local result = {} + local code = 0 + local ip = LuciHttp.formvalue("ip") + local mask = "255.255.255.0" + local wanIp = XQLanWanUtil.getLanWanIp("wan")[1] + if not LuciDatatypes.ipaddr(ip) then + code = 1525 + else + if wanIp then + local lanIpNl = LuciIp.iptonl(ip) + local lanMaskNl = LuciIp.iptonl(mask) + local wanIpNl = LuciIp.iptonl(wanIp.ip) + local wanMaskNl = LuciIp.iptonl(wanIp.mask) + if bit.band(lanIpNl,lanMaskNl) == bit.band(wanIpNl,lanMaskNl) or bit.band(lanIpNl,wanMaskNl) == bit.band(wanIpNl,wanMaskNl) then + code = 1526 + else + code = XQLanWanUtil.checkLanIp(ip) + end + end + end + if code == 0 then + XQLanWanUtil.setLanIp(ip,mask) + else + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + XQFunction.forkReboot() + end +end + +function setWan() + local XQLog = require("xiaoqiang.XQLog") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQFunction = require("xiaoqiang.common.XQFunction") + local code = 0 + local result = {} + local client = LuciHttp.formvalue("client") + local wanType = LuciHttp.formvalue("wanType") + local pppoeName = LuciHttp.formvalue("pppoeName") + local pppoePwd = LuciHttp.formvalue("pppoePwd") + local staticIp = LuciHttp.formvalue("staticIp") + local staticMask = LuciHttp.formvalue("staticMask") + local staticGateway = LuciHttp.formvalue("staticGateway") + local dns1 = LuciHttp.formvalue("dns1") + local dns2 = LuciHttp.formvalue("dns2") + local special = LuciHttp.formvalue("special") + local peerDns = LuciHttp.formvalue("peerDns") + local mtu = tonumber(LuciHttp.formvalue("mtu")) + local service = LuciHttp.formvalue("service") + if XQFunction.isStrNil(wanType) + and XQFunction.isStrNil(pppoeName) + and XQFunction.isStrNil(pppoePwd) + and XQFunction.isStrNil(staticIp) + and XQFunction.isStrNil(staticMask) + and XQFunction.isStrNil(staticGateway) + and XQFunction.isStrNil(dns1) + and XQFunction.isStrNil(dns2) + and XQFunction.isStrNil(special) + and XQFunction.isStrNil(peerDns) then + code = 1502 + else + if wanType == "pppoe" then + if client == "web" then + XQLog.check(0, XQLog.KEY_VALUE_NETWORK_PPPOE, 1) + end + if XQFunction.isStrNil(pppoeName) or XQFunction.isStrNil(pppoePwd) then + code = 1528 + else + if mtu and not XQLanWanUtil.checkMTU(mtu) then + code = 1590 + else + if not XQLanWanUtil.setWanPPPoE(pppoeName, pppoePwd, dns1, dns2, peerDns, mtu, service) then + code = 1529 + end + end + end + elseif wanType == "dhcp" then + if client == "web" then + XQLog.check(0, XQLog.KEY_VALUE_NETWORK_DHCP, 1) + end + if not XQLanWanUtil.setWanStaticOrDHCP(wanType, nil, nil, nil, dns1, dns2, peerDns, mtu) then + code = 1529 + end + elseif wanType == "static" then + if client == "web" then + XQLog.check(0, XQLog.KEY_VALUE_NETWORK_STATIC, 1) + end + local LuciDatatypes = require("luci.cbi.datatypes") + local LuciIp = require("luci.ip") + if not LuciDatatypes.ipaddr(staticIp) then + code = 1530 + elseif not XQFunction.checkMask(staticMask) then + code = 1531 + elseif not LuciDatatypes.ipaddr(staticGateway) then + code = 1532 + else + local lanIp = XQLanWanUtil.getLanWanIp("lan")[1] + local lanIpNl = LuciIp.iptonl(lanIp.ip) + local lanMaskNl = LuciIp.iptonl(lanIp.mask) + local wanIpNl = LuciIp.iptonl(staticIp) + local wanMaskNl = LuciIp.iptonl(staticMask) + if bit.band(lanIpNl,lanMaskNl) == bit.band(wanIpNl,lanMaskNl) or bit.band(lanIpNl,wanMaskNl) == bit.band(wanIpNl,wanMaskNl) then + code = 1526 + else + code = XQLanWanUtil.checkWanIp(staticIp) + if code == 0 then + if not XQLanWanUtil.setWanStaticOrDHCP(wanType, staticIp, staticMask, staticGateway, dns1, dns2, peerDns, mtu) then + code = 1529 + end + end + end + end + else + -- unknown type + end + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function setLanDhcp() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local LuciDatatypes = require("luci.cbi.datatypes") + local XQFunction = require("xiaoqiang.common.XQFunction") + local code = 0 + local result = {} + local startReq = tonumber(LuciHttp.formvalue("start")) + local endReq = tonumber(LuciHttp.formvalue("end")) + local leasetime = LuciHttp.formvalue("leasetime") + local ignore = LuciHttp.formvalue("ignore") + local num,unit = leasetime:match("^(%d+)(%S+)") + num = tonumber(num) + if ignore == "1" then + XQLanWanUtil.setLanDHCPService(nil,nil,nil,ignore) + else + if not LuciDatatypes.uinteger(startReq) + or not LuciDatatypes.integer(endReq) + or num == nil + or unit ~= "h" and unit ~= "m" then + code = 1537 + else + if startReq > endReq then + code = 1534 + elseif startReq <= 1 or endReq > 254 or endReq <= 1 or endReq >254 then + code = 1535 + elseif (unit == "h" and (num < 1 or num > 48)) or (unit == "m" and (num < 2 or num > 2880)) then + code = 1536 + else + XQLanWanUtil.setLanDHCPService(startReq,endReq,leasetime,ignore) + end + end + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function setWanMac() + local XQLog = require("xiaoqiang.XQLog") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local code = 0 + local result = {} + local mac = LuciHttp.formvalue("mac") + local succeed = XQLanWanUtil.setWanMac(mac) + XQLog.check(0, XQLog.KEY_FUNC_MACCLONE, 1) + if not succeed then + code = 1537 + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function getWifiMacfilterInfo() + local LuciUtil = require("luci.util") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local model = tonumber(LuciHttp.formvalue("model")) + local code = 0 + local result = {} + local macfilterInfo = XQWifiUtil.getWiFiMacfilterInfo(model) + local wifiList = XQDeviceUtil.getConDevices(false) + result["enable"] = macfilterInfo.enable + result["model"] = macfilterInfo.model + if macfilterInfo.maclist then + for _, device in ipairs(wifiList) do + if LuciUtil.contains(macfilterInfo.maclist, device.mac) then + device.added = 1 + else + device.added = 0 + end + end + end + result["code"] = 0 + result["list"] = wifiList + result["macfilter"] = macfilterInfo.maclist + LuciHttp.write_json(result) +end + +function setWifiMacfilter() + local XQLog = require("xiaoqiang.XQLog") + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local enable = tonumber(LuciHttp.formvalue("enable")) == 1 and true or false + local model = tonumber(LuciHttp.formvalue("model")) + XQLog.check(0, XQLog.KEY_FUNC_WIRELESS_ACCESS, enable and 0 or 1) + if model and model == 0 then + XQLog.check(0, XQLog.KEY_FUNC_WIRELESS_BLACK, 1) + else + XQLog.check(0, XQLog.KEY_FUNC_WIRELESS_WHITE, 1) + end + XQWifiUtil.setWiFiMacfilterModel(enable, model) + local result = {["code"] = 0} + XQFunction.forkRestartWifi() + LuciHttp.write_json(result) +end + +function editDevice() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local code = 0 + local result = {} + local mac = LuciHttp.formvalue("mac") + local model = tonumber(LuciHttp.formvalue("model")) + local option = tonumber(LuciHttp.formvalue("option")) + local success = XQWifiUtil.editWiFiMacfilterList(model, mac, option) + if success and success == 1 then + code = 1591 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function macBind() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local code = 0 + local result = {} + local ip = LuciHttp.formvalue("ip") + local mac = LuciHttp.formvalue("mac") + local bind = XQLanWanUtil.addBind(mac, ip) + if bind == 1 then + code = 1593 + elseif bind == 2 then + code = 1592 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function macUnbind() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local code = 0 + local result = {} + local mac = LuciHttp.formvalue("mac") + local unbind = XQLanWanUtil.removeBind(mac) + if not unbind then + code = 1594 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function saveBind() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = { + ["code"] = 0 + } + XQLanWanUtil.saveBindInfo() + XQFunction.forkRestartDnsmasq() + LuciHttp.write_json(result) +end + +function unbindAll() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = { + ["code"] = 0 + } + XQLanWanUtil.unbindAll() + XQFunction.forkRestartDnsmasq() + LuciHttp.write_json(result) +end + +function getMacBindInfo() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = { + ["code"] = 0 + } + local blist = {} + local bindInfo = XQLanWanUtil.macBindInfo() + local deviceList = XQDeviceUtil.getConDevices(true) or {} + for _, device in ipairs(deviceList) do + local bind = bindInfo[string.lower(device.mac)] + if bind then + device["tag"] = bind.tag + else + device["tag"] = 0 + end + end + for _, host in pairs(bindInfo) do + table.insert(blist, { + ["mac"] = string.upper(host.mac), + ["ip"] = host.ip, + ["tag"] = host.tag + }) + end + result["list"] = blist + result["devicelist"] = deviceList + LuciHttp.write_json(result) +end + +function pppoeStatus() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local code = 0 + local result = {} + local status = XQLanWanUtil.getPPPoEStatus() + if status then + result = status + if result.errtype == 1 then + code = 1603 + elseif result.errtype == 2 then + code = 1604 + elseif result.errtype == 3 then + code = 1605 + end + else + code = 1602 + end + if code ~= 0 then + if code ~= 1602 then + result["msg"] = string.format("%s(%s)",XQErrorUtil.getErrorMessage(code), tostring(result.errcode)) + else + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + end + result["code"] = code + LuciHttp.write_json(result) +end + +function pppoeStop() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = { + ["code"] = 0 + } + XQLanWanUtil.pppoeStop() + LuciHttp.write_json(result) +end + +function pppoeStart() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = { + ["code"] = 0 + } + XQLanWanUtil.pppoeStart() + LuciHttp.write_json(result) +end + +function getQosInfo() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local status = XQQoSUtil.qosStatus() + result["status"] = status + if status.on == 1 then + result["band"] = XQQoSUtil.qosBand() + result["list"] = XQQoSUtil.qosList() + end + LuciHttp.write_json(result) +end + +function qosSwitch() + local XQLog = require("xiaoqiang.XQLog") + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local on = tonumber(LuciHttp.formvalue("on")) == 1 and true or false + XQLog.check(0, XQLog.KEY_FUNC_QOS, on and 0 or 1) + local switch = XQQoSUtil.qosSwitch(on) + if not switch then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function qosMode() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local auto = tonumber(LuciHttp.formvalue("mode")) == 0 and true or false + local status = XQQoSUtil.qosStatus() + local switch + if status and status.on == 1 then + switch = XQQoSUtil.qosModeSwitch(auto) + else + result.code = 1607 + end + if not switch and result.code == 0 then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +-- level : 1/2/3 low/middle/high +-- upload : 1 ~ 100 +-- download : 1 ~ 100 +function qosLimit() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local mac = LuciHttp.formvalue("mac") + local upload = tonumber(LuciHttp.formvalue("upload")) + local download = tonumber(LuciHttp.formvalue("download")) + local level = tonumber(LuciHttp.formvalue("level")) + local limit + local status = XQQoSUtil.qosStatus() + if status and status.on == 1 then + if mac and upload and download and level then + limit = XQQoSUtil.qosOnLimit(mac, upload/100, download/100, level, level) + else + result.code = 1523 + end + else + result.code = 1607 + end + if not limit and result.code == 0 then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function qosOffLimit() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local mac = LuciHttp.formvalue("mac") + local status = XQQoSUtil.qosStatus() + local offlimit + if status and status.on == 1 then + offlimit = XQQoSUtil.qosOffLimit(mac) + else + result.code = 1607 + end + if not offlimit and result.code == 0 then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +-- upload/download M bits/s +function setBand() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = { + ["code"] = 0 + } + local upload = tonumber(LuciHttp.formvalue("upload")) + local download = tonumber(LuciHttp.formvalue("download")) + local band + local status = XQQoSUtil.qosStatus() + if upload and download then + if status and status.on == 1 then + band = XQQoSUtil.setQosBand(upload, download) + else + result.code = 1607 + end + else + result.code = 1523 + end + if not band and result.code == 0 then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function portForward() + local XQPortForward = require("xiaoqiang.module.XQPortForward") + local result = { + ["code"] = 0 + } + local ftype = tonumber(LuciHttp.formvalue("ftype")) or 0 + result["status"] = XQPortForward.portForwardInfo().status + result["list"] = XQPortForward.portForwards(ftype) + LuciHttp.write_json(result) +end + +function addRedirect() + local XQLog = require("xiaoqiang.XQLog") + local XQPortForward = require("xiaoqiang.module.XQPortForward") + local result = { + ["code"] = 0 + } + local ip = LuciHttp.formvalue("ip") + local name = LuciHttp.formvalue("name") + local proto = tonumber(LuciHttp.formvalue("proto")) + local sport = tonumber(LuciHttp.formvalue("sport")) + local dport = tonumber(LuciHttp.formvalue("dport")) + local add = XQPortForward.setPortForward(name, ip, sport, dport, proto) + XQLog.check(0, XQLog.KEY_FUNC_PORTFADD, 1) + if add == 1 then + result.code = 1537 + elseif add == 2 then + result.code = 1608 + elseif add == 3 then + result.code = 1609 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function addRangeRedirect() + local XQLog = require("xiaoqiang.XQLog") + local XQPortForward = require("xiaoqiang.module.XQPortForward") + local result = { + ["code"] = 0 + } + local ip = LuciHttp.formvalue("ip") + local name = LuciHttp.formvalue("name") + local proto = tonumber(LuciHttp.formvalue("proto")) + local fport = tonumber(LuciHttp.formvalue("fport")) + local tport = tonumber(LuciHttp.formvalue("tport")) + local add = XQPortForward.setRangePortForward(name, ip, fport, tport, proto) + XQLog.check(0, XQLog.KEY_FUNC_RANGEFADD, 1) + if add == 1 then + result.code = 1537 + elseif add == 2 then + result.code = 1608 + elseif add == 3 then + result.code = 1609 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function deleteRedirect() + local XQPortForward = require("xiaoqiang.module.XQPortForward") + local result = { + ["code"] = 0 + } + local port = tonumber(LuciHttp.formvalue("port")) or 0 + if port == 0 then + XQPortForward.deleteAllPortForward() + else + XQPortForward.deletePortForward(port) + end + LuciHttp.write_json(result) +end + +function redirectApply() + local XQLog = require("xiaoqiang.XQLog") + local XQPortForward = require("xiaoqiang.module.XQPortForward") + local result = { + ["code"] = 0 + } + XQLog.check(0, XQLog.KEY_FUNC_PORTENABLE, 1) + XQPortForward.restart() + LuciHttp.write_json(result) +end + +function getDMZInfo() + local XQDMZModule = require("xiaoqiang.module.XQDMZModule") + local result = { + ["code"] = 0 + } + local info = XQDMZModule.getDMZInfo() + result["status"] = info.status + result["ip"] = info.ip + result["lanip"] = info.lanip + LuciHttp.write_json(result) +end + +function setDMZ() + local XQLog = require("xiaoqiang.XQLog") + local XQDMZModule = require("xiaoqiang.module.XQDMZModule") + local result = { + ["code"] = 0 + } + local ip = LuciHttp.formvalue("ip") + local mac = LuciHttp.formvalue("mac") + local mode = tonumber(LuciHttp.formvalue("mode")) or 0 + local set = XQDMZModule.setDMZ(mode, ip, mac) + if set == 1 then + result.code = 1593 + elseif set == 2 then + result.code = 1592 + elseif set == 3 then + result.code = 1611 + elseif set == 4 then + result.code = 1610 + end + XQLog.check(0, XQLog.KEY_FUNC_DMZ, 0) + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + else + XQDMZModule.dmzReload(mode) + end + LuciHttp.write_json(result) +end + +function closeDMZ() + local XQLog = require("xiaoqiang.XQLog") + local XQDMZModule = require("xiaoqiang.module.XQDMZModule") + local result = { + ["code"] = 0 + } + local mode = tonumber(LuciHttp.formvalue("mode")) or 0 + XQLog.check(0, XQLog.KEY_FUNC_DMZ, 1) + XQDMZModule.unsetDMZ(mode) + LuciHttp.write_json(result) +end + +function reloadDMZ() + local XQDMZModule = require("xiaoqiang.module.XQDMZModule") + local result = { + ["code"] = 0 + } + local mode = tonumber(LuciHttp.formvalue("mode")) or 0 + XQDMZModule.dmzReload(mode) + LuciHttp.write_json(result) +end + +function ddnsStatus() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local ddns = XQDDNS.ddnsInfo() + result["on"] = ddns.on + result["list"] = ddns.list + LuciHttp.write_json(result) +end + +function ddnsSwitch() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local on = tonumber(LuciHttp.formvalue("on")) == 1 and true or false + XQDDNS.ddnsSwitch(on) + LuciHttp.write_json(result) +end + +function addServer() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local id = tonumber(LuciHttp.formvalue("id")) + local enable = tonumber(LuciHttp.formvalue("enable")) == 1 and 1 or 0 + local domain = LuciHttp.formvalue("domain") or "" + local username = LuciHttp.formvalue("username") or "" + local password = LuciHttp.formvalue("password") or "" + local checkinterval = tonumber(LuciHttp.formvalue("checkinterval")) + local forceinterval = tonumber(LuciHttp.formvalue("forceinterval")) + if not id or not checkinterval or not forceinterval then + result.code = 1612 + elseif checkinterval <= 0 or forceinterval <= 0 then + result.code = 1523 + else + local add = XQDDNS.setDdns(id, enable, username, password, checkinterval, forceinterval, domain) + if not add then + result.code = 1606 + end + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function deleteServer() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local id = tonumber(LuciHttp.formvalue("id")) + if not id then + result.code = 1612 + else + local delete = XQDDNS.deleteDdns(id) + if not delete then + result.code = 1606 + end + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function serverSwitch() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local id = tonumber(LuciHttp.formvalue("id")) + local on = tonumber(LuciHttp.formvalue("on")) == 1 and true or false + if not id then + result.code = 1612 + else + local switch = XQDDNS.ddnsServerSwitch(id, on) + if not switch then + result.code = 1606 + end + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function ddnsReload() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + if not XQDDNS.reload() then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function getServer() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = {} + local id = tonumber(LuciHttp.formvalue("id")) + local get = XQDDNS.getDdns(id) + if get then + result = get + result["code"] = 0 + else + result["code"] = 1614 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function ddnsEdit() + local XQDDNS = require("xiaoqiang.module.XQDDNS") + local result = { + ["code"] = 0 + } + local id = tonumber(LuciHttp.formvalue("id")) + local enable = tonumber(LuciHttp.formvalue("enable")) == 1 and 1 or 0 + local domain = LuciHttp.formvalue("domain") + local username = LuciHttp.formvalue("username") + local password = LuciHttp.formvalue("password") + local checkinterval = tonumber(LuciHttp.formvalue("checkinterval")) + local forceinterval = tonumber(LuciHttp.formvalue("forceinterval")) + local edit = XQDDNS.editDdns(id, enable, username, password, checkinterval, forceinterval, domain) + if not edit then + result.code = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end diff --git a/1_1.mi_Lua/luci/controller/api/xqpassport.lua b/1_1.mi_Lua/luci/controller/api/xqpassport.lua new file mode 100644 index 0000000..951475a --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqpassport.lua @@ -0,0 +1,316 @@ +module("luci.controller.api.xqpassport", package.seeall) + +function index() + local page = node("api","xqpassport") + page.target = firstchild() + page.title = ("") + page.order = 400 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqpassport"}, firstchild(), (""), 400) + entry({"api", "xqpassport", "login"}, call("passportLogin"), (""), 401, 0x01) + entry({"api", "xqpassport", "userInfo"}, call("getUserInfo"), (""), 402) + entry({"api", "xqpassport", "rigister"}, call("routerRegister"), (""), 405, 0x01) + entry({"api", "xqpassport", "binded"}, call("getBindInfo"), (""), 406, 0x01) + entry({"api", "xqpassport", "plugin_list"}, call("pluginList"), (""), 407) + entry({"api", "xqpassport", "plugin_enable"}, call("pluginEnable"), (""), 408) + entry({"api", "xqpassport", "plugin_disable"}, call("pluginDisable"), (""), 409) + entry({"api", "xqpassport", "plugin_detail"}, call("pluginDetail"), (""), 410) + entry({"api", "xqpassport", "unbound"}, call("unboundRouter"), (""), 411) +end + +local LuciHttp = require("luci.http") +local XQErrorUtil = require("xiaoqiang.util.XQErrorUtil") + +function getBindInfo() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local uuid = LuciHttp.formvalue("uuid") or "" + local force = tonumber(LuciHttp.formvalue("force") or "0") + local result = {} + local code = 0 + local bindUUID = XQSysUtil.getPassportBindInfo() + if bindUUID then + result["bind"] = 1 + local info = XQSysUtil.getBindUserInfo() + if info == nil or force ~= 0 then + info = XQNetUtil.getUserInfo(uuid) + end + if info then + if info.miliaoNick and info.miliaoNick ~= "" then + info.aliasNick = info.miliaoNick + end + result["info"] = info + else + info = {} + info["aliasNick"] = bindUUID + info["miliaoIcon"] = "" + info["miliaoIconOrig"] = "" + info["miliaoNick"] = "" + info["userId"] = bindUUID + result["info"] = info + end + else + result["bind"] = 0 + end + result["routerName"] = XQSysUtil.getRouterName() + + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function unboundRouter() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQDBUtil = require("xiaoqiang.util.XQDBUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + local code = 0 + local uuid = LuciHttp.formvalue("uuid") + local password = LuciHttp.formvalue("password") + if uuid == nil or uuid == "" then + uuid = XQSysUtil.getBindUUID() + end + if password ~= nil then + local login = XQNetUtil.xiaomiLogin(uuid,password) + if login and login.code == 0 then + if XQSysUtil.getPassportBindInfo() then + local unbound = XQNetUtil.dismissAccount(nil,uuid) + if unbound and (tonumber(unbound.code) == 0 or tonumber(unbound.code) == 3001 or tonumber(unbound.code) == 3002) then + XQSysUtil.setPassportBound(false,uuid) + else + code = 1550 + end + end + else + code = 1556 + end + else + code = 1557 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + else + LuciHttp.header("Set-Cookie", "psp=admin|||2|||0;path=/;") + end + result["code"] = code + LuciHttp.write_json(result) +end + +function passportLogin() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQDBUtil = require("xiaoqiang.util.XQDBUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + local code = 0 + local uuid = LuciHttp.formvalue("uuid") + local password = LuciHttp.formvalue("password") + local encrypt = LuciHttp.formvalue("encrypt") + local login = XQNetUtil.xiaomiLogin(uuid,password) + if login and login.code == 0 then + local bindInfo = XQSysUtil.getPassportBindInfo() + if bindInfo then + if login.uuid == bindInfo then + local adminList = XQNetUtil.getAdminList() + if adminList and type(adminList) == "table" then + if tonumber(adminList.code) == 0 then + code = 0 + LuciHttp.header("Set-Cookie", "psp=" .. login.uuid .. "|||" .. 1 .. "|||" .. login.token .. ";path=/;") + elseif tonumber(adminList.code) == 401 then + code = 1551 + else + code = 1549 + XQSysUtil.setPassportBound(false,login.uuid) + LuciHttp.header("Set-Cookie", "psp=admin|||2|||0;path=/;") + end + else + code = 1551 + if adminList and adminList.msg then + result["errorDetail"] = adminList.msg + end + end + else + code = 1548 + end + else + XQSysUtil.setBindUUID(login.uuid) + end + result["token"] = login.token + result["uuid"] = login.uuid + elseif login and login.code ~= 0 then + if login.code == 1 then + code = 1564 + elseif login.code == 2 then + code = 1565 + else + code = 1566 + end + else + code = 1538 + end + if code ~= 0 then + local XQFunction = require("xiaoqiang.common.XQFunction") + XQFunction.forkExec("/usr/sbin/ntpsetclock 99999 log >/dev/null 2>&1") + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function routerAdminList() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + local code = 0 + local uuid = LuciHttp.formvalue("uuid") or "" + if not XQSysUtil.getPassportBindInfo() then + code = 1542 + else + local admin = XQNetUtil.getAdminList(uuid) + if admin and tonumber(admin.code) == 0 then + result["list"] = admin.adminList + elseif admin and tonumber(admin.code) == 401 then + code = 1581 + else + code = 1543 + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function routerRegister() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQDBUtil = require("xiaoqiang.util.XQDBUtil") + local result = {} + local code = 0 + local uuid = LuciHttp.formvalue("uuid") + local register = XQNetUtil.routerRegister(uuid) + local passport = XQNetUtil.getPassport(uuid) + if register and tonumber(register.code) == 0 then + result["deviceID"] = register.id + XQSysUtil.setPassportBound(true,passport.uuid) + else + XQSysUtil.setPassportBound(false,nil) + code = 1541 + end + if code ~= 0 then + local XQFunction = require("xiaoqiang.common.XQFunction") + XQFunction.forkExec("/usr/sbin/ntpsetclock 99999 log >/dev/null 2>&1") + result["msg"] = XQErrorUtil.getErrorMessage(code) + else + LuciHttp.header("Set-Cookie", "psp=" .. uuid .. "|||" .. 1 .. "|||" .. passport.token .. ";path=/;") + end + result["code"] = code + LuciHttp.write_json(result) +end + +function getUserInfo() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local result = {} + local code = 0 + local uuid = LuciHttp.formvalue("uuid") or "" + local info = XQNetUtil.getUserInfo(uuid) + if info then + result["userInfo"] = info + else + code = 1539 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function pluginList() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local result = {} + local uuid = LuciHttp.formvalue("uuid") or "" + local pList = XQNetUtil.pluginList(uuid) + if pList and tonumber(pList.code) == 0 then + result["code"] = 0 + result["list"] = pList + elseif pList and tonumber(pList.code) == 401 then + result["code"] = 1581 + elseif pList and tonumber(pList.code) == 3001 then + result["code"] = 1580 + else + result["code"] = 1544 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function pluginEnable() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local result = {} + local uuid = LuciHttp.formvalue("uuid") or "" + local pluginId = LuciHttp.formvalue("pluginId") + local enable = XQNetUtil.pluginEnable(uuid,pluginId) + if enable and tonumber(enable.code) == 0 then + result["code"] = 0 + elseif enable and tonumber(enable.code) == 401 then + result["code"] = 1581 + elseif enable and tonumber(enable.code) == 3001 then + result["code"] = 1580 + else + result["code"] = 1545 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function pluginDisable() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local result = {} + local uuid = LuciHttp.formvalue("uuid") or "" + local pluginId = LuciHttp.formvalue("pluginId") + local disable = XQNetUtil.pluginDisable(uuid,pluginId) + if disable and tonumber(disable.code) == 0 then + result["code"] = 0 + elseif disable and tonumber(disable.code) == 401 then + result["code"] = 1581 + elseif disable and tonumber(disable.code) == 3001 then + result["code"] = 1580 + else + result["code"] = 1546 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function pluginDetail() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local result = {} + local uuid = LuciHttp.formvalue("uuid") or "" + local pluginId = LuciHttp.formvalue("pluginId") + local plugin = XQNetUtil.pluginDetail(uuid,pluginId) + if plugin and tonumber(plugin.code) == 0 then + result["code"] = 0 + result["detail"] = plugin + elseif plugin and tonumber(plugin.code) == 401 then + result["code"] = 1581 + elseif plugin and tonumber(plugin.code) == 3001 then + result["code"] = 1580 + else + result["code"] = 1547 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end diff --git a/1_1.mi_Lua/luci/controller/api/xqsmarthome.lua b/1_1.mi_Lua/luci/controller/api/xqsmarthome.lua new file mode 100644 index 0000000..3bc69db --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqsmarthome.lua @@ -0,0 +1,67 @@ +module("luci.controller.api.xqsmarthome", package.seeall) + +function index() + local page = node("api","xqsmarthome") + page.target = firstchild() + page.title = ("") + page.order = 500 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqsmarthome"}, firstchild(), _(""), 500) + entry({"api", "xqsmarthome", "request"}, call("tunnelSmartHomeRequest"), _(""), 501) + entry({"api", "xqsmarthome", "request_smartcontroller"}, call("tunnelSmartControllerRequest"), _(""), 502) + entry({"api", "xqsmarthome", "request_miio"}, call("tunnelMiioRequest"), _(""), 503) + entry({"api", "xqsmarthome", "request_mitv"}, call("requestMitv"), _(""), 504) + entry({"api", "xqsmarthome", "request_yeelink"}, call("tunnelYeelink"), _(""), 505) + entry({"api", "xqsmarthome", "request_camera"}, call("requestCamera"), _(""), 506) +end + +local LuciHttp = require("luci.http") +local XQConfigs = require("xiaoqiang.common.XQConfigs") +local XQFunction = require("xiaoqiang.common.XQFunction") + +function tunnelSmartHomeRequest() + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = XQCryptoUtil.binaryBase64Enc(LuciHttp.formvalue("payload")) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_SMARTHOME % payload + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function tunnelSmartControllerRequest() + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = XQCryptoUtil.binaryBase64Enc(LuciHttp.formvalue("payload")) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_SMARTHOME_CONTROLLER % payload + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function tunnelMiioRequest() + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = XQCryptoUtil.binaryBase64Enc(LuciHttp.formvalue("payload")) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_MIIO % payload + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function tunnelYeelink() + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local payload = XQCryptoUtil.binaryBase64Enc(LuciHttp.formvalue("payload")) + -- merge yeelink daemon into miio, so tunnel into miio + local cmd = XQConfigs.THRIFT_TUNNEL_TO_MIIO % payload + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function requestMitv() + local payload = LuciHttp.formvalue("payload"); + local MitvUtil = require("xiaoqiang.util.XQMitvUtil"); + LuciHttp.write(MitvUtil.request(payload)); +end + +function requestCamera() + local payload = LuciHttp.formvalue("payload"); + local CamUtil = require("xiaoqiang.util.XQCameraUtil"); + LuciHttp.write(CamUtil.request(payload)); +end diff --git a/1_1.mi_Lua/luci/controller/api/xqsystem.lua b/1_1.mi_Lua/luci/controller/api/xqsystem.lua new file mode 100644 index 0000000..a613b41 --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqsystem.lua @@ -0,0 +1,1598 @@ +module("luci.controller.api.xqsystem", package.seeall) + +function index() + local page = node("api","xqsystem") + page.target = firstchild() + page.title = ("") + page.order = 100 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqsystem"}, firstchild(), (""), 100) + entry({"api", "xqsystem", "login"}, call("actionLogin"), (""), 109, 0x08) + entry({"api", "xqsystem", "init_info"}, call("getInitInfo"), (""), 101, 0x09) + entry({"api", "xqsystem", "fac_info"}, call("getFacInfo"), (""), 101, 0x09) + entry({"api", "xqsystem", "token"}, call("getToken"), (""), 103, 0x08) + entry({"api", "xqsystem", "set_inited"}, call("setInited"), (""), 103, 0x08) + entry({"api", "xqsystem", "system_info"}, call("getSysInfo"), (""), 104, 0x01) + entry({"api", "xqsystem", "set_name_password"}, call("setPassword"), (""), 105) + entry({"api", "xqsystem", "check_rom_update"}, call("checkRomUpdate"), (""), 106) + entry({"api", "xqsystem", "lan_wan"}, call("getLanWanSta"), (""), 106) + -- for Web only + entry({"api", "xqsystem", "flash_rom"}, call("flashRom"), (""), 108) + + -- deprecated + entry({"api", "xqsystem", "router_name"}, call("getRouterName"), (""), 110) + + entry({"api", "xqsystem", "device_list"}, call("getDeviceList"), (""), 112) + entry({"api", "xqsystem", "set_device_nickname"}, call("setDeviceNickName"), (""), 113) + entry({"api", "xqsystem", "internet_connect"}, call("isInternetConnect"), (""), 114) + entry({"api", "xqsystem", "upload_rom"}, call("uploadRom"), (""), 115) + entry({"api", "xqsystem", "get_languages"}, call("getLangList"), (""), 118, 0x01) + entry({"api", "xqsystem", "get_main_language"}, call("getMainLang"), (""), 119, 0x01) + entry({"api", "xqsystem", "set_language"}, call("setLang"), (""), 120) + + entry({"api", "xqsystem", "upload_log"}, call("uploadLogFile"), (""), 124) + entry({"api", "xqsystem", "backup_config"}, call("uploadConfigFile"), (""), 125) + entry({"api", "xqsystem", "config_recovery"}, call("configRecovery"), (""), 126) + entry({"api", "xqsystem", "router_init"}, call("setRouter"), (""), 126, 0x08) + entry({"api", "xqsystem", "information"}, call("getAllInfo"), (""), 127) + entry({"api", "xqsystem", "status"}, call("getStatusInfo"), (""), 128) + entry({"api", "xqsystem", "count"}, call("getConDevCount"), (""), 129) + entry({"api", "xqsystem", "reboot"}, call("reboot"), (""), 130) + entry({"api", "xqsystem", "reset"}, call("reset"), (""), 131) + entry({"api", "xqsystem", "passport_bind_info"}, call("getPassportBindInfo"), (""), 132, 0x01) + entry({"api", "xqsystem", "set_passport_bound"}, call("setPassportBound"), (""), 133, 0x08) + entry({"api", "xqsystem", "get_sys_avg_load"}, call("getSysAvgLoad"), (""), 134) + entry({"api", "xqsystem", "set_mac_filter"}, call("setMacFilter"), (""), 135) + entry({"api", "xqsystem", "renew_token"}, call("renewToken"), (""), 136) + entry({"api", "xqsystem", "remove_passport_info"}, call("removePassportBindInfo"), (""), 137) + entry({"api", "xqsystem", "upgrade_rom"}, call("upgradeRom"), (""), 138) + entry({"api", "xqsystem", "wps"}, call("openWps"), (""), 139, 0x08) + entry({"api", "xqsystem", "wps_status"}, call("getWpsStatus"), (""), 140) + entry({"api", "xqsystem", "stop_nginx"}, call("stopNginx"), (""), 141) + entry({"api", "xqsystem", "check_router_name_pending"}, call("checkRouterNamePending"), (""), 142) + entry({"api", "xqsystem", "clear_router_name_pending"}, call("clearRouterNamePending"), (""), 143) + entry({"api", "xqsystem", "web_url"}, call("redirectUrl"), (""), 144) + entry({"api", "xqsystem", "start_nginx"}, call("startNginx"), (""), 145) + entry({"api", "xqsystem", "nginx"}, call("nginxCacheStatus"), (""), 146) + entry({"api", "xqsystem", "flash_status"}, call("flashStatus"), (""), 147, 0x01) + entry({"api", "xqsystem", "upgrade_status"}, call("upgradeStatus"), (""), 148, 0x0d) + entry({"api", "xqsystem", "create_sandbox"}, call("createSandbox"), (""), 149) + entry({"api", "xqsystem", "is_sandbox_created"}, call("isSandboxCreated"), (""), 150) + entry({"api", "xqsystem", "mount_things"}, call("mountThings"), (""), 151) + entry({"api", "xqsystem", "umount_things"}, call("umountThings"), (""), 152) + entry({"api", "xqsystem", "are_things_mounted"}, call("areThingsMounted"), (""), 153) + entry({"api", "xqsystem", "start_dropbear"}, call("startDropbear"), (""), 154) + entry({"api", "xqsystem", "stop_dropbear"}, call("stopDropbear"), (""), 155) + entry({"api", "xqsystem", "is_dropbear_started"}, call("isDropbearStarted"), (""), 156) + entry({"api", "xqsystem", "main_status_for_app"}, call("mainStatusForApp"), (""), 157) + entry({"api", "xqsystem", "mode"}, call("getMacfilterMode"), (""), 158) + entry({"api", "xqsystem", "set_mode"}, call("setMacfilterMode"), (""), 159) + entry({"api", "xqsystem", "cancel"}, call("cancelUpgrade"), (""), 160, 0x0d) + entry({"api", "xqsystem", "shutdown"}, call("shutdown"), (""), 161) + entry({"api", "xqsystem", "upnp"}, call("upnpList"), (""), 162) + entry({"api", "xqsystem", "upnp_switch"}, call("upnpSwitch"), (""), 163) + entry({"api", "xqsystem", "app_limit"}, call("appLimit"), (""), 164) + entry({"api", "xqsystem", "app_limit_switch"}, call("appLimitSwitch"), (""), 165) + entry({"api", "xqsystem", "set_app_limit"}, call("setAppLimit"), (""), 166) + entry({"api", "xqsystem", "vpn"}, call("vpnInfo"), (""), 167) + entry({"api", "xqsystem", "vpn_status"}, call("vpnStatus"), (""), 168) + entry({"api", "xqsystem", "vpn_switch"}, call("vpnSwitch"), (""), 169) + entry({"api", "xqsystem", "set_vpn"}, call("setVpn"), (""), 170) + entry({"api", "xqsystem", "device_mac"}, call("getDeviceMacaddr"), (""), 171, 0x01) + entry({"api", "xqsystem", "wps_cancel"}, call("stopWps"), (""), 172) + entry({"api", "xqsystem", "detection_ts"}, call("getDetectionTimestamp"), (""), 173) + entry({"api", "xqsystem", "wifi_log"}, call("getWifiLog"), (""), 174) + entry({"api", "xqsystem", "sys_recovery"}, call("sysRecovery"), (""), 175) + entry({"api", "xqsystem", "smart_shutdown"}, call("smartShutdown"), (""), 177) + + -- include zigbee dongle device only + entry({"api", "xqsystem", "device_list_zigbee"}, call("getDeviceListZigbee"), (""), 176) + -- Noflushd + entry({"api", "xqsystem", "noflushd"}, call("getNofStatus"), (""), 178) + entry({"api", "xqsystem", "nof_switch"}, call("nofSwitch"), (""), 179) + entry({"api", "xqsystem", "pred_status"}, call("predownloadInfo"), (""), 180) + entry({"api", "xqsystem", "pred_switch"}, call("predownloadSwitch"), (""), 181) +end + +local LuciHttp = require("luci.http") +local XQConfigs = require("xiaoqiang.common.XQConfigs") +local XQSysUtil = require("xiaoqiang.util.XQSysUtil") +local XQErrorUtil = require("xiaoqiang.util.XQErrorUtil") + +function getInitInfo() + local XQCountryCode = require("xiaoqiang.XQCountryCode") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local monitor = XQLanWanUtil.getWanMonitorStat() + local connect = 0 + if monitor.WANLINKSTAT == "UP" then + connect = 1 + end + local result = {} + result["code"] = 0 + result["connect"] = connect + result["inited"] = XQSysUtil.getInitInfo() and 1 or 0 + result["bound"] = XQSysUtil.getPassportBindInfo() and 1 or 0 + result["id"] = XQNetUtil.getSN() + result["routerId"] = XQNetUtil.getDeviceId() + result["hardware"] = XQSysUtil.getHardware() + result["romversion"] = XQSysUtil.getRomVersion() + result["modules"] = XQSysUtil.getModulesList() + result["language"] = XQSysUtil.getLang() + result["countrycode"] = XQCountryCode.getCurrentCountryCode() + LuciHttp.write_json(result) +end + +function getFacInfo() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + LuciHttp.write_json(XQSysUtil.facInfo()) +end + +function actionLogin() + local result = {} + local init = tonumber(LuciHttp.formvalue("init")) + result["code"] = 0 + if init and init == 1 then + result["url"] = luci.dispatcher.build_url("web", "init", "guide") + else + result["url"] = luci.dispatcher.build_url("web", "home") + end + LuciHttp.write_json(result) +end + +function getToken() + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local sid = LuciHttp.formvalue("sid") + local result = {} + result["code"] = 0 + result["token"] = luci.dispatcher.context.urltoken.stok + result["id"] = XQNetUtil.getSN() + result["name"] = XQSysUtil.getRouterName() + LuciHttp.write_json(result) +end + +function renewToken() + local sauth = require "luci.sauth" + local result = {} + local session = sauth.available() + if session then + result["token"] = session.token + else + local token = luci.sys.uniqueid(16) + sauth.write(token, { + user="admin", + token=token, + ltype="1", + secret=luci.sys.uniqueid(16) + }) + result["token"] = token + end + result["code"] = 0 + LuciHttp.write_json(result) +end + +function setInited() + local XQLog = require("xiaoqiang.XQLog") + local client = LuciHttp.formvalue("client") + if client == "ios" then + XQLog.check(0, XQLog.KEY_GEL_INIT_IOS, 1) + elseif client == "android" then + XQLog.check(0, XQLog.KEY_GEL_INIT_ANDROID, 1) + elseif client == "other" then + XQLog.check(0, XQLog.KEY_GEL_INIT_OTHER, 1) + end + local result = {} + local inited = XQSysUtil.setInited() + if not inited then + result["code"] = 1501 + result["msg"] = XQErrorUtil.getErrorMessage(1501) + else + result["code"] = 0 + end + LuciHttp.write_json(result) +end + +function getLanWanSta() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local result = {} + result["code"] = 0 + result["lan"] = XQDeviceUtil.getWanLanNetworkStatistics("lan") + result["wan"] = XQDeviceUtil.getWanLanNetworkStatistics("wan") + LuciHttp.write_json(result) +end + +function getPassportBindInfo() + local result = {} + local bind = XQSysUtil.getPassportBindInfo() + result["code"] = 0 + if bind then + result["bound"] = 1 + result["uuid"] = bind + else + result["bound"] = 0 + end + LuciHttp.write_json(result) +end + +function setPassportBound() + local uuid = LuciHttp.formvalue("uuid") + local result = {} + local inited = XQSysUtil.setPassportBound(true,uuid) + if not inited then + result["code"] = 1501 + result["msg"] = XQErrorUtil.getErrorMessage(1501) + else + result["code"] = 0 + end + LuciHttp.write_json(result) +end + +function removePassportBindInfo() + local uuid = LuciHttp.formvalue("uuid") + local result = {} + XQSysUtil.setPassportBound(false,uuid) + result["code"] = 0 + LuciHttp.write_json(result) +end + +function getSysInfo() + local result = {} + result["code"] = 0 + result["upTime"] = XQSysUtil.getSysUptime() + result["routerName"] = XQSysUtil.getRouterName() + result["romVersion"] = XQSysUtil.getRomVersion() + result["romChannel"] = XQSysUtil.getChannel() + result["hardware"] = XQSysUtil.getHardware() + LuciHttp.write_json(result) +end + +function getAllInfo() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local monitor = XQLanWanUtil.getWanMonitorStat() + local connect = 0 + if monitor.WANLINKSTAT == "UP" then + connect = 1 + end + result["connect"] = connect + result["wifi"] = XQWifiUtil.getAllWifiInfo() + result["wan"] = XQLanWanUtil.getLanWanInfo("wan") + result["lan"] = XQLanWanUtil.getLanWanInfo("lan") + result["code"] = 0 + result.wifi[1].channel = XQWifiUtil.getWifiWorkChannel(1) + result.wifi[2].channel = XQWifiUtil.getWifiWorkChannel(2) + LuciHttp.write_json(result) +end + +function getStatusInfo() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local monitor = XQLanWanUtil.getWanMonitorStat() + if monitor.WANLINKSTAT == "UP" then + result["connect"] = 1 + end + if monitor.VPNLINKSTAT == "UP" then + result["vpn"] = 1 + end + local wifiConCount = {} + table.insert(wifiConCount,#XQWifiUtil.getWifiConnectDeviceList(1)) + table.insert(wifiConCount,#XQWifiUtil.getWifiConnectDeviceList(2)) + local statList = XQDeviceUtil.getDevNetStatisticsList() + if #statList > 0 then + table.sort(statList, function(a, b) return tonumber(a.download) > tonumber(b.download) end) + end + if #statList > XQConfigs.DEVICE_STATISTICS_LIST_LIMIT then + local item = {} + item["mac"] = "" + item["ip"] = "" + for i=1,#statList - XQConfigs.DEVICE_STATISTICS_LIST_LIMIT + 1 do + local deleteElement = table.remove(statList, XQConfigs.DEVICE_STATISTICS_LIST_LIMIT) + item["onlinets"] = deleteElement.onlinets + item["activets"] = deleteElement.activets + item["upload"] = tonumber(deleteElement.upload) + tonumber(item.upload or 0) + item["upspeed"] = tonumber(deleteElement.upspeed) + tonumber(item.upspeed or 0) + item["download"] = tonumber(deleteElement.download) + tonumber(item.download or 0) + item["downspeed"] = tonumber(deleteElement.downspeed) + tonumber(item.downspeed or 0) + item["online"] = deleteElement.online + item["idle"] = deleteElement.idle + item["devname"] = "Others" + item["initail"] = deleteElement.initail + item["maxuploadspeed"] = deleteElement.maxuploadspeed + item["maxdownloadspeed"] = deleteElement.maxdownloadspeed + end + table.insert(statList,item) + end + + result["lanLink"] = XQLanWanUtil.getLanLinkList() + result["count"] = XQDeviceUtil.getConnectDeviceCount() + result["upTime"] = XQSysUtil.getSysUptime() + result["wifiCount"] = wifiConCount + result["wanStatistics"] = XQDeviceUtil.getWanLanNetworkStatistics("wan") + result["devStatistics"] = statList + result["code"] = 0 + LuciHttp.write_json(result) +end + +function getConDevCount() + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local result = {} + result["code"]= 0 + result["count"] = XQDeviceUtil.getConnectDeviceCount() + LuciHttp.write_json(result) +end + +function _savePassword(nonce, oldpwd, newpwd) + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + local code = 0 + local mac = luci.dispatcher.getremotemac() + local checkNonce = XQSecureUtil.checkNonce(nonce, mac) + if checkNonce then + local check = XQSecureUtil.checkUser("admin", nonce, oldpwd) + if check then + if XQSecureUtil.saveCiphertextPwd("admin", newpwd) then + code = 0 + else + code = 1553 + end + else + code = 1552 + end + else + code = 1582 + end + return code +end + +function setPassword() + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code + local nonce = LuciHttp.formvalue("nonce") + local oldPassword = LuciHttp.formvalue("oldPwd") + local newPassword = LuciHttp.formvalue("newPwd") + if XQFunction.isStrNil(oldPassword) or XQFunction.isStrNil(newPassword) then + code = 1502 + else + if nonce then + code = _savePassword(nonce, oldPassword, newPassword) + else + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + local check = XQSysUtil.checkSysPassword(oldPassword) or XQSecureUtil.checkPlaintextPwd("admin", oldPassword) + if check then + local setPwd = XQSysUtil.setSysPassword(newPassword) + if setPwd then + code = 0 + else + code = 1553 + end + else + code = 1552 + end + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function checkRomUpdate() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + local status = {status = 0, percent = 0} + local code = 0 + local check = XQNetUtil.checkUpgrade() + local upgrade = XQSysUtil.checkUpgradeStatus() + if check == false then + code = 1504 + else + code = 0 + result = check + end + result["status"] = status + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +-- 直接执行升级脚本 +function upgradeRom() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + + local url = LuciHttp.formvalue("url") + local filesize = tostring(LuciHttp.formvalue("filesize")) + local hash = tostring(LuciHttp.formvalue("hash")) + + local result = {} + local code = 0 + if XQSysUtil.checkBeenUpgraded() then + code = 1577 + elseif XQSysUtil.isUpgrading() then + code = 1568 + elseif not XQSecureUtil.cmdSafeCheck(url) or not XQSecureUtil.cmdSafeCheck(filesize) or not XQSecureUtil.cmdSafeCheck(hash) then + code = 1523 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) + if code == 0 then + XQFunction.sysLock() + if url and filesize and hash then + XQFunction.forkExec(string.format("/usr/sbin/crontab_rom.sh '%s' '%s' '%s'", url, hash, filesize)) + else + XQFunction.forkExec("/usr/sbin/crontab_rom.sh") + end + end +end + +function cancelUpgrade() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local code = 0 + local result = {} + local succeed = XQSysUtil.cancelUpgrade() + if not succeed then + code = 1579 + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function flashRom() + local LuciFs = require("luci.fs") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQPreference = require("xiaoqiang.XQPreference") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local LuciUtil = require("luci.util") + local custom = tonumber(LuciHttp.formvalue("custom") or 0) + local result = {} + local code = 0 + local filePath = XQConfigs.ROM_CACHE_FILEPATH + if custom == 1 then + filePath = XQConfigs.CROM_DISK_CACHE_FILEPATH + end + local flashStatus = XQSysUtil.getFlashStatus() + if flashStatus == 1 then + code = 1560 + elseif flashStatus == 2 then + code = 1577 + elseif not LuciFs.access(filePath) then + code = 1507 + elseif not XQSysUtil.verifyImage(filePath) then + code = 1554 + end + XQFunction.ledFlashAlert(false) + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) + if code == 0 then + LuciHttp.close() + XQFunction.sysLock() + XQFunction.forkFlashRomFile(filePath) + end +end + +function flashStatus() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + result["code"] = 0 + result["status"] = XQSysUtil.getFlashStatus() + LuciHttp.write_json(result) +end + +function upgradeStatus() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + result["code"] = 0 + result["status"] = XQSysUtil.checkUpgradeStatus() + if result.status == 3 then + local LuciFs = require("luci.fs") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQPreference = require("xiaoqiang.XQPreference") + local XQDownloadUtil = require("xiaoqiang.util.XQDownloadUtil") + local downloadId = XQPreference.get(XQConfigs.PREF_ROM_DOWNLOAD_ID, nil) + if downloadId then + result["percent"] = XQDownloadUtil.downloadPercent(downloadId) + else + result["percent"] = 0 + end + elseif result.status == 5 then + result["percent"] = 100 + end + LuciHttp.write_json(result) +end + +function getRouterName() + local result = {} + result["code"] = 0 + result["routerName"] = XQSysUtil.getRouterName() + LuciHttp.write_json(result) +end + +function setRouterName() + local XQFunction = require("xiaoqiang.common.XQFunction") + local routerName = LuciHttp.xqformvalue("routerName") + local result = {} + local code = 0 + if XQFunction.isStrNil(routerName) then + code = 1502 + else + local newName = XQSysUtil.setRouterName(routerName) + if newName == false then + code = 1503 + else + result["routerName"] = newName + end + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function setRouter() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + local code = 0 + local msg = {} + local needRestartWifi = false + local nonce = LuciHttp.formvalue("nonce") + local newPwd = LuciHttp.formvalue("newPwd") + local oldPwd = LuciHttp.formvalue("oldPwd") + local wifiPwd = LuciHttp.formvalue("wifiPwd") + local wifi24Ssid = LuciHttp.formvalue("wifi24Ssid") + local wifi50Ssid = LuciHttp.formvalue("wifi50Ssid") + local wanType = LuciHttp.formvalue("wanType") + local pppoeName = LuciHttp.formvalue("pppoeName") + local pppoePwd = LuciHttp.formvalue("pppoePwd") + + XQFunction.nvramSet("Router_unconfigured", "0") + XQFunction.nvramCommit() + + local checkssid = XQWifiUtil.checkSSID(wifi24Ssid,28) + if not XQFunction.isStrNil(wifi24Ssid) and checkssid == 0 then + XQSysUtil.setRouterName(wifi24Ssid) + end + if not XQFunction.isStrNil(newPwd) and not XQFunction.isStrNil(oldPwd) then + if nonce then + code = _savePassword(nonce, oldPwd, newPwd) + else + local check = XQSysUtil.checkSysPassword(oldPwd) + if check then + local succeed = XQSysUtil.setSysPassword(newPwd) + if not succeed then + code = 1515 + end + else + code = 1552 + end + end + if code ~= 0 then + table.insert(msg,XQErrorUtil.getErrorMessage(code)) + end + end + if not XQFunction.isStrNil(wanType) then + local succeed + if wanType == "pppoe" and not XQFunction.isStrNil(pppoeName) and not XQFunction.isStrNil(pppoePwd) then + succeed = XQLanWanUtil.setWanPPPoE(pppoeName,pppoePwd) + elseif wanType == "dhcp" then + succeed = XQLanWanUtil.setWanStaticOrDHCP(wanType) + end + if not succeed then + code = 1518 + table.insert(msg,XQErrorUtil.getErrorMessage(code)) + else + needRestartWifi = true + end + end + if not XQFunction.isStrNil(wifiPwd) and checkssid == 0 then + local succeed1 = XQWifiUtil.setWifiBasicInfo(1, wifi24Ssid, wifiPwd, "mixed-psk", nil, nil, 0) + local succeed2 = XQWifiUtil.setWifiBasicInfo(2, wifi50Ssid, wifiPwd, "mixed-psk", nil, nil, 0) + if succeed1 or succeed2 then + needRestartWifi = true + end + if not succeed1 or not succeed2 then + code = XQWifiUtil.checkWifiPasswd(wifiPwd, "mixed-psk") + table.insert(msg,XQErrorUtil.getErrorMessage(code)) + end + end + if checkssid ~= 0 then + code = checkssid + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(1519) + result["errorDetails"] = msg + end + XQSysUtil.setSPwd() + XQSysUtil.setInited() + result["code"] = code + LuciHttp.write_json(result) + if needRestartWifi then + LuciHttp.close() + XQFunction.forkRestartWifi() + end +end + +function getDeviceList() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local result = {} + result["code"] = 0 + result["mac"] = luci.dispatcher.getremotemac() + result["list"] = XQDeviceUtil.getConnectDeviceList() + LuciHttp.write_json(result) +end + +function getDeviceListZigbee() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local XQZigbeeUtil = require("xiaoqiang.util.XQZigbeeUtil") + local result = {} + result["code"] = 0 + result["mac"] = luci.dispatcher.getremotemac() + local list = {} + -- add zigbee device + XQZigbeeUtil.append_yeelink_list(list) + result["list"] = list + LuciHttp.write_json(result) +end + +function isInternetConnect() + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local result = {} + local monitor = XQLanWanUtil.getWanMonitorStat() + local connect = 0 + if monitor.WANLINKSTAT == "UP" then + connect = 1 + end + result["code"] = 0 + result["connect"] = connect + LuciHttp.write_json(result) +end + +function setDeviceNickName() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local LuciDatatypes = require("luci.cbi.datatypes") + local result = {} + local code = 0 + local mac = LuciHttp.formvalue("mac") + local nickName = LuciHttp.formvalue("name") + if XQFunction.isStrNil(mac) or XQFunction.isStrNil(nickName) then + code = 1502 + -- allow none ip device to set nick name (zigbee device) + -- elseif not LuciDatatypes.macaddr(mac) then + -- code = 1508 + else + XQDeviceUtil.saveDeviceName(mac,nickName) + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + + +function _prepare() + local FS = require("nixio.fs") + FS.mkdir(XQConfigs.USERDISK_UPLOAD_DIR, 777) + if not _sane() then + error("Upload Rom Exception: /userdisk/upload path is not sane!") + end +end + +function _sane() + local FS = require("nixio.fs") + local LuciSys = require("luci.sys") + return LuciSys.process.info("uid") + == FS.stat(XQConfigs.USERDISK_UPLOAD_DIR, "uid") +end + +function uploadRom() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local LuciSys = require("luci.sys") + local LuciFs = require("luci.fs") + + local fp + local code = 0 + if not _sane() then + _prepare() + end + local tmpfile = XQConfigs.USERDISK_UPLOAD_DIR..LuciSys.uniqueid(16) + local fileSize = tonumber(LuciHttp.getenv("CONTENT_LENGTH")) + local canupload = XQSysUtil.checkDiskSpace(fileSize) + LuciHttp.setfilehandler( + function(meta, chunk, eof) + if canupload then + if not fp then + if meta and meta.name == "image" then + fp = io.open(tmpfile, "w") + end + end + if chunk then + fp:write(chunk) + end + if eof then + fp:close() + if LuciFs.access(XQConfigs.CROM_DISK_CACHE_FILEPATH) then + LuciFs.unlink(XQConfigs.CROM_DISK_CACHE_FILEPATH) + end + LuciFs.rename(tmpfile, XQConfigs.CROM_DISK_CACHE_FILEPATH) + end + else + code = 1578 + end + end) + if LuciHttp.formvalue("image") and fp then + code = 0 + else + if code == 0 then + XQLog.log(6, "upload failed, file not exist: "..tostring(filepath)) + code = 1509 + end + end + local result = {} + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function getLangList() + local result = {} + result["code"] = 0 + result["list"] = XQSysUtil.getLangList() + LuciHttp.write_json(result) +end + +function getMainLang() + local result = {} + result["code"] = 0 + result["lang"] = XQSysUtil.getLang() + LuciHttp.write_json(result) +end + +function setLang() + local XQFunction = require("xiaoqiang.common.XQFunction") + local code = 0 + local result = {} + local lang = LuciHttp.formvalue("language") + if XQFunction.isStrNil(lang) then + code = 1502 + end + local succeed = XQSysUtil.setLang() + if not succeed then + code = 1511 + end + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + result["code"] = code + LuciHttp.write_json(result) +end + +function uploadLogFile() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local LuciUtil = require("luci.util") + local code = 0 + local result = {} + LuciUtil.exec("/usr/sbin/log_collection.sh") + local succeed = XQNetUtil.uploadLogFile(XQConfigs.LOG_ZIP_FILEPATH,"B") + if not succeed then + code = 1512 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciUtil.exec("rm "..XQConfigs.LOG_ZIP_FILEPATH) + LuciHttp.write_json(result) +end + +function uploadConfigFile() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local LuciUtil = require("luci.util") + local code = 0 + local result = {} + LuciUtil.exec("/usr/sbin/config_collection.sh") + local succeed = XQNetUtil.uploadConfigFile(XQConfigs.CONFIG_ZIP_FILEPATH) + if not succeed then + code = 1512 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciUtil.exec("rm "..XQConfigs.CONFIG_ZIP_FILEPATH) + LuciHttp.write_json(result) +end + +function configRecovery() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQNetUtil = require("xiaoqiang.util.XQNetUtil") + local LuciUtil = require("luci.util") + local code = 0 + local result = {} + local succeed = XQNetUtil.getConfigFile(XQConfigs.CONFIG_ZIP_FILEPATH) + if not succeed then + code = 1513 + else + LuciUtil.exec("/usr/bin/unzip -o "..XQConfigs.CONFIG_ZIP_FILEPATH.." -d //") + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciUtil.exec("/bin/rm "..XQConfigs.CONFIG_ZIP_FILEPATH) + LuciHttp.write_json(result) +end + +function reboot() + local XQLog = require("xiaoqiang.XQLog") + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local client = LuciHttp.formvalue("client") + local lanIp = XQLanWanUtil.getLanWanIp("lan") + local result = {} + if client == "web" then + XQLog.check(0, XQLog.KEY_REBOOT, 1) + end + result["code"] = 0 + result["lanIp"] = lanIp + LuciHttp.write_json(result) + LuciHttp.close() + XQFunction.forkReboot() +end + +function reset() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQFunction = require("xiaoqiang.common.XQFunction") + local LuciUtil = require("luci.util") + local LuciJson = require("json") + local format = tonumber(LuciHttp.formvalue("format") or 0) + local code = 0 + local result = {} + if format == 1 then + local formatResult = XQFunction.thrift_tunnel_to_datacenter([[{"api":28}]]) + if formatResult then + if formatResult.code == 0 then + code = 0 + else + code = 1558 + end + else + code = 1559 + end + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) + LuciHttp.close() + if result.code == 0 then + -- reset smart controller database and config + XQFunction.thrift_tunnel_to_smarthome_controller([[{"command":"reset_scenes"}]]) + -- set restore default and reboot + XQFunction.forkResetAll() + end +end + +function getSysAvgLoad() + local LuciUtil = require("luci.util") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + XQSysUtil.setDetectionTimestamp() + local result = {} + result["code"] = 0 + local avg = LuciUtil.exec("/usr/sbin/sysapi system_info get cpuload") + result["loadavg"] = tonumber(avg) + result["processCount"] = tonumber(LuciUtil.exec("cat /proc/cpuinfo | grep -c 'processor'")) + LuciHttp.write_json(result) + LuciHttp.close() +end + +function setMacFilter() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local LuciUtil = require("luci.util") + local LuciDatatypes = require("luci.cbi.datatypes") + local result = {} + local code = 0 + local mac = LuciHttp.formvalue("mac") + local wan = LuciHttp.formvalue("wan") + local lan = LuciHttp.formvalue("lan") + local admin = LuciHttp.formvalue("admin") + local pridisk = LuciHttp.formvalue("pridisk") + + if not XQFunction.isStrNil(mac) and LuciDatatypes.macaddr(mac) then + if wan then + wan = tonumber(wan) == 1 and "1" or "0" + end + if lan then + lan = tonumber(lan) == 1 and "1" or "0" + end + if admin then + admin = tonumber(admin) == 1 and "1" or "0" + end + if pridisk then + pridisk = tonumber(pridisk) == 1 and "1" or "0" + end + XQSysUtil.setMacFilter(mac,lan,wan,admin,pridisk) + else + code = 1508 + end + result["code"] = code + if code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(code) + end + LuciHttp.write_json(result) +end + +function openWps() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local result = {} + result["code"] = 0 + result["timestamp"] = XQWifiUtil.openWifiWps() + LuciHttp.write_json(result) +end + +function stopWps() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + XQWifiUtil.stopWps() + local result = {} + result["code"] = 0 + LuciHttp.write_json(result) +end + +function _checkConnection(mac, try) + local cmac + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + if not mac then + cmac = XQWifiUtil.getWpsConDevMac() + else + cmac = mac + end + if XQWifiUtil.isDeviceWifiConnect(cmac, 1) or XQWifiUtil.isDeviceWifiConnect(cmac, 2) then + return cmac + else + if try > 0 then + os.execute("sleep 3") + _checkConnection(cmac, try - 1) + end + end + return false +end + +function getWpsStatus() + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQPreference = require("xiaoqiang.XQPreference") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local result = {} + local status = XQWifiUtil.getWifiWpsStatus() + if status == 2 then + local device = {} + local mac = XQWifiUtil.getWpsConDevMac() + if mac then + if XQWifiUtil.isDeviceWifiConnect(mac, 1) or XQWifiUtil.isDeviceWifiConnect(mac, 2) then + device["mac"] = mac + device["company"] = XQDeviceUtil.getDeviceCompany(mac) + else + local cmac = _checkConnection(mac, 2) + if cmac then + device["mac"] = cmac + device["company"] = XQDeviceUtil.getDeviceCompany(cmac) + result["device"] = device + else + status = 9 + end + end + else + local cmac = _checkConnection(mac, 2) + if cmac then + device["mac"] = cmac + device["company"] = XQDeviceUtil.getDeviceCompany(cmac) + result["device"] = device + else + status = 9 + end + end + end + if status >= 3 and status <= 7 then + status = 3 + end + result["code"] = 0 + result["status"] = status + result["startTime"] = XQPreference.get(XQConfigs.PREF_WPS_TIMESTAMP,"") + result["currentTime"] = tostring(os.time()) + LuciHttp.write_json(result) +end + +function createSandbox() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.LAMP_CREATE_SANDBOX) + LuciHttp.write_json(result) +end + +function mountThings() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.LAMP_MOUNT_THINGS) + LuciHttp.write_json(result) +end + +function umountThings() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.LAMP_UMOUNT_THINGS) + LuciHttp.write_json(result) +end + +function startDropbear() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.LAMP_START_DROPBEAR) + LuciHttp.write_json(result) +end + +function stopDropbear() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.LAMP_STOP_DROPBEAR) + LuciHttp.write_json(result) +end + +function isSandboxCreated() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + result["isSandboxCreated"] = (0 == tonumber(os.execute(XQConfigs.LAMP_IS_SANDBOX_CREATED))) + LuciHttp.write_json(result) +end + +function areThingsMounted() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + result["areThingsMounted"] = (0 == tonumber(os.execute(XQConfigs.LAMP_ARE_THINGS_MOUNTED))) + LuciHttp.write_json(result) +end + +function isDropbearStarted() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + result["isDropbearStarted"] = (0 == tonumber(os.execute(XQConfigs.LAMP_IS_DROPBEAR_STARTED))) + LuciHttp.write_json(result) +end + +function stopNginx() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.NGINX_CACHE_STOP) + LuciHttp.write_json(result) +end + +function startNginx() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + LuciUtil.exec(XQConfigs.NGINX_CACHE_START) + LuciHttp.write_json(result) +end + +function nginxCacheStatus() + local LuciUtil = require("luci.util") + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local result = {} + result["code"] = 0 + result["status"] = 1 + local status = LuciUtil.exec(XQConfigs.NGINX_CACHE_STATUS) + if status then + result["status"] = LuciUtil.trim(status) == "NGINX_CACHE=off" and 0 or 1 + end + LuciHttp.write_json(result) +end + +function checkRouterNamePending() + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local cmd = XQConfigs.THRIFT_TO_MQTT_GET_DEVICEID + local LuciUtil = require("luci.util") + local result = {} + result["code"] = 0 + result['pending'] = XQSysUtil.getRouterNamePending() + result["routerId"] = LuciUtil.exec(cmd) + result['routerName'] = XQSysUtil.getRouterName() + LuciHttp.write_json(result) +end + +function clearRouterNamePending() + XQSysUtil.setRouterNamePending('0') + local result = {} + result["code"] = 0 + LuciHttp.write_json(result) +end + +function redirectUrl() + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + local cookieValue = LuciHttp.getcookie("psp") + local result = {} + result["code"] = 0 + if cookieValue then + local loginType = cookieValue:match("|||(%S)|||") + result["redirectUrl"] = "http://miwifi.com/cgi-bin/luci/web/home?redirectKey="..XQSecureUtil.generateRedirectKey(loginType) + else + result["redirectUrl"] = "http://miwifi.com/cgi-bin/luci/web/home?redirectKey="..XQSecureUtil.generateRedirectKey(2) + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function mainStatusForApp() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQDeviceUtil = require("xiaoqiang.util.XQDeviceUtil") + local XQZigbeeUtil = require("xiaoqiang.util.XQZigbeeUtil") + local result = {} + local lan = XQDeviceUtil.getWanLanNetworkStatistics("lan") + local wan = XQDeviceUtil.getWanLanNetworkStatistics("wan") + local count = XQFunction.thrift_tunnel_to_smarthome_controller([[{"command":"get_scene_count"}]]) + if count and count.code == 0 then + result["smartSceneCount"] = count.count + else + result["smartSceneCount"] = 0 + end + -- userdisk + local disk = XQFunction.thrift_tunnel_to_datacenter([[{"api":26}]]) + if disk and disk.code == 0 then + result["useableSpace"] = math.floor(tonumber(disk.free) / 1024) + else + result["useableSpace"] = 0 + end + -- plugin + local plugin = XQFunction.thrift_tunnel_to_datacenter([[{"api":601}]]) + if plugin and plugin.code == 0 then + result["installedPluginCount"] = #plugin.data + else + result["installedPluginCount"] = 0 + end + -- downloading + local downloads = 0 + local downloading = 0 + local download = XQFunction.thrift_tunnel_to_datacenter([[{"api":503}]]) + if download and download.code == 0 then + table.foreach(download.uncompletedList, + function(i,v) + downloads = downloads + 1 + if v.downloadStatus == 1 then + downloading = downloading + 1 + end + end + ) + end + -- zigbee + local zigbeecount = XQZigbeeUtil.get_zigbee_count(); + result["code"] = 0 + result["connectDeviceCount"] = zigbeecount + XQDeviceUtil.getConnectDeviceCount() + + + result["upTime"] = XQSysUtil.getSysUptime() + result["maxWanSpeed"] = tonumber(wan.maxdownloadspeed) + result["maxLanSpeed"] = tonumber(lan.maxdownloadspeed) + result["wanSpeed"] = tonumber(wan.downspeed) + result["lanSpeed"] = tonumber(lan.downspeed) + result["hasDownloading"] = downloading > 0 and 1 or 0 + result["downloadingCount"] = downloads + LuciHttp.write_json(result) +end + +--[[ + filter : lan/wan/admin +]]-- +function getMacfilterMode() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local code = 0 + local result = {} + + local filter = LuciHttp.formvalue("filter") or "lan" + local mode = XQSysUtil.getMacfilterMode(filter) + if mode then + result["mode"] = mode + else + code = 1574 + end + result["code"] = code + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +--[[ + filter : lan/wan/admin + mode : 0/1 (whitelist/blacklist) +]]-- +function setMacfilterMode() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local code = 0 + local result = {} + + local filter = LuciHttp.formvalue("filter") or "lan" + local mode = tonumber(LuciHttp.formvalue("mode") or 0) + local setMode = XQSysUtil.setMacfilterMode(filter,mode) + if not setMode then + code = 1575 + end + result["code"] = code + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function shutdown() + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + result["code"] = 0 + LuciHttp.write_json(result) + LuciHttp.close() + XQFunction.forkShutdown() +end + +function upnpList() + local XQUPnPUtil = require("xiaoqiang.util.XQUPnPUtil") + local result = {} + result["code"] = 0 + result["status"] = XQUPnPUtil.getUPnPStatus() and 1 or 0 + local upnp = XQUPnPUtil.getUPnPList() + if upnp then + result["list"] = upnp + else + result["list"] = {} + end + LuciHttp.write_json(result) +end + +function upnpSwitch() + local XQLog = require("xiaoqiang.XQLog") + local XQUPnPUtil = require("xiaoqiang.util.XQUPnPUtil") + local switch = tonumber(LuciHttp.formvalue("switch") or 1) + local result = {} + XQLog.check(0, XQLog.KEY_FUNC_UPNP, switch == 1 and 0 or 1) + XQUPnPUtil.switchUPnP(switch == 1) + result["code"] = 0 + LuciHttp.write_json(result) +end + +function appLimit() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local info = XQQoSUtil.appInfo() + info.code = 0 + LuciHttp.write_json(info) +end + +function appLimitSwitch() + local XQLog = require("xiaoqiang.XQLog") + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local switch = tonumber(LuciHttp.formvalue("switch") or 1) + local result = {} + XQLog.check(0, XQLog.KEY_FUNC_APPQOS, switch == 1 and 0 or 1) + XQQoSUtil.appSpeedlimitSwitch(switch == 1) + result["code"] = 0 + LuciHttp.write_json(result) +end + +function setAppLimit() + local XQQoSUtil = require("xiaoqiang.util.XQQoSUtil") + local result = {} + local xlmaxdownload = LuciHttp.formvalue("xlmaxdownload") + local xlmaxupload = LuciHttp.formvalue("xlmaxupload") + local kpmaxdownload = LuciHttp.formvalue("kpmaxdownload") + local kpmaxupload = LuciHttp.formvalue("kpmaxupload") + XQQoSUtil.setXunlei(xlmaxdownload, xlmaxupload) + XQQoSUtil.setKuaipan(kpmaxdownload, kpmaxupload) + XQQoSUtil.reload() + result["code"] = 0 + LuciHttp.write_json(result) +end + +function vpnInfo() + local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil") + local result = XQVPNUtil.getVPNInfo("vpn") + result["code"] = 0 + LuciHttp.write_json(result) +end + +function setVpn() + local XQLog = require("xiaoqiang.XQLog") + local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil") + local code = 0 + local result = {} + local server = LuciHttp.formvalue("server") + local username = LuciHttp.formvalue("username") + local password = LuciHttp.formvalue("password") + local proto = LuciHttp.formvalue("proto") + local auto = LuciHttp.formvalue("auto") + local set = XQVPNUtil.setVpn("vpn", server, username, password, proto, auto) + if proto and string.upper(proto) == "PPTP" then + XQLog.check(0, XQLog.KEY_FUNC_PPTP, 0) + elseif proto and string.upper(proto) == "L2TP" then + XQLog.check(0, XQLog.KEY_FUNC_L2TP, 0) + end + if set then + code = 0 + else + code = 1583 + end + result["code"] = code + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function _vpnErrorCodeHelper(code) + local errorA = { + ["507"] = 1,["691"] = 1,["509"] = 1,["514"] = 1,["520"] = 1, + ["646"] = 1,["647"] = 1,["648"] = 1,["649"] = 1,["691"] = 1, + ["646"] = 1 + } + local errorB = { + ["516"] = 1,["650"] = 1,["601"] = 1,["510"] = 1 + } + local errorC = { + ["501"] = 1,["502"] = 1,["503"] = 1,["504"] = 1,["505"] = 1, + ["506"] = 1,["507"] = 1,["508"] = 1,["511"] = 1,["512"] = 1, + ["515"] = 1,["517"] = 1,["518"] = 1,["519"] = 1 + } + local errcode = tostring(code) + if errcode then + if errorA[errcode] then + return 1584 + end + if errorB[errcode] then + return 1585 + end + if errorC[errcode] then + return 1586 + end + return 1584 + end +end + +-- status: 0 connected 1 connecting 2 failed 3 close 4 none +function vpnStatus() + local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil") + local status = XQVPNUtil.vpnStatus() + local result = {} + if status then + local up = status.up + local autostart = status.autostart + local uptime = tonumber(status.uptime) + local stat = status.stat + if up then + result["status"] = 0 + result["uptime"] = uptime + else + if autostart then + if stat and stat.code ~= 0 then + result["status"] = 2 + result["uptime"] = 0 + result["errcode"] = stat.code + result["errmsg"] = XQErrorUtil.getErrorMessage(_vpnErrorCodeHelper(stat.code)).." "..tostring(stat.code) + else + result["status"] = 1 + result["uptime"] = 0 + end + else + result["status"] = 3 + result["uptime"] = 0 + end + end + else + result["status"] = 4 + result["uptime"] = 0 + end + result["code"] = 0 + LuciHttp.write_json(result) +end + +function vpnSwitch() + local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil") + local conn = tonumber(LuciHttp.formvalue("conn")) + local result = {} + if conn and conn == 1 then + XQVPNUtil.vpnSwitch(true) + else + XQVPNUtil.vpnSwitch(false) + end + result["code"] = 0 + LuciHttp.write_json(result) +end + +function getDeviceMacaddr() + local remoteaddr = luci.http.getenv("REMOTE_ADDR") or "" + local result = {} + local code = 0 + if remoteaddr ~= "127.0.0.1" then + result["mac"] = luci.dispatcher.getremotemac() + else + code = 1587 + end + result["code"] = code + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function getDetectionTimestamp() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + result["code"] = 0 + result["timestamp"] = XQSysUtil.getDetectionTimestamp() + result["currentTime"] = tostring(os.time()) + LuciHttp.write_json(result) +end + +function getWifiLog() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local result = {} + XQSysUtil.getWifiLog() + result["code"] = 0 + LuciHttp.write_json(result) +end + +function sysRecovery() + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQWifiUtil = require("xiaoqiang.util.XQWifiUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local ssid = LuciHttp.formvalue("ssid") + local enc = LuciHttp.formvalue("enc") + local key = LuciHttp.formvalue("pwd") + local wanType = LuciHttp.formvalue("wanType") + local pppoeName = LuciHttp.formvalue("pppoeName") + local pppoePwd = LuciHttp.formvalue("pppoePwd") + if ssid then + XQWifiUtil.setWifiBasicInfo(1, ssid, key, enc, nil, nil, 0) + XQWifiUtil.setWifiBasicInfo(2, ssid.."_5G", key, enc, nil, nil, 0) + end + XQFunction.forkRestartWifi() + if wanType == "pppoe" then + XQLanWanUtil.setWanPPPoE(pppoeName,pppoePwd,nil,nil,nil) + elseif wanType == "dhcp" then + XQLanWanUtil.setWanStaticOrDHCP(wanType,nil,nil,nil,nil,nil,nil) + end + local result = {} + result["code"] = 0 + LuciHttp.write_json(result) +end +--flag定时wifi开关 +function smartShutdown() + local XQFunction = require("xiaoqiang.common.XQFunction") + local result = {} + local code = 0 + local delay1 = LuciHttp.formvalue("delay1") + local delay2 = LuciHttp.formvalue("delay2") + if delay1 and delay2 then + XQFunction.forkShutdownAndRebootWithDelay(delay1, delay2) + else + code = 1502 + end + result["code"] = code + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function getNofStatus() + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local status = tonumber(XQSysUtil.noflushdStatus()) + if status == 0 then + status = 1 + else + status = 0 + end + local result = { + ["code"] = 0, + ["status"] = status + } + LuciHttp.write_json(result) +end + +function nofSwitch() + local XQLog = require("xiaoqiang.XQLog") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local switch = tonumber(LuciHttp.formvalue("switch")) or 0 + local result = {} + local success = XQSysUtil.noflushdSwitch(switch == 1 and true or false) + XQLog.check(0, XQLog.KEY_FUNC_NOFLUSHED, switch == 1 and 0 or 1) + if switch == 1 then + XQLog.check(0, XQLog.KEY_DISKSLEEP_OPEN, 1) + else + XQLog.check(0, XQLog.KEY_DISKSLEEP_CLOSE, 1) + end + if success then + result["code"] = 0 + else + result["code"] = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end + +function predownloadInfo() + local Predownload = require("xiaoqiang.module.XQPredownload") + local result = {} + local info = Predownload.predownloadInfo() + result["code"] = 0 + result["status"] = info.enable + result["priority"] = info.priority + LuciHttp.write_json(result) +end + +function predownloadSwitch() + local Predownload = require("xiaoqiang.module.XQPredownload") + local switch = tonumber(LuciHttp.formvalue("switch")) or 0 + local result = {} + local success = Predownload.switch(switch == 1 and true or false) + if success then + result["code"] = 0 + else + result["code"] = 1606 + end + if result.code ~= 0 then + result["msg"] = XQErrorUtil.getErrorMessage(result.code) + end + LuciHttp.write_json(result) +end diff --git a/1_1.mi_Lua/luci/controller/api/xqtunnel.lua b/1_1.mi_Lua/luci/controller/api/xqtunnel.lua new file mode 100644 index 0000000..87e348e --- /dev/null +++ b/1_1.mi_Lua/luci/controller/api/xqtunnel.lua @@ -0,0 +1,53 @@ +module("luci.controller.api.xqtunnel", package.seeall) + +function index() + local page = node("api","xqtunnel") + page.target = firstchild() + page.title = ("") + page.order = 300 + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"api", "xqtunnel", "request"}, call("tunnelRequest"), _(""), 301) +end + +local LuciHttp = require("luci.http") +local XQConfigs = require("xiaoqiang.common.XQConfigs") + +local base64chars = { + ['A']=true,['B']=true,['C']=true,['D']=true, + ['E']=true,['F']=true,['G']=true,['H']=true, + ['I']=true,['J']=true,['K']=true,['L']=true, + ['M']=true,['N']=true,['O']=true,['P']=true, + ['Q']=true,['R']=true,['S']=true,['T']=true, + ['U']=true,['V']=true,['W']=true,['X']=true, + ['Y']=true,['Z']=true,['a']=true,['b']=true, + ['c']=true,['d']=true,['e']=true,['f']=true, + ['g']=true,['h']=true,['i']=true,['j']=true, + ['k']=true,['l']=true,['m']=true,['n']=true, + ['o']=true,['p']=true,['q']=true,['r']=true, + ['s']=true,['t']=true,['u']=true,['v']=true, + ['w']=true,['x']=true,['y']=true,['z']=true, + ['0']=true,['1']=true,['2']=true,['3']=true, + ['4']=true,['5']=true,['6']=true,['7']=true, + ['8']=true,['9']=true,['-']=true,['_']=true, + ['+']=true,['/']=true,['=']=true +} + +local function base64filter(input) + local result = "" + for i = 1, #input do + local c = input:sub(i,i) + if base64chars[c] ~= nil and base64chars[c] then + result = result .. c + end + end + return result +end + +function tunnelRequest() + local payload = LuciHttp.formvalue("payloadB64") + local cmd = XQConfigs.TUNNEL_TOOL % base64filter(payload) + local LuciUtil = require("luci.util") + LuciHttp.write(LuciUtil.exec(cmd)) +end diff --git a/1_1.mi_Lua/luci/controller/dispatch/index.lua b/1_1.mi_Lua/luci/controller/dispatch/index.lua new file mode 100644 index 0000000..24eabdd --- /dev/null +++ b/1_1.mi_Lua/luci/controller/dispatch/index.lua @@ -0,0 +1,18 @@ +module("luci.controller.dispatch.index", package.seeall) + +function index() + local root = node() + if not root.target then + root.target = alias("dispatch") + root.index = true + end + local page = node("dispatch") + page.target = firstchild() + page.title = _("") + page.order = 1 + page.sysauth = "admin" + page.mediaurlbase = "/xiaoqiang/dispatch" + page.sysauth_authenticator = "htmlauth" + page.index = true + entry({"dispatch"}, template("index"), _("跳转"), 1, 0x09) +end \ No newline at end of file diff --git a/1_1.mi_Lua/luci/controller/firewall.lua b/1_1.mi_Lua/luci/controller/firewall.lua new file mode 100644 index 0000000..51f05b3 --- /dev/null +++ b/1_1.mi_Lua/luci/controller/firewall.lua @@ -0,0 +1,23 @@ +module("luci.controller.firewall", package.seeall) + +function index() +-- entry({"admin", "network", "firewall"}, +-- alias("admin", "network", "firewall", "zones"), +-- _("Firewall"), 60) +-- +-- entry({"admin", "network", "firewall", "zones"}, +-- arcombine(cbi("firewall/zones"), cbi("firewall/zone-details")), +-- _("General Settings"), 10).leaf = true +-- +-- entry({"admin", "network", "firewall", "forwards"}, +-- arcombine(cbi("firewall/forwards"), cbi("firewall/forward-details")), +-- _("Port Forwards"), 20).leaf = true +-- +-- entry({"admin", "network", "firewall", "rules"}, +-- arcombine(cbi("firewall/rules"), cbi("firewall/rule-details")), +-- _("Traffic Rules"), 30).leaf = true +-- +-- entry({"admin", "network", "firewall", "custom"}, +-- cbi("firewall/custom"), +-- _("Custom Rules"), 40).leaf = true +end diff --git a/1_1.mi_Lua/luci/controller/mobile/index.lua b/1_1.mi_Lua/luci/controller/mobile/index.lua new file mode 100644 index 0000000..3e8ba3f --- /dev/null +++ b/1_1.mi_Lua/luci/controller/mobile/index.lua @@ -0,0 +1,32 @@ +module("luci.controller.mobile.index", package.seeall) +function index() + local root = node() + if not root.target then + root.target = alias("mobile") + root.index = true + end + local page = node("mobile") + page.target = firstchild() + page.title = _("") + page.order = 110 + page.sysauth = "admin" + page.mediaurlbase = "/xiaoqiang/mobile" + page.sysauth_authenticator = "htmlauth_moblie" + page.index = true + entry({"mobile"}, template("mobile/home"), _("首页"), 1, 0x08) + entry({"mobile", "logout"}, call("action_logout"), 2, 0x09) + entry({"mobile", "hello"}, template("mobile/init/hello"), _("初始化欢迎界面"), 3, 0x09) + entry({"mobile", "agreement"}, template("mobile/init/agreement"), _("查看协议"), 4, 0x09) + entry({"mobile", "guide"}, template("mobile/init/guide"), _("初始化引导"), 5, 0x08) +end + +function action_logout() + local dsp = require "luci.dispatcher" + local sauth = require "luci.sauth" + if dsp.context.authsession then + sauth.kill(dsp.context.authsession) + dsp.context.urltoken.stok = nil + end + luci.http.header("Set-Cookie", "sysauth=; path=" .. dsp.build_url()) + luci.http.redirect(luci.dispatcher.build_url().."/mobile") +end diff --git a/1_1.mi_Lua/luci/controller/service/datacenter.lua b/1_1.mi_Lua/luci/controller/service/datacenter.lua new file mode 100644 index 0000000..c12f14a --- /dev/null +++ b/1_1.mi_Lua/luci/controller/service/datacenter.lua @@ -0,0 +1,382 @@ +module("luci.controller.service.datacenter", package.seeall) + +function index() + local page = node("service","datacenter") + page.target = firstchild() + page.title = ("") + page.order = nil + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true + entry({"service", "datacenter", "download_file"}, call("downloadFile"), _(""), nil, 0x11) + entry({"service", "datacenter", "device_id"}, call("getDeviceID"), _(""), nil, 0x11) + entry({"service", "datacenter", "download_info"}, call("getDownloadInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "upload_file"}, call("uploadFile"), _(""), nil, 0x11) + entry({"service", "datacenter", "batch_download_info"}, call("getBatchDownloadInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "config_info"}, call("getConfigInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "set_config"}, call("setConfigInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "plugin_enable"}, call("enablePlugin"), _(""), nil, 0x11) + entry({"service", "datacenter", "plugin_download_info"}, call("pluginDownloadInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "plugin_disable"}, call("disablePlugin"), _(""), nil, 0x11) + entry({"service", "datacenter", "plugin_control"}, call("controlPlugin"), _(""), nil, 0x11) + entry({"service", "datacenter", "download_delete"}, call("deleteDownload"), _(""), nil, 0x11) + entry({"service", "datacenter", "get_plugin_status"}, call("pluginStatus"), _(""), nil, 0x11) + entry({"service", "datacenter", "get_connected_device"}, call("connectedDevice"), _(""), nil, 0x11) + entry({"service", "datacenter", "get_router_mac"}, call("getMac"), _(""), nil, 0x11) + entry({"service", "datacenter", "set_wan_access"}, call("setWanAccess"), _(""), nil, 0x11) + entry({"service", "datacenter", "get_router_info"}, call("getRouterInfo"), _(""), nil, 0x11) + entry({"service", "datacenter", "xunlei_notify"}, call("xunleiNotify"), _(""), nil, 0x11) +end + +local LuciHttp = require("luci.http") +local XQConfigs = require("xiaoqiang.common.XQConfigs") +local ServiceErrorUtil = require("service.util.ServiceErrorUtil") + +function xunleiNotify() + local payload = {} + payload["api"] = 519 + payload["info"] = LuciHttp.formvalue("tasks") + tunnelRequestDatacenter(payload) +end + +function tunnelRequestDatacenter(payload) + local LuciJson = require("cjson") + local LuciUtil = require("luci.util") + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + payload = LuciJson.encode(payload) + payload = XQCryptoUtil.binaryBase64Enc(payload) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_DATACENTER % payload + LuciHttp.write(LuciUtil.exec(cmd)) +end + +function requestDatacenter(payload) + local LuciJson = require("cjson") + local LuciUtil = require("luci.util") + local XQCryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + payload = LuciJson.encode(payload) + payload = XQCryptoUtil.binaryBase64Enc(payload) + local cmd = XQConfigs.THRIFT_TUNNEL_TO_DATACENTER % payload + return LuciUtil.exec(cmd) +end + +function downloadFile() + local payload = {} + payload["api"] = 1101 + payload["appid"] = LuciHttp.formvalue("appId") + payload["path"] = LuciHttp.formvalue("path") + payload["url"] = LuciHttp.formvalue("url") + payload["name"] = LuciHttp.formvalue("downloadName") + payload["tag"] = LuciHttp.formvalue("tag") + payload["hidden"] = false + if LuciHttp.formvalue("hidden") == "true" then + payload["hidden"] = true + end + + payload["redownload"] = 0 + if LuciHttp.formvalue("redownload") == "1" then + payload["redownload"] = 1 + end + + payload["dupId"] = LuciHttp.formvalue("dupId") + tunnelRequestDatacenter(payload) +end + +function setWanAccess() + local payload = {} + payload["api"] = 618 + payload["appid"] = LuciHttp.formvalue("appId") + payload["mac"] = LuciHttp.formvalue("mac") + payload["enable"] = false + if LuciHttp.formvalue("enable") == "true" then + payload["enable"] = true + end + tunnelRequestDatacenter(payload) +end + +function getDeviceID() + local payload = {} + payload["api"] = 1103 + payload["appid"] = LuciHttp.formvalue("appId") + tunnelRequestDatacenter(payload) +end + +function getMac() + local payload = {} + payload["api"] = 617 + payload["appid"] = LuciHttp.formvalue("appId") + tunnelRequestDatacenter(payload) +end + +function getRouterInfo() + local payload = {} + payload["api"] = 622 + payload["appid"] = LuciHttp.formvalue("appId") + tunnelRequestDatacenter(payload) +end + +function getOperateDeviceID() + local payload = {} + payload["api"] = 1103 + payload["appid"] = LuciHttp.formvalue("appId") + + local result = requestDatacenter(payload) + if result then + local LuciJson = require("cjson") + result = LuciJson.decode(result) + if result then + if result.code == 0 then + local deviceid = result["deviceid"] + if deviceid then + return 0, deviceid + end + elseif result.code == 5 then + return 5, nil + end + end + end + + return 1559, nil +end + +function urlEncode(url) + if url then + url = string.gsub(url, "\n", "\r\n") + url = string.gsub(url, "([^0-9a-zA-Z/])", + function(c) return string.format ("%%%02X", string.byte(c)) end) + end + return url +end + +function generateUrlFromPath(path) + if path then + path = urlEncode(path) + local url, count = string.gsub (path, "^/userdisk/data/", "http://miwifi.com/api-third-party/download/public/") + if count == 1 then + return url + end + + url, count = string.gsub (path, "^/userdisk/appdata/", "http://miwifi.com/api-third-party/download/private/") + if count == 1 then + return url + end + + url, count = string.gsub (path, "^/extdisks/", "http://miwifi.com/api-third-party/download/extdisks/") + if count == 1 then + return url + end + end + + return nil +end + +function generateResponseFromCode(code) + local response = {} + response["code"] = code + response["msg"] = ServiceErrorUtil.getErrorMessage(code) + return response +end + +function getDownloadInfo() + local LuciJson = require("cjson") + local payload = {} + payload["api"] = 1102 + payload["appid"] = LuciHttp.formvalue("appId") + payload["deviceId"] = LuciHttp.formvalue("deviceId") + payload["downloadId"] = LuciHttp.formvalue("downloadId") + payload["hidden"] = false + if LuciHttp.formvalue("hidden") == "true" then + payload["hidden"] = true + end + + local response = {} + local result = requestDatacenter(payload) + if result then + result = LuciJson.decode(result) + if result and result.code == 0 then + local url = generateUrlFromPath(result["path"]) + if url then + response["code"] = result["code"] + response["msg"] = result["msg"] + response["url"] = url + else + response = generateResponseFromCode(1559) + end + else + response = result + end + else + response = generateResponseFromCode(1559) + end + + LuciHttp.write_json(response) + LuciHttp.close() +end + +function uploadFile() + local fp + local log = require("xiaoqiang.XQLog") + local fs = require("luci.fs") + local tmpfile = "/userdisk/upload.tmp" + if fs.isfile(tmpfile) then + fs.unlink(tmpfile) + end + + local filename + LuciHttp.setfilehandler( + function(meta, chunk, eof) + if not fp then + if meta and meta.name == "file" then + fp = io.open(tmpfile, "w") + filename = meta.file + filename = string.gsub(filename, "+", " ") + filename = string.gsub(filename, "%%(%x%x)", + function(h) + return string.char(tonumber(h, 16)) + end) + filename = filename.gsub(filename, "\r\n", "\n") + end + end + if chunk then + fp:write(chunk) + end + if eof then + fp:close() + end + end + ) + + local code, deviceId = getOperateDeviceID() + if code ~= 0 then + return LuciHttp.write_json(generateResponseFromCode(code)) + end + + local path + local appid = LuciHttp.formvalue("appId") + local saveType = LuciHttp.formvalue("saveType") + if saveType == "public" then + path = "/userdisk/data/上传/" + elseif saveType == "private" then + path = "/userdisk/appdata/" .. appid .. "/" + else + return LuciHttp.write_json(generateResponseFromCode(3)) + end + fs.mkdir(path, true) + + local savename = fs.basename(filename) + if fs.isfile(path .. savename) then + local basename = savename + local index = basename:match(".+()%.%w+$") + if index then + basename = basename:sub(1, index - 1) + end + + local extension = savename:match(".+%.(%w+)$") + for i = 1, 100, 1 do + local tmpname = basename .. "(" .. i .. ")" + if extension then + tmpname = tmpname .. "." .. extension + end + if not fs.isfile(path .. tmpname) then + savename = tmpname + break + end + end + end + local dest = path .. savename + log.log("dest=" .. dest) + fs.rename(tmpfile, dest) + + local response = {} + response["code"] = 0 + response["url"] = generateUrlFromPath(dest) + response["deviceId"] = deviceId + response["msg"] = "" + LuciHttp.write_json(response) + LuciHttp.close() +end + +function getBatchDownloadInfo() + local payload = {} + payload["api"] = 1105 + payload["appid"] = LuciHttp.formvalue("appId") + payload["ids"] = LuciHttp.formvalue("ids") + payload["hidden"] = false + if LuciHttp.formvalue("hidden") == "true" then + payload["hidden"] = true + end + tunnelRequestDatacenter(payload) +end + +function getConfigInfo() + local payload = {} + payload["api"] = 1106 + payload["appid"] = LuciHttp.formvalue("appId") + payload["key"] = LuciHttp.formvalue("key") + tunnelRequestDatacenter(payload) +end +function connectedDevice() + local payload = {} + payload["api"] = 616 + payload["appid"] = LuciHttp.formvalue("appId") + tunnelRequestDatacenter(payload) +end +function setConfigInfo() + local payload = {} + payload["api"] = 1107 + payload["appid"] = LuciHttp.formvalue("appId") + payload["key"] = LuciHttp.formvalue("key") + payload["value"] = LuciHttp.formvalue("value") + tunnelRequestDatacenter(payload) +end +function enablePlugin() + local payload = {} + payload["api"] = 1108 + payload["appid"] = LuciHttp.formvalue("appId") + payload["status"] = 5 + tunnelRequestDatacenter(payload) +end +function disablePlugin () + local payload = {} + payload["api"] = 1108 + payload["appid"] = LuciHttp.formvalue("appId") + payload["status"] = 6 + tunnelRequestDatacenter(payload) +end +function controlPlugin() + local payload = {} + payload["api"] = 600 + payload["pluginID"] = LuciHttp.formvalue("appId") + payload["info"] = LuciHttp.formvalue("info") + tunnelRequestDatacenter(payload) +end +function deleteDownload() + local payload = {} + payload["api"] = 1110 + payload["appid"] = LuciHttp.formvalue("appId") + payload["idList"] = LuciHttp.formvalue("idList") + payload["deletefile"] = false + if LuciHttp.formvalue("deletefile") == "true" then + payload["deletefile"] = true + end + tunnelRequestDatacenter(payload) +end +function pluginStatus() + local payload = {} + payload["api"] = 1111 + payload["appid"] = LuciHttp.formvalue("appId") + tunnelRequestDatacenter(payload) +end +function pluginDownloadInfo() + local payload = {} + payload["api"] = 1109 + payload["appid"] = LuciHttp.formvalue("appId") + payload["hidden"] = false + if LuciHttp.formvalue("hidden") == "true" then + payload["hidden"] = true + end + payload["lite"] = false + if LuciHttp.formvalue("lite") == "true" then + payload["lite"] = true + end + tunnelRequestDatacenter(payload) +end diff --git a/1_1.mi_Lua/luci/controller/service/index.lua b/1_1.mi_Lua/luci/controller/service/index.lua new file mode 100644 index 0000000..8763c1a --- /dev/null +++ b/1_1.mi_Lua/luci/controller/service/index.lua @@ -0,0 +1,10 @@ +module("luci.controller.service.index", package.seeall) +function index() + local page = node("service") + page.target = firstchild() + page.title = _("") + page.order = nil + page.sysauth = "admin" + page.sysauth_authenticator = "jsonauth" + page.index = true +end diff --git a/1_1.mi_Lua/luci/controller/web/index.lua b/1_1.mi_Lua/luci/controller/web/index.lua new file mode 100644 index 0000000..c53e96a --- /dev/null +++ b/1_1.mi_Lua/luci/controller/web/index.lua @@ -0,0 +1,96 @@ +module("luci.controller.web.index", package.seeall) + +function index() + local root = node() + if not root.target then + root.target = alias("web") + root.index = true + end + local page = node("web") + page.target = firstchild() + page.title = _("") + page.order = 10 + page.sysauth = "admin" + page.mediaurlbase = "/xiaoqiang/web" + page.sysauth_authenticator = "htmlauth" + page.index = true + entry({"web"}, template("web/index"), _("路由器状态"), 10, 0x08) + entry({"web", "home"}, template("web/index"), _("路由器状态"), 70, 0x08) + entry({"web", "manager"}, template("web/manager"), _("终端管理"), 71) + --entry({"web", "plugin"}, template("web/plugin"), _("插件管理"), 72) + --entry({"web", "plugin", "kuaipan"}, template("web/plugins/kuaipan"), _("插件管理_快盘"), 72) + --entry({"web", "plugin", "guest"}, template("web/plugins/guest"), _("插件管理_访客"), 72) + entry({"web", "logout"}, call("action_logout"), 11, 0x09) + entry({"web", "init"}, template("web/init/hello"), _("初始化引导"), 190, 0x09) + entry({"web", "init", "hello"}, template("web/init/hello"), _("欢迎界面"), 198, 0x09) --不需要登录 + entry({"web", "init", "agreement"}, template("web/init/agreement"), _("用户协议"), 198, 0x09) --不需要登录 + entry({"web", "init", "guide"}, template("web/init/guide"), _("引导模式"), 190, 0x08) + + entry({"web", "netset"}, template("web/netset"), _("路由设置"), 73) + entry({"web", "sysset"}, template("web/sysset"), _("路由设置"), 73) + entry({"web", "sysset", "passport"}, template("web/setting/passport"), _("路由器权限"), 18) + entry({"web", "sysset", "reboot"}, template("web/setting/reboot"), _("重启路由器"), 73) + entry({"web", "sysset", "reset"}, template("web/setting/reset"), _("恢复出厂设置"), 73) + + entry({"web", "netset", "wifi"}, template("web/setting/wifi_set"), _("WIFI网络设置"), 20) + entry({"web", "netset", "wifi_mini"}, template("web/setting/wifi_set_mini"), _("WIFI网络快捷设置"), 20) + entry({"web", "netset", "wifi_pro"}, template("web/setting/wifi_set_pro"), _("WIFI网络高级设置"), 60) + entry({"web", "netset", "wifi_txpwr"}, template("web/setting/wifi_txpwr"), _("WIFI强度设置"), 60) + entry({"web", "netset", "wifi_filter"}, template("web/setting/wifi_filter"), _("WIFI访问控制"), 60) + + entry({"web", "netset" ,"net_wan"}, template("web/setting/net_wan"), _("网络设置WAN"), 20) + entry({"web", "netset", "net_lan"}, template("web/setting/net_lan"), _("网络设置LAN"), 30) + entry({"web", "netset", "mac"}, template("web/setting/net_setup_mac"), _("mac 设置"), 40) + entry({"web", "netset", "ipmacband"}, template("web/setting/net_ipmacband"), _("mac 设置"), 40) + entry({"web", "sysset", "qos_pro"}, template("web/setting/qos_pro"), _("QoS 设置"), 40) + + + entry({"web", "sysset", "upgrade"}, template("web/setting/upgrade"), _("路由器固件升级"), 198, 0x01) + entry({"web", "sysset", "upgrade_manual"}, template("web/setting/upgrade_manual", _("路由器手动升级"), 200)) + entry({"web", "sysset", "log"}, template("web/setting/log", _("上传日志"), 201)) + --entry({"web", "sysset", "upload_config"}, template("web/setting/upload_config"), _("上传配置信息"), 202) + + --entry({"web", "setting", "sys_psp"}, template("web/setting/sys_psp"), _("管理小米账号"), 73) + entry({"web", "sysset", "sys_status"}, template("web/setting/sys_status"), _("系统状态"), 73) + + entry({"web", "sysset", "diskformat"}, template("web/setting/diskformat"), _("格式化小强盘"), 202) + entry({"web", "sysset", "nginx"}, template("web/setting/nginx"), _("关闭NGINX"), 203) + entry({"web", "sysset", "upnp"}, template("web/setting/upnp"), _("upnp"), 204) + -- entry({"web", "sysset", "lamp"}, template("web/setting/lamp"), _("LAMP Settings"), 204) + entry({"web", "sysset", "qos"}, template("web/setting/qos"), _("应用限速"), 204) + entry({"web", "sysset", "vpn"}, template("web/setting/vpn"), _("VPN"), 204) + + entry({"web", "sysset", "developer"}, template("web/setting/developer"), _("开发者选项"), 205) + entry({"web", "sysset", "dmz"}, template("web/setting/dmz"), _("DMZ"), 205) + entry({"web", "sysset", "ddns"}, template("web/setting/ddns"), _("DDNS"), 204) + entry({"web", "sysset", "nat"}, template("web/setting/nat"), _("端口转发"), 206) + entry({"web", "sysset", "noflushd"}, template("web/setting/noflushd"), _("磁盘休眠"), 207) + --entry({"web", "sysset", "predownload"}, template("web/setting/predownload"), _("预下载"), 208) + + entry({"web", "detecte"}, template("web/netdetection"), _("网络检测"), 74, 0x01) + entry({"web", "detecte_pro"}, template("web/urldetection"), _("网络高级检测"), 75, 0x01) + entry({"web", "xmaccount"}, template("web/xmaccount"), _("小米帐号验证"), 75, 0x01) + -- entry({"web", "safeurl"}, call("action_safeurl"), _(""), 75, 0x09) + + entry({"web", "webinitrdr"}, template("web/init/webinitrdr"), _("劫持页面"), 300, 0x09) --不需要登录 +end +function action_logout() + local dsp = require "luci.dispatcher" + local sauth = require "luci.sauth" + if dsp.context.authsession then + sauth.kill(dsp.context.authsession) + dsp.context.urltoken.stok = nil + end + luci.http.header("Set-Cookie", "sysauth=; path=" .. dsp.build_url()) + luci.http.header("Set-Cookie", "autologin_v2=;expires=-1;path=/;") + luci.http.redirect(luci.dispatcher.build_url()) +end + +function action_safeurl() + + local safeUrl = luci.http.formvalue("safeurl") + require("luci.template") + luci.template.render("web/safeurl", {safeurl=safeUrl}) + +end + diff --git a/1_1.mi_Lua/luci/datacentertunnel.so b/1_1.mi_Lua/luci/datacentertunnel.so new file mode 100644 index 0000000..3dc058c Binary files /dev/null and b/1_1.mi_Lua/luci/datacentertunnel.so differ diff --git a/1_1.mi_Lua/luci/debug.lua b/1_1.mi_Lua/luci/debug.lua new file mode 100644 index 0000000..8ff1bb6 --- /dev/null +++ b/1_1.mi_Lua/luci/debug.lua @@ -0,0 +1,37 @@ +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/1_1.mi_Lua/luci/dispatcher.lua b/1_1.mi_Lua/luci/dispatcher.lua new file mode 100644 index 0000000..c02413d --- /dev/null +++ b/1_1.mi_Lua/luci/dispatcher.lua @@ -0,0 +1,1037 @@ +--[[ +LuCI - Dispatcher + +Description: +The request dispatcher and module dispatcher generators + +FileId: +$Id: dispatcher.lua 9018 2012-08-14 15:31:26Z jow $ + +License: +Copyright 2008 Steven Barth + +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 bit = require("bit") +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" + +local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + +module("luci.dispatcher", package.seeall) +context = util.threadlocal() +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) + local logger = require("xiaoqiang.XQLog") + logger.log(3, "Internal Server Error", message) + message = "Internal Server Error" + 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 empower(lan,wan,admin) + local XQFunction = require("xiaoqiang.common.XQFunction") + local remoteAddr = luci.http.getenv("REMOTE_ADDR") + local mac = XQFunction.macFormat(luci.sys.net.ip4mac(remoteAddr)) + if not XQFunction.isStrNil(mac) then + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + if not XQSysUtil.setMacFilter(mac,lan,wan,admin) then + local XQLog = require("xiaoqiang.XQLog") + XQLog.log(3,"Empower failed"..mac) + end + end +end + +function getremotemac() + local XQFunction = require("xiaoqiang.common.XQFunction") + local remote_addr = luci.http.getenv("REMOTE_ADDR") or "" + local mac = luci.sys.net.ip4mac(remote_addr) or "" + return XQFunction.macFormat(mac) +end + +-- TODO auth will be found similar +function authenticator.jsonauth(validator, accs, default) + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + + local user = luci.http.xqformvalue("username") + local pass = luci.http.xqformvalue("password") + local nonce = luci.http.xqformvalue("nonce") + local uuid = luci.http.xqformvalue("uuid") + local token = luci.http.xqformvalue("token") + local isBinded = XQSysUtil.getPassportBindInfo() + + if isBinded and uuid and token and (uuid == isBinded) then + local XQDBUtil = require("xiaoqiang.util.XQDBUtil") + local passport = XQDBUtil.fetchPassport(uuid)[1] + if passport and token == passport.token then + empower("1","1",nil) + local logtype = "1" + luci.http.header("Set-Cookie", "psp=" .. uuid .. "|||" .. logtype .. "|||" .. token .. ";path=/;") + return default, logtype + end + end + + if nonce then + if XQSecureUtil.checkNonce(nonce, getremotemac()) then + if XQSecureUtil.checkUser(user, nonce, pass) then + empower("1","1",nil) + local logtype = "2" + luci.http.header("Set-Cookie", "psp=" .. user .. "|||" .. logtype .. "|||0;path=/;") + return user, logtype + end + else + context.path = {} + luci.http.write([[{"code":1582,"msg":"nonce invalid"}]]) + return false + end + else + if XQSecureUtil.checkPlaintextPwd(user, pass) then + empower("1","1",nil) + local logtype = "2" + luci.http.header("Set-Cookie", "psp=" .. user .. "|||" .. logtype .. "|||0;path=/;") + return user, logtype + else + context.path = {} + luci.http.write([[{"code":401,"msg":"密码错误"}]]) + return false + end + end + context.path = {} + luci.http.write([[{"code":401,"msg":"not auth"}]]) + return false +end + +function authenticator.htmlauth(validator, accs, default) + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local redirectKey = luci.http.xqformvalue("redirectKey") + local isBinded = XQSysUtil.getPassportBindInfo() + + if redirectKey then + local check = XQSecureUtil.checkRedirectKey(redirectKey) + if check then + if check == "1" and isBinded then + local XQDBUtil = require("xiaoqiang.util.XQDBUtil") + local bindUUID = XQSysUtil.getBindUUID() + local passport = XQDBUtil.fetchPassport(bindUUID)[1] + if passport then + luci.http.header("Set-Cookie", "psp=" .. bindUUID .. "|||1|||" .. passport.token .. ";path=/;") + return default, check + end + elseif check == "2" then + luci.http.header("Set-Cookie", "psp=admin|||2|||0;path=/;") + return "admin", check + end + end + end + require("luci.i18n") + require("luci.template") + context.path = {} + luci.template.render("web/sysauth", {duser=default, fuser=user}) + return false +end + +function authenticator.htmlauth_moblie(validator, accs, default) + local user = luci.http.xqformvalue("username") + local pass = luci.http.xqformvalue("password") + local nonce = luci.http.xqformvalue("nonce") + if nonce then + if XQSecureUtil.checkNonce(nonce, getremotemac()) and XQSecureUtil.checkUser(user, nonce, pass) then + empower("1","1",nil) + return user, "2" + end + end + require("luci.i18n") + require("luci.template") + context.path = {} + luci.template.render("mobile/sysauth", {duser=default, fuser=user}) + return false +end + +function check_show_syslock(sysauth) + local XQFunction = require("xiaoqiang.common.XQFunction") + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + + if XQFunction.sysLockStatus() == 1 then + if XQSysUtil.isUpgrading() then + require("luci.i18n") + require("luci.template") + if type(sysauth) == "string" and sysauth == "htmlauth" then + context.path = {} + luci.template.render("web/syslock",{}) + elseif type(sysauth) == "string" and sysauth == "jsonauth" then + context.path = {} + luci.http.write([[{"code":403,"msg":"system locked"}]]) + else + XQFunction.sysUnlock() + return false + end + return true + else + XQFunction.sysUnlock() + end + end + return false +end + +function http_request_log(request, tag) + local XQLog = require("xiaoqiang.XQLog") + local requestUri = request:getenv("REQUEST_URI") + if requestUri and tag and type(tag) == "string" then + local uriInfo = luci.util.split(requestUri,"?") + XQLog.log(6,tag..":"..uriInfo[1]) + if uriInfo[2] then + XQLog.log(7,uriInfo[2]) + end + end +end + +-- API Permissions +function _noauthAccessAllowed(flag) + if flag == nil then + return false + end + if bit.band(flag, 0x01) == 0x01 then + return true + else + return false + end +end + +function _remoteAccessForbidden(flag) + if flag == nil then + return false + end + if bit.band(flag, 0x02) == 0x02 then + return true + else + return false + end +end + +function _syslockAccessAllowed(flag) + if flag == nil then + return false + end + if bit.band(flag, 0x04) == 0x04 then + return true + else + return false + end +end + +function _noinitAccessAllowed(flag) + local xqsys = require("xiaoqiang.util.XQSysUtil") + if xqsys.getInitInfo() then + return true + else + if flag == nil then + return false + end + if bit.band(flag, 0x08) == 0x08 then + return true + else + return false + end + end +end + +function _sdkFilter(flag) + if flag == nil then + return false + end + if bit.band(flag, 0x10) == 0x10 then + return true + else + return false + end +end + +--- Dispatch an HTTP request. +-- @param request LuCI HTTP Request object +function httpdispatch(request, prefix) + http_request_log(request, "request") + -- 设置全局表,使 _() 使用当前文件内的 _函数,即为标记tag, translate 可以直接使用翻译 + _G._ = _ + _G.translate = i18n.translate + 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() + http_request_log(request, "finished") +end + +--- Dispatches a LuCI virtual path. +-- @param request Virtual path +function dispatch(request) + 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; + 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 not _syslockAccessAllowed(track.flag) then + if check_show_syslock(track.sysauth_authenticator) then + return + end + end + if not _noinitAccessAllowed(track.flag) then + luci.http.status(403, "Forbidden") + return + end + local isremote = http.getenv("REMOTE_ADDR") == "127.0.0.1" + if _sdkFilter(track.flag) and not isremote then + local sdkutil = require("xiaoqiang.util.XQSDKUtil") + if not sdkutil.checkPermission(getremotemac()) then + context.path = {} + luci.http.write([[{"code":1500,"msg":"Permission denied"}]]) + return + end + end + if not isremote and not _noauthAccessAllowed(track.flag) and track.sysauth then + local sauth = require "luci.sauth" + local crypto = require "xiaoqiang.util.XQCryptoUtil" + local sysutil = require "xiaoqiang.util.XQSysUtil" + local isBinded = sysutil.getPassportBindInfo() + + 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.urltoken.stok + local sdat = sauth.read(sess) + local user + if sdat then + if ctx.urltoken.stok == sdat.token then + if (sdat.ltype == "2" or (sdat.ltype == "1" and isBinded)) then + user = sdat.user + end + 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, logintype = authen(nil, accs, def) + if not user or not util.contains(accs, user) then + return + else + local sid = sess or luci.sys.uniqueid(16) + local ltype = logintype or "2" + local token = luci.sys.uniqueid(16) + sauth.reap() + sauth.write(token, { + user=user, + token=token, + ltype=ltype, + secret=luci.sys.uniqueid(16) + }) + ctx.urltoken.stok = token + ctx.authsession = token + 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) +-- @param flag For extension (optional) +-- @return Dispatching tree node +function assign(path, clone, title, order, flag) + local obj = node(unpack(path)) + obj.nodes = nil + obj.module = nil + + obj.title = title + obj.order = order + obj.flag = flag + + 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) +-- @param flag For extension (optional) +-- @return Dispatching tree node +function entry(path, target, title, order, flag) + local c = node(unpack(path)) + + c.target = target + c.title = title + c.order = order + c.flag = flag + 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 _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 + +--- 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 \ No newline at end of file diff --git a/1_1.mi_Lua/luci/fs.lua b/1_1.mi_Lua/luci/fs.lua new file mode 100644 index 0000000..53b2ee8 --- /dev/null +++ b/1_1.mi_Lua/luci/fs.lua @@ -0,0 +1,244 @@ +--[[ +LuCI - Filesystem tools + +Description: +A module offering often needed filesystem manipulation functions + +FileId: +$Id: fs.lua 5134 2009-07-24 17:34:40Z Cyrus $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/http.lua b/1_1.mi_Lua/luci/http.lua new file mode 100644 index 0000000..ed8fbc3 --- /dev/null +++ b/1_1.mi_Lua/luci/http.lua @@ -0,0 +1,336 @@ +--[[ +LuCI - HTTP-Interaction + +Description: +HTTP-Header manipulator and form variable preprocessor + +License: +Copyright 2008 Steven Barth + +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", package.seeall) + +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 + +function xqformvalue(name, noparse) + local XQSecureUtil = require("xiaoqiang.util.XQSecureUtil") + local value = context.request:formvalue(name, noparse) + return XQSecureUtil.xssCheck(value) +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 + +function writeJsonNoLog(x) + if x == nil then + write("null") + elseif type(x) == "table" then + local json = require("luci.json") + write(json.encode(x)) + 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 + +--- Send the given data as JSON encoded string. +-- @param data Data to send +function write_json(x) + local XQLog = require("xiaoqiang.XQLog") + XQLog.log(7,x) + writeJsonNoLog(x) +end diff --git a/1_1.mi_Lua/luci/http/protocol.lua b/1_1.mi_Lua/luci/http/protocol.lua new file mode 100644 index 0000000..00a5f71 --- /dev/null +++ b/1_1.mi_Lua/luci/http/protocol.lua @@ -0,0 +1,727 @@ +--[[ + +HTTP protocol implementation for LuCI +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +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: protocol.lua 9195 2012-08-29 13:06:58Z jow $ + +]]-- + +--- 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 util = require "luci.util" +local ltn12 = require("luci.ltn12") + +HTTP_MAX_CONTENT = 1024*32 -- 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 + +function xqurlencode(str) + if (str) then + --Ensure all newlines are in CRLF form + str = string.gsub (str, "\r?\n", "\r\n") + + --Percent-encode all non-unreserved characters + --as per RFC 3986, Section 2.3 + --(except for space, which gets plus-encoded) + str = string.gsub (str, "([^%w%-%.%_%~ ])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + + --Convert spaces to plus signs + str = string.gsub (str, " ", "+") + end + return str +end + +function xq_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) .. "=" .. xqurlencode(v2) + end + else + enc = (enc .. ( #enc > 0 and "&" or "" ) .. + urlencode(k) .. "=" .. xqurlencode(v)) + end + end + return enc +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 ) + else + key = "invalid_param" + __initval( msg.params, key ) + __appendval( msg.params, key, pair ) + __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/1_1.mi_Lua/luci/http/protocol/conditionals.lua b/1_1.mi_Lua/luci/http/protocol/conditionals.lua new file mode 100644 index 0000000..664d8df --- /dev/null +++ b/1_1.mi_Lua/luci/http/protocol/conditionals.lua @@ -0,0 +1,153 @@ +--[[ + +HTTP protocol implementation for LuCI - RFC2616 / 14.19, 14.24 - 14.28 +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +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: conditionals.lua 5637 2009-12-20 18:35:05Z jow $ + +]]-- + +--- 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/1_1.mi_Lua/luci/http/protocol/date.lua b/1_1.mi_Lua/luci/http/protocol/date.lua new file mode 100644 index 0000000..db7b524 --- /dev/null +++ b/1_1.mi_Lua/luci/http/protocol/date.lua @@ -0,0 +1,115 @@ +--[[ + +HTTP protocol implementation for LuCI - date handling +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +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: date.lua 3860 2008-12-06 03:18:14Z jow $ + +]]-- + +--- 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/1_1.mi_Lua/luci/http/protocol/mime.lua b/1_1.mi_Lua/luci/http/protocol/mime.lua new file mode 100644 index 0000000..9cf0fe4 --- /dev/null +++ b/1_1.mi_Lua/luci/http/protocol/mime.lua @@ -0,0 +1,99 @@ +--[[ + +HTTP protocol implementation for LuCI - mime handling +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +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: mime.lua 5327 2009-09-11 01:55:10Z jow $ + +]]-- + +--- 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/1_1.mi_Lua/luci/i18n.lua b/1_1.mi_Lua/luci/i18n.lua new file mode 100644 index 0000000..5c8aba2 --- /dev/null +++ b/1_1.mi_Lua/luci/i18n.lua @@ -0,0 +1,104 @@ +--[[ +LuCI - Internationalisation + +Description: +A very minimalistic but yet effective internationalisation module + +FileId: +$Id: i18n.lua 9558 2012-12-18 13:58:22Z jow $ + +License: +Copyright 2008 Steven Barth + +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 tostring(translate(...)) +-- @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 tostring(translatef(...)) +-- @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/1_1.mi_Lua/luci/i18n/base.en.lmo b/1_1.mi_Lua/luci/i18n/base.en.lmo new file mode 100644 index 0000000..76ff9db Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/base.en.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/base.zh-cn.lmo b/1_1.mi_Lua/luci/i18n/base.zh-cn.lmo new file mode 100644 index 0000000..81d67b8 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/base.zh-cn.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.ca.lmo b/1_1.mi_Lua/luci/i18n/firewall.ca.lmo new file mode 100644 index 0000000..103d847 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.ca.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.cs.lmo b/1_1.mi_Lua/luci/i18n/firewall.cs.lmo new file mode 100644 index 0000000..ee88f2e Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.cs.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.de.lmo b/1_1.mi_Lua/luci/i18n/firewall.de.lmo new file mode 100644 index 0000000..9a72186 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.de.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.el.lmo b/1_1.mi_Lua/luci/i18n/firewall.el.lmo new file mode 100644 index 0000000..fdd43ac Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.el.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.es.lmo b/1_1.mi_Lua/luci/i18n/firewall.es.lmo new file mode 100644 index 0000000..078e225 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.es.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.fr.lmo b/1_1.mi_Lua/luci/i18n/firewall.fr.lmo new file mode 100644 index 0000000..885e9bf Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.fr.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.hu.lmo b/1_1.mi_Lua/luci/i18n/firewall.hu.lmo new file mode 100644 index 0000000..4ff58c8 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.hu.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.it.lmo b/1_1.mi_Lua/luci/i18n/firewall.it.lmo new file mode 100644 index 0000000..d8e6e8d Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.it.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.ja.lmo b/1_1.mi_Lua/luci/i18n/firewall.ja.lmo new file mode 100644 index 0000000..a7cc3af Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.ja.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.no.lmo b/1_1.mi_Lua/luci/i18n/firewall.no.lmo new file mode 100644 index 0000000..6476585 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.no.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.pl.lmo b/1_1.mi_Lua/luci/i18n/firewall.pl.lmo new file mode 100644 index 0000000..3493ab6 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.pl.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.pt-br.lmo b/1_1.mi_Lua/luci/i18n/firewall.pt-br.lmo new file mode 100644 index 0000000..b26426b Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.pt-br.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.pt.lmo b/1_1.mi_Lua/luci/i18n/firewall.pt.lmo new file mode 100644 index 0000000..a62e0f8 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.pt.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.ro.lmo b/1_1.mi_Lua/luci/i18n/firewall.ro.lmo new file mode 100644 index 0000000..084babe Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.ro.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.ru.lmo b/1_1.mi_Lua/luci/i18n/firewall.ru.lmo new file mode 100644 index 0000000..e207bce Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.ru.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.uk.lmo b/1_1.mi_Lua/luci/i18n/firewall.uk.lmo new file mode 100644 index 0000000..083de3a Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.uk.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.vi.lmo b/1_1.mi_Lua/luci/i18n/firewall.vi.lmo new file mode 100644 index 0000000..bf32fb5 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.vi.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.zh-cn.lmo b/1_1.mi_Lua/luci/i18n/firewall.zh-cn.lmo new file mode 100644 index 0000000..ffa1078 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.zh-cn.lmo differ diff --git a/1_1.mi_Lua/luci/i18n/firewall.zh-tw.lmo b/1_1.mi_Lua/luci/i18n/firewall.zh-tw.lmo new file mode 100644 index 0000000..ffa1078 Binary files /dev/null and b/1_1.mi_Lua/luci/i18n/firewall.zh-tw.lmo differ diff --git a/1_1.mi_Lua/luci/init.lua b/1_1.mi_Lua/luci/init.lua new file mode 100644 index 0000000..9689fcf --- /dev/null +++ b/1_1.mi_Lua/luci/init.lua @@ -0,0 +1,39 @@ +--[[ +LuCI - Lua Configuration Interface + +Description: +Main class + +FileId: +$Id: init.lua 7365 2011-08-13 09:52:50Z jow $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/ip.lua b/1_1.mi_Lua/luci/ip.lua new file mode 100644 index 0000000..07c177a --- /dev/null +++ b/1_1.mi_Lua/luci/ip.lua @@ -0,0 +1,684 @@ +--[[ + +LuCI ip calculation libarary +(c) 2008 Jo-Philipp Wich +(c) 2008 Steven Barth + +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: ip.lua 8142 2012-01-01 15:51:37Z jow $ + +]]-- + +--- 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 + +function iptonl( ip ) + local a,b,c,d = ip:match("^(%d+).(%d+).(%d+).(%d+)") + local ipnl = bit.lshift(a, 24) + bit.lshift(b, 16) + bit.lshift(c, 8) + d + return ipnl +end + +function ipnot ( ip ) + local ipnl = iptonl(ip) + return bit.band(bit.bnot(ipnl),0xFFFFFFFF) +end diff --git a/1_1.mi_Lua/luci/json.lua b/1_1.mi_Lua/luci/json.lua new file mode 100644 index 0000000..0218a1f --- /dev/null +++ b/1_1.mi_Lua/luci/json.lua @@ -0,0 +1,566 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: json.lua 6988 2011-04-17 11:39:17Z jow $ + +Decoder: + Info: + null will be decoded to luci.json.null if first parameter of Decoder() is true + + Example: + decoder = luci.json.Decoder() + luci.ltn12.pump.all(luci.ltn12.source.string("decodableJSON"), decoder:sink()) + luci.util.dumptable(decoder:get()) + + Known issues: + does not support unicode conversion \uXXYY with XX != 00 will be ignored + + +Encoder: + Info: + Accepts numbers, strings, nil, booleans as they are + Accepts luci.json.null as replacement for nil + Accepts full associative and full numerically indexed tables + Mixed tables will loose their associative values during conversion + Iterator functions will be encoded as an array of their return values + Non-iterator functions will probably corrupt the encoder + + Example: + encoder = luci.json.Encoder(encodableData) + luci.ltn12.pump.all(encoder:source(), luci.ltn12.sink.file(io.open("someFile", w))) +]]-- + +local util = require "luci.util" +local table = require "table" +local string = require "string" +local coroutine = require "coroutine" + +local assert = assert +local tonumber = tonumber +local tostring = tostring +local error = error +local type = type +local pairs = pairs +local ipairs = ipairs +local next = next +local pcall = pcall + +local getmetatable = getmetatable + +--- LuCI JSON-Library +-- @cstyle instance +module "luci.json" + + +--- Directly decode a JSON string +-- @param json JSON-String +-- @return Lua object +function decode(json, ...) + local a = ActiveDecoder(function() return nil end, ...) + a.chunk = json + local s, obj = pcall(a.get, a) + return s and obj or nil +end + + +--- Direcly encode a Lua object into a JSON string. +-- @param obj Lua Object +-- @return JSON string +function encode(obj, ...) + local out = {} + local e = Encoder(obj, 1, ...):source() + local chnk, err + repeat + chnk, err = e() + out[#out+1] = chnk + until not chnk + return not err and table.concat(out) or nil +end + + +--- Null replacement function +-- @return null +function null() + return null +end + +--- Create a new JSON-Encoder. +-- @class function +-- @name Encoder +-- @param data Lua-Object to be encoded. +-- @param buffersize Blocksize of returned data source. +-- @param fastescape Use non-standard escaping (don't escape control chars) +-- @return JSON-Encoder +Encoder = util.class() + +function Encoder.__init__(self, data, buffersize, fastescape) + self.data = data + self.buffersize = buffersize or 512 + self.buffer = "" + self.fastescape = fastescape + + getmetatable(self).__call = Encoder.source +end + +--- Create an LTN12 source providing the encoded JSON-Data. +-- @return LTN12 source +function Encoder.source(self) + local source = coroutine.create(self.dispatch) + return function() + local res, data = coroutine.resume(source, self, self.data, true) + if res then + return data + else + return nil, data + end + end +end + +function Encoder.dispatch(self, data, start) + local parser = self.parsers[type(data)] + + parser(self, data) + + if start then + if #self.buffer > 0 then + coroutine.yield(self.buffer) + end + + coroutine.yield() + end +end + +function Encoder.put(self, chunk) + if self.buffersize < 2 then + coroutine.yield(chunk) + else + if #self.buffer + #chunk > self.buffersize then + local written = 0 + local fbuffer = self.buffersize - #self.buffer + + coroutine.yield(self.buffer .. chunk:sub(written + 1, fbuffer)) + written = fbuffer + + while #chunk - written > self.buffersize do + fbuffer = written + self.buffersize + coroutine.yield(chunk:sub(written + 1, fbuffer)) + written = fbuffer + end + + self.buffer = chunk:sub(written + 1) + else + self.buffer = self.buffer .. chunk + end + end +end + +function Encoder.parse_nil(self) + self:put("null") +end + +function Encoder.parse_bool(self, obj) + self:put(obj and "true" or "false") +end + +function Encoder.parse_number(self, obj) + self:put(tostring(obj)) +end + +function Encoder.parse_string(self, obj) + if self.fastescape then + self:put('"' .. obj:gsub('\\', '\\\\'):gsub('"', '\\"') .. '"') + else + self:put('"' .. + obj:gsub('[%c\\"]', + function(char) + return '\\u00%02x' % char:byte() + end + ) + .. '"') + end +end + +function Encoder.parse_iter(self, obj) + if obj == null then + return self:put("null") + end + + if type(obj) == "table" and (#obj == 0 and next(obj)) then + self:put("{") + local first = true + + for key, entry in pairs(obj) do + first = first or self:put(",") + first = first and false + self:parse_string(tostring(key)) + self:put(":") + self:dispatch(entry) + end + + self:put("}") + else + self:put("[") + local first = true + + if type(obj) == "table" then + for i=1, #obj do + first = first or self:put(",") + first = first and nil + self:dispatch(obj[i]) + end + else + for entry in obj do + first = first or self:put(",") + first = first and nil + self:dispatch(entry) + end + end + + self:put("]") + end +end + +Encoder.parsers = { + ['nil'] = Encoder.parse_nil, + ['table'] = Encoder.parse_iter, + ['number'] = Encoder.parse_number, + ['string'] = Encoder.parse_string, + ['boolean'] = Encoder.parse_bool, + ['function'] = Encoder.parse_iter +} + + +--- Create a new JSON-Decoder. +-- @class function +-- @name Decoder +-- @param customnull Use luci.json.null instead of nil for decoding null +-- @return JSON-Decoder +Decoder = util.class() + +function Decoder.__init__(self, customnull) + self.cnull = customnull + getmetatable(self).__call = Decoder.sink +end + +--- Create an LTN12 sink from the decoder object which accepts the JSON-Data. +-- @return LTN12 sink +function Decoder.sink(self) + local sink = coroutine.create(self.dispatch) + return function(...) + return coroutine.resume(sink, self, ...) + end +end + + +--- Get the decoded data packets after the rawdata has been sent to the sink. +-- @return Decoded data +function Decoder.get(self) + return self.data +end + +function Decoder.dispatch(self, chunk, src_err, strict) + local robject, object + local oset = false + + while chunk do + while chunk and #chunk < 1 do + chunk = self:fetch() + end + + assert(not strict or chunk, "Unexpected EOS") + if not chunk then break end + + local char = chunk:sub(1, 1) + local parser = self.parsers[char] + or (char:match("%s") and self.parse_space) + or (char:match("[0-9-]") and self.parse_number) + or error("Unexpected char '%s'" % char) + + chunk, robject = parser(self, chunk) + + if parser ~= self.parse_space then + assert(not oset, "Scope violation: Too many objects") + object = robject + oset = true + + if strict then + return chunk, object + end + end + end + + assert(not src_err, src_err) + assert(oset, "Unexpected EOS") + + self.data = object +end + + +function Decoder.fetch(self) + local tself, chunk, src_err = coroutine.yield() + assert(chunk or not src_err, src_err) + return chunk +end + + +function Decoder.fetch_atleast(self, chunk, bytes) + while #chunk < bytes do + local nchunk = self:fetch() + assert(nchunk, "Unexpected EOS") + chunk = chunk .. nchunk + end + + return chunk +end + + +function Decoder.fetch_until(self, chunk, pattern) + local start = chunk:find(pattern) + + while not start do + local nchunk = self:fetch() + assert(nchunk, "Unexpected EOS") + chunk = chunk .. nchunk + start = chunk:find(pattern) + end + + return chunk, start +end + + +function Decoder.parse_space(self, chunk) + local start = chunk:find("[^%s]") + + while not start do + chunk = self:fetch() + if not chunk then + return nil + end + start = chunk:find("[^%s]") + end + + return chunk:sub(start) +end + + +function Decoder.parse_literal(self, chunk, literal, value) + chunk = self:fetch_atleast(chunk, #literal) + assert(chunk:sub(1, #literal) == literal, "Invalid character sequence") + return chunk:sub(#literal + 1), value +end + + +function Decoder.parse_null(self, chunk) + return self:parse_literal(chunk, "null", self.cnull and null) +end + + +function Decoder.parse_true(self, chunk) + return self:parse_literal(chunk, "true", true) +end + + +function Decoder.parse_false(self, chunk) + return self:parse_literal(chunk, "false", false) +end + + +function Decoder.parse_number(self, chunk) + local chunk, start = self:fetch_until(chunk, "[^0-9eE.+-]") + local number = tonumber(chunk:sub(1, start - 1)) + assert(number, "Invalid number specification") + return chunk:sub(start), number +end + + +function Decoder.parse_string(self, chunk) + local str = "" + local object = nil + assert(chunk:sub(1, 1) == '"', 'Expected "') + chunk = chunk:sub(2) + + while true do + local spos = chunk:find('[\\"]') + if spos then + str = str .. chunk:sub(1, spos - 1) + + local char = chunk:sub(spos, spos) + if char == '"' then -- String end + chunk = chunk:sub(spos + 1) + break + elseif char == "\\" then -- Escape sequence + chunk, object = self:parse_escape(chunk:sub(spos)) + str = str .. object + end + else + str = str .. chunk + chunk = self:fetch() + assert(chunk, "Unexpected EOS while parsing a string") + end + end + + return chunk, str +end + + +function Decoder.parse_escape(self, chunk) + local str = "" + chunk = self:fetch_atleast(chunk:sub(2), 1) + local char = chunk:sub(1, 1) + chunk = chunk:sub(2) + + if char == '"' then + return chunk, '"' + elseif char == "\\" then + return chunk, "\\" + elseif char == "u" then + chunk = self:fetch_atleast(chunk, 4) + local s1, s2 = chunk:sub(1, 2), chunk:sub(3, 4) + s1, s2 = tonumber(s1, 16), tonumber(s2, 16) + assert(s1 and s2, "Invalid Unicode character") + + -- ToDo: Unicode support + return chunk:sub(5), s1 == 0 and string.char(s2) or "" + elseif char == "/" then + return chunk, "/" + elseif char == "b" then + return chunk, "\b" + elseif char == "f" then + return chunk, "\f" + elseif char == "n" then + return chunk, "\n" + elseif char == "r" then + return chunk, "\r" + elseif char == "t" then + return chunk, "\t" + else + error("Unexpected escaping sequence '\\%s'" % char) + end +end + + +function Decoder.parse_array(self, chunk) + chunk = chunk:sub(2) + local array = {} + local nextp = 1 + + local chunk, object = self:parse_delimiter(chunk, "%]") + + if object then + return chunk, array + end + + repeat + chunk, object = self:dispatch(chunk, nil, true) + table.insert(array, nextp, object) + nextp = nextp + 1 + + chunk, object = self:parse_delimiter(chunk, ",%]") + assert(object, "Delimiter expected") + until object == "]" + + return chunk, array +end + + +function Decoder.parse_object(self, chunk) + chunk = chunk:sub(2) + local array = {} + local name + + local chunk, object = self:parse_delimiter(chunk, "}") + + if object then + return chunk, array + end + + repeat + chunk = self:parse_space(chunk) + assert(chunk, "Unexpected EOS") + + chunk, name = self:parse_string(chunk) + + chunk, object = self:parse_delimiter(chunk, ":") + assert(object, "Separator expected") + + chunk, object = self:dispatch(chunk, nil, true) + array[name] = object + + chunk, object = self:parse_delimiter(chunk, ",}") + assert(object, "Delimiter expected") + until object == "}" + + return chunk, array +end + + +function Decoder.parse_delimiter(self, chunk, delimiter) + while true do + chunk = self:fetch_atleast(chunk, 1) + local char = chunk:sub(1, 1) + if char:match("%s") then + chunk = self:parse_space(chunk) + assert(chunk, "Unexpected EOS") + elseif char:match("[%s]" % delimiter) then + return chunk:sub(2), char + else + return chunk, nil + end + end +end + + +Decoder.parsers = { + ['"'] = Decoder.parse_string, + ['t'] = Decoder.parse_true, + ['f'] = Decoder.parse_false, + ['n'] = Decoder.parse_null, + ['['] = Decoder.parse_array, + ['{'] = Decoder.parse_object +} + + +--- Create a new Active JSON-Decoder. +-- @class function +-- @name ActiveDecoder +-- @param customnull Use luci.json.null instead of nil for decoding null +-- @return Active JSON-Decoder +ActiveDecoder = util.class(Decoder) + +function ActiveDecoder.__init__(self, source, customnull) + Decoder.__init__(self, customnull) + self.source = source + self.chunk = nil + getmetatable(self).__call = self.get +end + + +--- Fetches one JSON-object from given source +-- @return Decoded object +function ActiveDecoder.get(self) + local chunk, src_err, object + if not self.chunk then + chunk, src_err = self.source() + else + chunk = self.chunk + end + + self.chunk, object = self:dispatch(chunk, src_err, true) + return object +end + + +function ActiveDecoder.fetch(self) + local chunk, src_err = self.source() + assert(chunk or not src_err, src_err) + return chunk +end diff --git a/1_1.mi_Lua/luci/ltn12.lua b/1_1.mi_Lua/luci/ltn12.lua new file mode 100644 index 0000000..1e1cc6b --- /dev/null +++ b/1_1.mi_Lua/luci/ltn12.lua @@ -0,0 +1,391 @@ +--[[ +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: ltn12.lua 3212 2008-09-09 12:44:41Z Cyrus $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- 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/1_1.mi_Lua/luci/model/cbi/admin_network/proto_dhcp.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_dhcp.lua new file mode 100644 index 0000000..8d2bcc6 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_dhcp.lua @@ -0,0 +1,88 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011-2012 Jo-Philipp Wich + +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 map, section, net = ... +local ifc = net:get_interface() + +local hostname, accept_ra, send_rs +local bcast, defaultroute, peerdns, dns, metric, clientid, vendorclass + + +hostname = section:taboption("general", Value, "hostname", + translate("Hostname to send when requesting DHCP")) + +hostname.placeholder = luci.sys.hostname() +hostname.datatype = "hostname" + + +if luci.model.network:has_ipv6() then + + accept_ra = s:taboption("general", Flag, "accept_ra", translate("Accept router advertisements")) + accept_ra.default = accept_ra.enabled + + + send_rs = s:taboption("general", Flag, "send_rs", translate("Send router solicitations")) + send_rs.default = send_rs.disabled + send_rs:depends("accept_ra", "") + +end + +bcast = section:taboption("advanced", Flag, "broadcast", + translate("Use broadcast flag"), + translate("Required for certain ISPs, e.g. Charter with DOCSIS 3")) + +bcast.default = bcast.disabled + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" + + +clientid = section:taboption("advanced", Value, "clientid", + translate("Client ID to send when requesting DHCP")) + + +vendorclass = section:taboption("advanced", Value, "vendorid", + translate("Vendor Class to send when requesting DHCP")) + + +luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address")) + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_l2tp.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_l2tp.lua new file mode 100644 index 0000000..f5de45d --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_l2tp.lua @@ -0,0 +1,69 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... + +local server, username, password +local ipv6, defaultroute, metric, peerdns, dns, mtu + + +server = section:taboption("general", Value, "server", translate("L2TP Server")) +server.datatype = "host" + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + +if luci.model.network:has_ipv6() then + + ipv6 = section:taboption("advanced", Flag, "ipv6", + translate("Enable IPv6 negotiation on the PPP link")) + + ipv6.default = ipv6.disabled + +end + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_none.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_none.lua new file mode 100644 index 0000000..0e34b67 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_none.lua @@ -0,0 +1,13 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_ppp.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_ppp.lua new file mode 100644 index 0000000..00760b9 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_ppp.lua @@ -0,0 +1,136 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... + +local device, username, password +local ipv6, defaultroute, metric, peerdns, dns, + keepalive_failure, keepalive_interval, demand, mtu + + +device = section:taboption("general", Value, "device", translate("Modem device")) +device.rmempty = false + +local device_suggestions = nixio.fs.glob("/dev/tty*S*") + or nixio.fs.glob("/dev/tts/*") + +if device_suggestions then + local node + for node in device_suggestions do + device:value(node) + end +end + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + + +if luci.model.network:has_ipv6() then + + ipv6 = section:taboption("advanced", Flag, "ipv6", + translate("Enable IPv6 negotiation on the PPP link")) + + ipv6.default = ipv6.disabled + +end + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure", + translate("LCP echo failure threshold"), + translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures")) + +function keepalive_failure.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^(%d+)[ ,]+%d+") or v) + end +end + +function keepalive_failure.write() end +function keepalive_failure.remove() end + +keepalive_failure.placeholder = "0" +keepalive_failure.datatype = "uinteger" + + +keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval", + translate("LCP echo interval"), + translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold")) + +function keepalive_interval.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^%d+[ ,]+(%d+)")) + end +end + +function keepalive_interval.write(self, section, value) + local f = tonumber(keepalive_failure:formvalue(section)) or 0 + local i = tonumber(value) or 5 + if i < 1 then i = 1 end + if f > 0 then + m:set(section, "keepalive", "%d %d" %{ f, i }) + else + m:del(section, "keepalive") + end +end + +keepalive_interval.remove = keepalive_interval.write +keepalive_interval.placeholder = "5" +keepalive_interval.datatype = "min(1)" + + +demand = section:taboption("advanced", Value, "demand", + translate("Inactivity timeout"), + translate("Close inactive connection after the given amount of seconds, use 0 to persist connection")) + +demand.placeholder = "0" +demand.datatype = "uinteger" + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoa.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoa.lua new file mode 100644 index 0000000..5d4c84d --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoa.lua @@ -0,0 +1,142 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... + +local encaps, atmdev, vci, vpi, username, password +local ipv6, defaultroute, metric, peerdns, dns, + keepalive_failure, keepalive_interval, demand, mtu + + +encaps = section:taboption("general", ListValue, "encaps", translate("PPPoA Encapsulation")) +encaps:value("vc", "VC-Mux") +encaps:value("llc", "LLC") + + +atmdev = section:taboption("general", Value, "atmdev", translate("ATM device number")) +atmdev.default = "0" +atmdev.datatype = "uinteger" + + +vci = section:taboption("general", Value, "vci", translate("ATM Virtual Channel Identifier (VCI)")) +vci.default = "35" +vci.datatype = "uinteger" + + +vpi = section:taboption("general", Value, "vpi", translate("ATM Virtual Path Identifier (VPI)")) +vpi.default = "8" +vpi.datatype = "uinteger" + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + + +if luci.model.network:has_ipv6() then + + ipv6 = section:taboption("advanced", Flag, "ipv6", + translate("Enable IPv6 negotiation on the PPP link")) + + ipv6.default = ipv6.disabled + +end + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure", + translate("LCP echo failure threshold"), + translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures")) + +function keepalive_failure.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^(%d+)[ ,]+%d+") or v) + end +end + +function keepalive_failure.write() end +function keepalive_failure.remove() end + +keepalive_failure.placeholder = "0" +keepalive_failure.datatype = "uinteger" + + +keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval", + translate("LCP echo interval"), + translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold")) + +function keepalive_interval.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^%d+[ ,]+(%d+)")) + end +end + +function keepalive_interval.write(self, section, value) + local f = tonumber(keepalive_failure:formvalue(section)) or 0 + local i = tonumber(value) or 5 + if i < 1 then i = 1 end + if f > 0 then + m:set(section, "keepalive", "%d %d" %{ f, i }) + else + m:del(section, "keepalive") + end +end + +keepalive_interval.remove = keepalive_interval.write +keepalive_interval.placeholder = "5" +keepalive_interval.datatype = "min(1)" + + +demand = section:taboption("advanced", Value, "demand", + translate("Inactivity timeout"), + translate("Close inactive connection after the given amount of seconds, use 0 to persist connection")) + +demand.placeholder = "0" +demand.datatype = "uinteger" + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoe.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoe.lua new file mode 100644 index 0000000..4f19ac3 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pppoe.lua @@ -0,0 +1,136 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... + +local username, password, ac, service +local ipv6, defaultroute, metric, peerdns, dns, + keepalive_failure, keepalive_interval, demand, mtu + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + + +ac = section:taboption("general", Value, "ac", + translate("Access Concentrator"), + translate("Leave empty to autodetect")) + +ac.placeholder = translate("auto") + + +service = section:taboption("general", Value, "service", + translate("Service Name"), + translate("Leave empty to autodetect")) + +service.placeholder = translate("auto") + + +if luci.model.network:has_ipv6() then + + ipv6 = section:taboption("advanced", Flag, "ipv6", + translate("Enable IPv6 negotiation on the PPP link")) + + ipv6.default = ipv6.disabled + +end + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure", + translate("LCP echo failure threshold"), + translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures")) + +function keepalive_failure.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^(%d+)[ ,]+%d+") or v) + end +end + +function keepalive_failure.write() end +function keepalive_failure.remove() end + +keepalive_failure.placeholder = "0" +keepalive_failure.datatype = "uinteger" + + +keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval", + translate("LCP echo interval"), + translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold")) + +function keepalive_interval.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^%d+[ ,]+(%d+)")) + end +end + +function keepalive_interval.write(self, section, value) + local f = tonumber(keepalive_failure:formvalue(section)) or 0 + local i = tonumber(value) or 5 + if i < 1 then i = 1 end + if f > 0 then + m:set(section, "keepalive", "%d %d" %{ f, i }) + else + m:del(section, "keepalive") + end +end + +keepalive_interval.remove = keepalive_interval.write +keepalive_interval.placeholder = "5" +keepalive_interval.datatype = "min(1)" + + +demand = section:taboption("advanced", Value, "demand", + translate("Inactivity timeout"), + translate("Close inactive connection after the given amount of seconds, use 0 to persist connection")) + +demand.placeholder = "0" +demand.datatype = "uinteger" + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pptp.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pptp.lua new file mode 100644 index 0000000..0a2ee8e --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_pptp.lua @@ -0,0 +1,116 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011-2012 Jo-Philipp Wich + +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 map, section, net = ... + +local server, username, password +local defaultroute, metric, peerdns, dns, + keepalive_failure, keepalive_interval, demand, mtu + + +server = section:taboption("general", Value, "server", translate("VPN Server")) +server.datatype = "host" + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure", + translate("LCP echo failure threshold"), + translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures")) + +function keepalive_failure.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^(%d+)[ ,]+%d+") or v) + end +end + +function keepalive_failure.write() end +function keepalive_failure.remove() end + +keepalive_failure.placeholder = "0" +keepalive_failure.datatype = "uinteger" + + +keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval", + translate("LCP echo interval"), + translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold")) + +function keepalive_interval.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^%d+[ ,]+(%d+)")) + end +end + +function keepalive_interval.write(self, section, value) + local f = tonumber(keepalive_failure:formvalue(section)) or 0 + local i = tonumber(value) or 5 + if i < 1 then i = 1 end + if f > 0 then + m:set(section, "keepalive", "%d %d" %{ f, i }) + else + m:del(section, "keepalive") + end +end + +keepalive_interval.remove = keepalive_interval.write +keepalive_interval.placeholder = "5" +keepalive_interval.datatype = "min(1)" + + +demand = section:taboption("advanced", Value, "demand", + translate("Inactivity timeout"), + translate("Close inactive connection after the given amount of seconds, use 0 to persist connection")) + +demand.placeholder = "0" +demand.datatype = "uinteger" + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" diff --git a/1_1.mi_Lua/luci/model/cbi/admin_network/proto_static.lua b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_static.lua new file mode 100644 index 0000000..e6bfcbb --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/admin_network/proto_static.lua @@ -0,0 +1,83 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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 map, section, net = ... +local ifc = net:get_interface() + +local ipaddr, netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw +local mtu, metric + + +ipaddr = section:taboption("general", Value, "ipaddr", translate("IPv4 address")) +ipaddr.datatype = "ip4addr" + + +netmask = section:taboption("general", Value, "netmask", + translate("IPv4 netmask")) + +netmask.datatype = "ip4addr" +netmask:value("255.255.255.0") +netmask:value("255.255.0.0") +netmask:value("255.0.0.0") + + +gateway = section:taboption("general", Value, "gateway", translate("IPv4 gateway")) +gateway.datatype = "ip4addr" + + +broadcast = section:taboption("general", Value, "broadcast", translate("IPv4 broadcast")) +broadcast.datatype = "ip4addr" + + +dns = section:taboption("general", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns.datatype = "ipaddr" +dns.cast = "string" + + +if luci.model.network:has_ipv6() then + + accept_ra = s:taboption("general", Flag, "accept_ra", translate("Accept router advertisements")) + accept_ra.default = accept_ra.disabled + + + send_rs = s:taboption("general", Flag, "send_rs", translate("Send router solicitations")) + send_rs.default = send_rs.enabled + send_rs:depends("accept_ra", "") + + + ip6addr = section:taboption("general", Value, "ip6addr", translate("IPv6 address")) + ip6addr.datatype = "ip6addr" + ip6addr:depends("accept_ra", "") + + + ip6gw = section:taboption("general", Value, "ip6gw", translate("IPv6 gateway")) + ip6gw.datatype = "ip6addr" + ip6gw:depends("accept_ra", "") + +end + + +luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address")) + + +mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU")) +mtu.placeholder = "1500" +mtu.datatype = "max(1500)" + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/custom.lua b/1_1.mi_Lua/luci/model/cbi/firewall/custom.lua new file mode 100644 index 0000000..ceb04ec --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/custom.lua @@ -0,0 +1,38 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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: custom.lua 8108 2011-12-19 21:16:31Z jow $ +]]-- + +local fs = require "nixio.fs" + +local f = SimpleForm("firewall", + translate("Firewall - Custom Rules"), + translate("Custom rules allow you to execute arbritary iptables commands \ + which are not otherwise covered by the firewall framework. \ + The commands are executed after each firewall restart, right after \ + the default ruleset has been loaded.")) + +local o = f:field(Value, "_custom") + +o.template = "cbi/tvalue" +o.rows = 20 + +function o.cfgvalue(self, section) + return fs.readfile("/etc/firewall.user") +end + +function o.write(self, section, value) + value = value:gsub("\r\n?", "\n") + fs.writefile("/etc/firewall.user", value) +end + +return f diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/forward-details.lua b/1_1.mi_Lua/luci/model/cbi/firewall/forward-details.lua new file mode 100644 index 0000000..4d67e67 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/forward-details.lua @@ -0,0 +1,178 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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: forward-details.lua 8962 2012-08-09 10:03:32Z jow $ +]]-- + +local sys = require "luci.sys" +local dsp = require "luci.dispatcher" +local ft = require "luci.tools.firewall" + +local m, s, o + +arg[1] = arg[1] or "" + +m = Map("firewall", + translate("Firewall - Port Forwards"), + translate("This page allows you to change advanced properties of the port \ + forwarding entry. In most cases there is no need to modify \ + those settings.")) + +m.redirect = dsp.build_url("admin/network/firewall/forwards") + +if m.uci:get("firewall", arg[1]) ~= "redirect" then + luci.http.redirect(m.redirect) + return +else + local name = m:get(arg[1], "name") or m:get(arg[1], "_name") + if not name or #name == 0 then + name = translate("(Unnamed Entry)") + end + m.title = "%s - %s" %{ translate("Firewall - Port Forwards"), name } +end + +local wan_zone = nil + +m.uci:foreach("firewall", "zone", + function(s) + local n = s.network or s.name + if n then + local i + for i in n:gmatch("%S+") do + if i == "wan" then + wan_zone = s.name + return false + end + end + end + end) + +s = m:section(NamedSection, arg[1], "redirect", "") +s.anonymous = true +s.addremove = false + +ft.opt_enabled(s, Button) +ft.opt_name(s, Value, translate("Name")) + + +o = s:option(Value, "proto", translate("Protocol")) +o:value("tcp udp", "TCP+UDP") +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("icmp", "ICMP") + +function o.cfgvalue(...) + local v = Value.cfgvalue(...) + if not v or v == "tcpudp" then + return "tcp udp" + end + return v +end + + +o = s:option(Value, "src", translate("Source zone")) +o.nocreate = true +o.default = "wan" +o.template = "cbi/firewall_zonelist" + + +o = s:option(DynamicList, "src_mac", + translate("Source MAC address"), + translate("Only match incoming traffic from these MACs.")) +o.rmempty = true +o.datatype = "neg(macaddr)" +o.placeholder = translate("any") + +luci.sys.net.mac_hints(function(mac, name) + o:value(mac, "%s (%s)" %{ mac, name }) +end) + + +o = s:option(Value, "src_ip", + translate("Source IP address"), + translate("Only match incoming traffic from this IP or range.")) +o.rmempty = true +o.datatype = "neg(ip4addr)" +o.placeholder = translate("any") + +luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) +end) + + +o = s:option(Value, "src_port", + translate("Source port"), + translate("Only match incoming traffic originating from the given source port or port range on the client host")) +o.rmempty = true +o.datatype = "neg(portrange)" +o.placeholder = translate("any") + + +o = s:option(Value, "src_dip", + translate("External IP address"), + translate("Only match incoming traffic directed at the given IP address.")) + +luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) +end) + + +o.rmempty = true +o.datatype = "neg(ip4addr)" +o.placeholder = translate("any") + + +o = s:option(Value, "src_dport", translate("External port"), + translate("Match incoming traffic directed at the given " .. + "destination port or port range on this host")) +o.datatype = "neg(portrange)" + + + +o = s:option(Value, "dest", translate("Internal zone")) +o.nocreate = true +o.default = "lan" +o.template = "cbi/firewall_zonelist" + + +o = s:option(Value, "dest_ip", translate("Internal IP address"), + translate("Redirect matched incoming traffic to the specified \ + internal host")) +o.datatype = "ip4addr" + +luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) +end) + + +o = s:option(Value, "dest_port", + translate("Internal port"), + translate("Redirect matched incoming traffic to the given port on \ + the internal host")) +o.placeholder = translate("any") +o.datatype = "portrange" + + +o = s:option(Flag, "reflection", translate("Enable NAT Loopback")) +o.rmempty = true +o.default = o.enabled +o:depends("src", wan_zone) +o.cfgvalue = function(...) + return Flag.cfgvalue(...) or "1" +end + + +s:option(Value, "extra", + translate("Extra arguments"), + translate("Passes additional arguments to iptables. Use with care!")) + + +return m diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/forwards.lua b/1_1.mi_Lua/luci/model/cbi/firewall/forwards.lua new file mode 100644 index 0000000..5f7a69b --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/forwards.lua @@ -0,0 +1,144 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2010-2012 Jo-Philipp Wich + +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 ds = require "luci.dispatcher" +local ft = require "luci.tools.firewall" + +m = Map("firewall", translate("Firewall - Port Forwards"), + translate("Port forwarding allows remote computers on the Internet to \ + connect to a specific computer or service within the \ + private LAN.")) + +-- +-- Port Forwards +-- + +s = m:section(TypedSection, "redirect", translate("Port Forwards")) +s.template = "cbi/tblsection" +s.addremove = true +s.anonymous = true +s.sortable = true +s.extedit = ds.build_url("admin/network/firewall/forwards/%s") +s.template_addremove = "firewall/cbi_addforward" + +function s.create(self, section) + local n = m:formvalue("_newfwd.name") + local p = m:formvalue("_newfwd.proto") + local E = m:formvalue("_newfwd.extzone") + local e = m:formvalue("_newfwd.extport") + local I = m:formvalue("_newfwd.intzone") + local a = m:formvalue("_newfwd.intaddr") + local i = m:formvalue("_newfwd.intport") + + if p == "other" or (p and a) then + created = TypedSection.create(self, section) + + self.map:set(created, "target", "DNAT") + self.map:set(created, "src", E or "wan") + self.map:set(created, "dest", I or "lan") + self.map:set(created, "proto", (p ~= "other") and p or "all") + self.map:set(created, "src_dport", e) + self.map:set(created, "dest_ip", a) + self.map:set(created, "dest_port", i) + self.map:set(created, "name", n) + end + + if p ~= "other" then + created = nil + end +end + +function s.parse(self, ...) + TypedSection.parse(self, ...) + if created then + m.uci:save("firewall") + luci.http.redirect(ds.build_url( + "admin/network/firewall/redirect", created + )) + end +end + +function s.filter(self, sid) + return (self.map:get(sid, "target") ~= "SNAT") +end + + +ft.opt_name(s, DummyValue, translate("Name")) + + +local function forward_proto_txt(self, s) + return "%s-%s" %{ + translate("IPv4"), + ft.fmt_proto(self.map:get(s, "proto"), + self.map:get(s, "icmp_type")) or "TCP+UDP" + } +end + +local function forward_src_txt(self, s) + local z = ft.fmt_zone(self.map:get(s, "src"), translate("any zone")) + local a = ft.fmt_ip(self.map:get(s, "src_ip"), translate("any host")) + local p = ft.fmt_port(self.map:get(s, "src_port")) + local m = ft.fmt_mac(self.map:get(s, "src_mac")) + + if p and m then + return translatef("From %s in %s with source %s and %s", a, z, p, m) + elseif p or m then + return translatef("From %s in %s with source %s", a, z, p or m) + else + return translatef("From %s in %s", a, z) + end +end + +local function forward_via_txt(self, s) + local a = ft.fmt_ip(self.map:get(s, "src_dip"), translate("any router IP")) + local p = ft.fmt_port(self.map:get(s, "src_dport")) + + if p then + return translatef("Via %s at %s", a, p) + else + return translatef("Via %s", a) + end +end + +match = s:option(DummyValue, "match", translate("Match")) +match.rawhtml = true +match.width = "50%" +function match.cfgvalue(self, s) + return "%s
%s
%s
" % { + forward_proto_txt(self, s), + forward_src_txt(self, s), + forward_via_txt(self, s) + } +end + + +dest = s:option(DummyValue, "dest", translate("Forward to")) +dest.rawhtml = true +dest.width = "40%" +function dest.cfgvalue(self, s) + local z = ft.fmt_zone(self.map:get(s, "dest"), translate("any zone")) + local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) + local p = ft.fmt_port(self.map:get(s, "dest_port")) or + ft.fmt_port(self.map:get(s, "src_dport")) + + if p then + return translatef("%s, %s in %s", a, p, z) + else + return translatef("%s in %s", a, z) + end +end + +ft.opt_enabled(s, Flag, translate("Enable")).width = "1%" + +return m diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/rule-details.lua b/1_1.mi_Lua/luci/model/cbi/firewall/rule-details.lua new file mode 100644 index 0000000..0086148 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/rule-details.lua @@ -0,0 +1,338 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2010-2012 Jo-Philipp Wich + +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 sys = require "luci.sys" +local dsp = require "luci.dispatcher" +local nxo = require "nixio" + +local ft = require "luci.tools.firewall" +local nw = require "luci.model.network" +local m, s, o, k, v + +arg[1] = arg[1] or "" + +m = Map("firewall", + translate("Firewall - Traffic Rules"), + translate("This page allows you to change advanced properties of the \ + traffic rule entry, such as matched source and destination \ + hosts.")) + +m.redirect = dsp.build_url("admin/network/firewall/rules") + +nw.init(m.uci) + +local rule_type = m.uci:get("firewall", arg[1]) +if rule_type == "redirect" and m:get(arg[1], "target") ~= "SNAT" then + rule_type = nil +end + +if not rule_type then + luci.http.redirect(m.redirect) + return + +-- +-- SNAT +-- +elseif rule_type == "redirect" then + + local name = m:get(arg[1], "name") or m:get(arg[1], "_name") + if not name or #name == 0 then + name = translate("(Unnamed SNAT)") + else + name = "SNAT %s" % name + end + + m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } + + local wan_zone = nil + + m.uci:foreach("firewall", "zone", + function(s) + local n = s.network or s.name + if n then + local i + for i in n:gmatch("%S+") do + if i == "wan" then + wan_zone = s.name + return false + end + end + end + end) + + s = m:section(NamedSection, arg[1], "redirect", "") + s.anonymous = true + s.addremove = false + + + ft.opt_enabled(s, Button) + ft.opt_name(s, Value, translate("Name")) + + + o = s:option(Value, "proto", + translate("Protocol"), + translate("You may specify multiple by selecting \"-- custom --\" and \ + then entering protocols separated by space.")) + + o:value("all", "All protocols") + o:value("tcp udp", "TCP+UDP") + o:value("tcp", "TCP") + o:value("udp", "UDP") + o:value("icmp", "ICMP") + + function o.cfgvalue(...) + local v = Value.cfgvalue(...) + if not v or v == "tcpudp" then + return "tcp udp" + end + return v + end + + + o = s:option(Value, "src", translate("Source zone")) + o.nocreate = true + o.default = "wan" + o.template = "cbi/firewall_zonelist" + + + o = s:option(DynamicList, "src_mac", translate("Source MAC address")) + o.rmempty = true + o.datatype = "neg(macaddr)" + o.placeholder = translate("any") + + luci.sys.net.mac_hints(function(mac, name) + o:value(mac, "%s (%s)" %{ mac, name }) + end) + + + o = s:option(Value, "src_ip", translate("Source IP address")) + o.rmempty = true + o.datatype = "neg(ipaddr)" + o.placeholder = translate("any") + + luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) + end) + + + o = s:option(Value, "src_port", + translate("Source port"), + translate("Match incoming traffic originating from the given source \ + port or port range on the client host.")) + o.rmempty = true + o.datatype = "neg(portrange)" + o.placeholder = translate("any") + + + o = s:option(Value, "dest", translate("Destination zone")) + o.nocreate = true + o.default = "lan" + o.template = "cbi/firewall_zonelist" + + + o = s:option(Value, "dest_ip", translate("Destination IP address")) + o.datatype = "neg(ip4addr)" + + luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) + end) + + + o = s:option(Value, "dest_port", + translate("Destination port"), + translate("Match forwarded traffic to the given destination port or \ + port range.")) + + o.rmempty = true + o.placeholder = translate("any") + o.datatype = "neg(portrange)" + + + o = s:option(Value, "src_dip", + translate("SNAT IP address"), + translate("Rewrite matched traffic to the given address.")) + o.rmempty = false + o.datatype = "ip4addr" + + for k, v in ipairs(nw:get_interfaces()) do + local a + for k, a in ipairs(v:ipaddrs()) do + o:value(a:host():string(), '%s (%s)' %{ + a:host():string(), v:shortname() + }) + end + end + + + o = s:option(Value, "src_dport", translate("SNAT port"), + translate("Rewrite matched traffic to the given source port. May be \ + left empty to only rewrite the IP address.")) + o.datatype = "portrange" + o.rmempty = true + o.placeholder = translate('Do not rewrite') + + + s:option(Value, "extra", + translate("Extra arguments"), + translate("Passes additional arguments to iptables. Use with care!")) + + +-- +-- Rule +-- +else + local name = m:get(arg[1], "name") or m:get(arg[1], "_name") + if not name or #name == 0 then + name = translate("(Unnamed Rule)") + end + + m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } + + + s = m:section(NamedSection, arg[1], "rule", "") + s.anonymous = true + s.addremove = false + + ft.opt_enabled(s, Button) + ft.opt_name(s, Value, translate("Name")) + + + o = s:option(ListValue, "family", translate("Restrict to address family")) + o.rmempty = true + o:value("", translate("IPv4 and IPv6")) + o:value("ipv4", translate("IPv4 only")) + o:value("ipv6", translate("IPv6 only")) + + + o = s:option(Value, "proto", translate("Protocol")) + o:value("all", translate("Any")) + o:value("tcp udp", "TCP+UDP") + o:value("tcp", "TCP") + o:value("udp", "UDP") + o:value("icmp", "ICMP") + + function o.cfgvalue(...) + local v = Value.cfgvalue(...) + if not v or v == "tcpudp" then + return "tcp udp" + end + return v + end + + + o = s:option(DynamicList, "icmp_type", translate("Match ICMP type")) + o:value("", "any") + o:value("echo-reply") + o:value("destination-unreachable") + o:value("network-unreachable") + o:value("host-unreachable") + o:value("protocol-unreachable") + o:value("port-unreachable") + o:value("fragmentation-needed") + o:value("source-route-failed") + o:value("network-unknown") + o:value("host-unknown") + o:value("network-prohibited") + o:value("host-prohibited") + o:value("TOS-network-unreachable") + o:value("TOS-host-unreachable") + o:value("communication-prohibited") + o:value("host-precedence-violation") + o:value("precedence-cutoff") + o:value("source-quench") + o:value("redirect") + o:value("network-redirect") + o:value("host-redirect") + o:value("TOS-network-redirect") + o:value("TOS-host-redirect") + o:value("echo-request") + o:value("router-advertisement") + o:value("router-solicitation") + o:value("time-exceeded") + o:value("ttl-zero-during-transit") + o:value("ttl-zero-during-reassembly") + o:value("parameter-problem") + o:value("ip-header-bad") + o:value("required-option-missing") + o:value("timestamp-request") + o:value("timestamp-reply") + o:value("address-mask-request") + o:value("address-mask-reply") + + + o = s:option(Value, "src", translate("Source zone")) + o.nocreate = true + o.allowany = true + o.default = "wan" + o.template = "cbi/firewall_zonelist" + + + o = s:option(Value, "src_mac", translate("Source MAC address")) + o.datatype = "list(macaddr)" + o.placeholder = translate("any") + + luci.sys.net.mac_hints(function(mac, name) + o:value(mac, "%s (%s)" %{ mac, name }) + end) + + + o = s:option(Value, "src_ip", translate("Source address")) + o.datatype = "neg(ipaddr)" + o.placeholder = translate("any") + + luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) + end) + + + o = s:option(Value, "src_port", translate("Source port")) + o.datatype = "list(neg(portrange))" + o.placeholder = translate("any") + + + o = s:option(Value, "dest", translate("Destination zone")) + o.nocreate = true + o.allowany = true + o.allowlocal = true + o.template = "cbi/firewall_zonelist" + + + o = s:option(Value, "dest_ip", translate("Destination address")) + o.datatype = "neg(ipaddr)" + o.placeholder = translate("any") + + luci.sys.net.ipv4_hints(function(ip, name) + o:value(ip, "%s (%s)" %{ ip, name }) + end) + + + o = s:option(Value, "dest_port", translate("Destination port")) + o.datatype = "list(neg(portrange))" + o.placeholder = translate("any") + + + o = s:option(ListValue, "target", translate("Action")) + o.default = "ACCEPT" + o:value("DROP", translate("drop")) + o:value("ACCEPT", translate("accept")) + o:value("REJECT", translate("reject")) + o:value("NOTRACK", translate("don't track")) + + + s:option(Value, "extra", + translate("Extra arguments"), + translate("Passes additional arguments to iptables. Use with care!")) +end + +return m diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/rules.lua b/1_1.mi_Lua/luci/model/cbi/firewall/rules.lua new file mode 100644 index 0000000..0f7462b --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/rules.lua @@ -0,0 +1,269 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2010-2012 Jo-Philipp Wich + +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 ds = require "luci.dispatcher" +local ft = require "luci.tools.firewall" + +m = Map("firewall", + translate("Firewall - Traffic Rules"), + translate("Traffic rules define policies for packets traveling between \ + different zones, for example to reject traffic between certain hosts \ + or to open WAN ports on the router.")) + +-- +-- Rules +-- + +s = m:section(TypedSection, "rule", translate("Traffic Rules")) +s.addremove = true +s.anonymous = true +s.sortable = true +s.template = "cbi/tblsection" +s.extedit = ds.build_url("admin/network/firewall/rules/%s") +s.defaults.target = "ACCEPT" +s.template_addremove = "firewall/cbi_addrule" + + +function s.create(self, section) + created = TypedSection.create(self, section) +end + +function s.parse(self, ...) + TypedSection.parse(self, ...) + + local i_n = m:formvalue("_newopen.name") + local i_p = m:formvalue("_newopen.proto") + local i_e = m:formvalue("_newopen.extport") + local i_x = m:formvalue("_newopen.submit") + + local f_n = m:formvalue("_newfwd.name") + local f_s = m:formvalue("_newfwd.src") + local f_d = m:formvalue("_newfwd.dest") + local f_x = m:formvalue("_newfwd.submit") + + if i_x then + created = TypedSection.create(self, section) + + self.map:set(created, "target", "ACCEPT") + self.map:set(created, "src", "wan") + self.map:set(created, "proto", (i_p ~= "other") and i_p or "all") + self.map:set(created, "dest_port", i_e) + self.map:set(created, "name", i_n) + + if i_p ~= "other" and i_e and #i_e > 0 then + created = nil + end + + elseif f_x then + created = TypedSection.create(self, section) + + self.map:set(created, "target", "ACCEPT") + self.map:set(created, "src", f_s) + self.map:set(created, "dest", f_d) + self.map:set(created, "name", f_n) + end + + if created then + m.uci:save("firewall") + luci.http.redirect(ds.build_url( + "admin/network/firewall/rules", created + )) + end +end + +ft.opt_name(s, DummyValue, translate("Name")) + +local function rule_proto_txt(self, s) + local f = self.map:get(s, "family") + local p = ft.fmt_proto(self.map:get(s, "proto"), + self.map:get(s, "icmp_type")) or "TCP+UDP" + + if f and f:match("4") then + return "%s-%s" %{ translate("IPv4"), p } + elseif f and f:match("6") then + return "%s-%s" %{ translate("IPv6"), p } + else + return "%s %s" %{ translate("Any"), p } + end +end + +local function rule_src_txt(self, s) + local z = ft.fmt_zone(self.map:get(s, "src"), translate("any zone")) + local a = ft.fmt_ip(self.map:get(s, "src_ip"), translate("any host")) + local p = ft.fmt_port(self.map:get(s, "src_port")) + local m = ft.fmt_mac(self.map:get(s, "src_mac")) + + if p and m then + return translatef("From %s in %s with source %s and %s", a, z, p, m) + elseif p or m then + return translatef("From %s in %s with source %s", a, z, p or m) + else + return translatef("From %s in %s", a, z) + end +end + +local function rule_dest_txt(self, s) + local z = ft.fmt_zone(self.map:get(s, "dest")) + local p = ft.fmt_port(self.map:get(s, "dest_port")) + + -- Forward + if z then + local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) + if p then + return translatef("To %s, %s in %s", a, p, z) + else + return translatef("To %s in %s", a, z) + end + + -- Input + else + local a = ft.fmt_ip(self.map:get(s, "dest_ip"), + translate("any router IP")) + + if p then + return translatef("To %s at %s on this device", a, p) + else + return translatef("To %s on this device", a) + end + end +end + +local function snat_dest_txt(self, s) + local z = ft.fmt_zone(self.map:get(s, "dest"), translate("any zone")) + local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) + local p = ft.fmt_port(self.map:get(s, "dest_port")) or + ft.fmt_port(self.map:get(s, "src_dport")) + + if p then + return translatef("To %s, %s in %s", a, p, z) + else + return translatef("To %s in %s", a, z) + end +end + + +match = s:option(DummyValue, "match", translate("Match")) +match.rawhtml = true +match.width = "70%" +function match.cfgvalue(self, s) + return "%s
%s
%s
" % { + rule_proto_txt(self, s), + rule_src_txt(self, s), + rule_dest_txt(self, s) + } +end + +target = s:option(DummyValue, "target", translate("Action")) +target.rawhtml = true +target.width = "20%" +function target.cfgvalue(self, s) + local t = ft.fmt_target(self.map:get(s, "target"), self.map:get(s, "dest")) + local l = ft.fmt_limit(self.map:get(s, "limit"), + self.map:get(s, "limit_burst")) + + if l then + return translatef("%s and limit to %s", t, l) + else + return "%s" % t + end +end + +ft.opt_enabled(s, Flag, translate("Enable")).width = "1%" + + +-- +-- SNAT +-- + +s = m:section(TypedSection, "redirect", + translate("Source NAT"), + translate("Source NAT is a specific form of masquerading which allows \ + fine grained control over the source IP used for outgoing traffic, \ + for example to map multiple WAN addresses to internal subnets.")) +s.template = "cbi/tblsection" +s.addremove = true +s.anonymous = true +s.sortable = true +s.extedit = ds.build_url("admin/network/firewall/rules/%s") +s.template_addremove = "firewall/cbi_addsnat" + +function s.create(self, section) + created = TypedSection.create(self, section) +end + +function s.parse(self, ...) + TypedSection.parse(self, ...) + + local n = m:formvalue("_newsnat.name") + local s = m:formvalue("_newsnat.src") + local d = m:formvalue("_newsnat.dest") + local a = m:formvalue("_newsnat.dip") + local p = m:formvalue("_newsnat.dport") + local x = m:formvalue("_newsnat.submit") + + if x and a and #a > 0 then + created = TypedSection.create(self, section) + + self.map:set(created, "target", "SNAT") + self.map:set(created, "src", s) + self.map:set(created, "dest", d) + self.map:set(created, "proto", "all") + self.map:set(created, "src_dip", a) + self.map:set(created, "src_dport", p) + self.map:set(created, "name", n) + end + + if created then + m.uci:save("firewall") + luci.http.redirect(ds.build_url( + "admin/network/firewall/rules", created + )) + end +end + +function s.filter(self, sid) + return (self.map:get(sid, "target") == "SNAT") +end + +ft.opt_name(s, DummyValue, translate("Name")) + +match = s:option(DummyValue, "match", translate("Match")) +match.rawhtml = true +match.width = "70%" +function match.cfgvalue(self, s) + return "%s
%s
%s
" % { + rule_proto_txt(self, s), + rule_src_txt(self, s), + snat_dest_txt(self, s) + } +end + +snat = s:option(DummyValue, "via", translate("Action")) +snat.rawhtml = true +snat.width = "20%" +function snat.cfgvalue(self, s) + local a = ft.fmt_ip(self.map:get(s, "src_dip")) + local p = ft.fmt_port(self.map:get(s, "src_dport")) + + if a and p then + return translatef("Rewrite to source %s, %s", a, p) + else + return translatef("Rewrite to source %s", a or p) + end +end + +ft.opt_enabled(s, Flag, translate("Enable")).width = "1%" + + +return m diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/zone-details.lua b/1_1.mi_Lua/luci/model/cbi/firewall/zone-details.lua new file mode 100644 index 0000000..c320d25 --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/zone-details.lua @@ -0,0 +1,243 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2010-2011 Jo-Philipp Wich + +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: zone-details.lua 8169 2012-01-09 05:48:27Z jow $ +]]-- + +local nw = require "luci.model.network" +local fw = require "luci.model.firewall" +local ds = require "luci.dispatcher" +local ut = require "luci.util" + +local m, p, i, v +local s, name, net, family, msrc, mdest, log, lim +local s2, out, inp + + +m = Map("firewall", translate("Firewall - Zone Settings")) +m.redirect = luci.dispatcher.build_url("admin/network/firewall/zones") + +fw.init(m.uci) +nw.init(m.uci) + + +local zone = fw:get_zone(arg[1]) +if not zone then + luci.http.redirect(dsp.build_url("admin/network/firewall/zones")) + return +else + m.title = "%s - %s" %{ + translate("Firewall - Zone Settings"), + translatef("Zone %q", zone:name() or "?") + } +end + + +s = m:section(NamedSection, zone.sid, "zone", + translatef("Zone %q", zone:name()), + translatef("This section defines common properties of %q. \ + The input and output options set the default \ + policies for traffic entering and leaving this zone while the \ + forward option describes the policy for forwarded traffic \ + between different networks within the zone. \ + Covered networks specifies which available networks are \ + member of this zone.", zone:name())) + +s.anonymous = true +s.addremove = false + +m.on_commit = function(map) + local zone = fw:get_zone(arg[1]) + if zone then + s.section = zone.sid + s2.section = zone.sid + end +end + + +s:tab("general", translate("General Settings")) +s:tab("advanced", translate("Advanced Settings")) + + +name = s:taboption("general", Value, "name", translate("Name")) +name.optional = false +name.forcewrite = true +name.datatype = "uciname" + +function name.write(self, section, value) + if zone:name() ~= value then + fw:rename_zone(zone:name(), value) + out.exclude = value + inp.exclude = value + end + + m.redirect = ds.build_url("admin/network/firewall/zones", value) + m.title = "%s - %s" %{ + translate("Firewall - Zone Settings"), + translatef("Zone %q", value or "?") + } +end + +p = { + s:taboption("general", ListValue, "input", translate("Input")), + s:taboption("general", ListValue, "output", translate("Output")), + s:taboption("general", ListValue, "forward", translate("Forward")) +} + +for i, v in ipairs(p) do + v:value("REJECT", translate("reject")) + v:value("DROP", translate("drop")) + v:value("ACCEPT", translate("accept")) +end + +s:taboption("general", Flag, "masq", translate("Masquerading")) +s:taboption("general", Flag, "mtu_fix", translate("MSS clamping")) + +net = s:taboption("general", Value, "network", translate("Covered networks")) +net.template = "cbi/network_netlist" +net.widget = "checkbox" +net.cast = "string" + +function net.formvalue(self, section) + return Value.formvalue(self, section) or "-" +end + +function net.cfgvalue(self, section) + return Value.cfgvalue(self, section) or name:cfgvalue(section) +end + +function net.write(self, section, value) + zone:clear_networks() + + local n + for n in ut.imatch(value) do + zone:add_network(n) + end +end + + +family = s:taboption("advanced", ListValue, "family", + translate("Restrict to address family")) + +family.rmempty = true +family:value("", translate("IPv4 and IPv6")) +family:value("ipv4", translate("IPv4 only")) +family:value("ipv6", translate("IPv6 only")) + +msrc = s:taboption("advanced", DynamicList, "masq_src", + translate("Restrict Masquerading to given source subnets")) + +msrc.optional = true +msrc.datatype = "list(neg(or(uciname,hostname,ip4addr)))" +msrc.placeholder = "0.0.0.0/0" +msrc:depends("family", "") +msrc:depends("family", "ipv4") + +mdest = s:taboption("advanced", DynamicList, "masq_dest", + translate("Restrict Masquerading to given destination subnets")) + +mdest.optional = true +mdest.datatype = "list(neg(or(uciname,hostname,ip4addr)))" +mdest.placeholder = "0.0.0.0/0" +mdest:depends("family", "") +mdest:depends("family", "ipv4") + +s:taboption("advanced", Flag, "conntrack", + translate("Force connection tracking")) + +log = s:taboption("advanced", Flag, "log", + translate("Enable logging on this zone")) + +log.rmempty = true +log.enabled = "1" + +lim = s:taboption("advanced", Value, "log_limit", + translate("Limit log messages")) + +lim.placeholder = "10/minute" +lim:depends("log", "1") + + +s2 = m:section(NamedSection, zone.sid, "fwd_out", + translate("Inter-Zone Forwarding"), + translatef("The options below control the forwarding policies between \ + this zone (%s) and other zones. Destination zones cover \ + forwarded traffic originating from %q. \ + Source zones match forwarded traffic from other zones \ + targeted at %q. The forwarding rule is \ + unidirectional, e.g. a forward from lan to wan does \ + not imply a permission to forward from wan to lan as well.", + zone:name(), zone:name(), zone:name() + + )) + +out = s2:option(Value, "out", + translate("Allow forward to destination zones:")) + +out.nocreate = true +out.widget = "checkbox" +out.exclude = zone:name() +out.template = "cbi/firewall_zonelist" + +inp = s2:option(Value, "in", + translate("Allow forward from source zones:")) + +inp.nocreate = true +inp.widget = "checkbox" +inp.exclude = zone:name() +inp.template = "cbi/firewall_zonelist" + +function out.cfgvalue(self, section) + local v = { } + local f + for _, f in ipairs(zone:get_forwardings_by("src")) do + v[#v+1] = f:dest() + end + return table.concat(v, " ") +end + +function inp.cfgvalue(self, section) + local v = { } + local f + for _, f in ipairs(zone:get_forwardings_by("dest")) do + v[#v+1] = f:src() + end + return v +end + +function out.formvalue(self, section) + return Value.formvalue(self, section) or "-" +end + +function inp.formvalue(self, section) + return Value.formvalue(self, section) or "-" +end + +function out.write(self, section, value) + zone:del_forwardings_by("src") + + local f + for f in ut.imatch(value) do + zone:add_forwarding_to(f) + end +end + +function inp.write(self, section, value) + zone:del_forwardings_by("dest") + + local f + for f in ut.imatch(value) do + zone:add_forwarding_from(f) + end +end + +return m diff --git a/1_1.mi_Lua/luci/model/cbi/firewall/zones.lua b/1_1.mi_Lua/luci/model/cbi/firewall/zones.lua new file mode 100644 index 0000000..de3b13f --- /dev/null +++ b/1_1.mi_Lua/luci/model/cbi/firewall/zones.lua @@ -0,0 +1,88 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +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: zones.lua 8108 2011-12-19 21:16:31Z jow $ +]]-- + +local ds = require "luci.dispatcher" +local fw = require "luci.model.firewall" + +local m, s, o, p, i, v + +m = Map("firewall", + translate("Firewall - Zone Settings"), + translate("The firewall creates zones over your network interfaces to control network traffic flow.")) + +fw.init(m.uci) + +s = m:section(TypedSection, "defaults", translate("General Settings")) +s.anonymous = true +s.addremove = false + +s:option(Flag, "syn_flood", translate("Enable SYN-flood protection")) + +o = s:option(Flag, "drop_invalid", translate("Drop invalid packets")) +o.default = o.disabled + +p = { + s:option(ListValue, "input", translate("Input")), + s:option(ListValue, "output", translate("Output")), + s:option(ListValue, "forward", translate("Forward")) +} + +for i, v in ipairs(p) do + v:value("REJECT", translate("reject")) + v:value("DROP", translate("drop")) + v:value("ACCEPT", translate("accept")) +end + + +s = m:section(TypedSection, "zone", translate("Zones")) +s.template = "cbi/tblsection" +s.anonymous = true +s.addremove = true +s.extedit = ds.build_url("admin", "network", "firewall", "zones", "%s") + +function s.create(self) + local z = fw:new_zone() + if z then + luci.http.redirect( + ds.build_url("admin", "network", "firewall", "zones", z.sid) + ) + end +end + +function s.remove(self, section) + return fw:del_zone(section) +end + +o = s:option(DummyValue, "_info", translate("Zone ⇒ Forwardings")) +o.template = "cbi/firewall_zoneforwards" +o.cfgvalue = function(self, section) + return self.map:get(section, "name") +end + +p = { + s:option(ListValue, "input", translate("Input")), + s:option(ListValue, "output", translate("Output")), + s:option(ListValue, "forward", translate("Forward")) +} + +for i, v in ipairs(p) do + v:value("REJECT", translate("reject")) + v:value("DROP", translate("drop")) + v:value("ACCEPT", translate("accept")) +end + +s:option(Flag, "masq", translate("Masquerading")) +s:option(Flag, "mtu_fix", translate("MSS clamping")) + +return m diff --git a/1_1.mi_Lua/luci/model/firewall.lua b/1_1.mi_Lua/luci/model/firewall.lua new file mode 100644 index 0000000..a9f6fdb --- /dev/null +++ b/1_1.mi_Lua/luci/model/firewall.lua @@ -0,0 +1,582 @@ +--[[ +LuCI - Firewall model + +Copyright 2009 Jo-Philipp Wich + +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/1_1.mi_Lua/luci/model/ipkg.lua b/1_1.mi_Lua/luci/model/ipkg.lua new file mode 100644 index 0000000..c927e71 --- /dev/null +++ b/1_1.mi_Lua/luci/model/ipkg.lua @@ -0,0 +1,239 @@ +--[[ +LuCI - Lua Configuration Interface + +(c) 2008-2011 Jo-Philipp Wich +(c) 2008 Steven Barth + +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/1_1.mi_Lua/luci/model/network.lua b/1_1.mi_Lua/luci/model/network.lua new file mode 100644 index 0000000..9a9a5f4 --- /dev/null +++ b/1_1.mi_Lua/luci/model/network.lua @@ -0,0 +1,1639 @@ +--[[ +LuCI - Network model + +Copyright 2009-2010 Jo-Philipp Wich + +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 +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_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 = nil + + _uci_state:foreach("wireless", "wifi-iface", + function(s) + if s.ifname == ifn then + sid = s['.name'] + return false + 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 = { } + + -- 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 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 + +function protocol.get_option_value(self,name) + return self:_get(name) +end + +function protocol.status(self) + local iface = uci.cursor_state():get_all("network", self.sid) + local proto = iface["proto"] + local ifname = iface["ifname"] + local device = iface["device"] + local up = tonumber(iface["up"]) + if proto == "pppoe" then + if device == nil then + return "down" + end + if up == nil then + return "connection" + end + if up == 1 then + return "up" + end + elseif proto == "3g" then + if device ~= ifname and up==nil then + return "down" + end + if device == ifname and up == nil then + return "connection" + end + if up == 1 then + return "up" + end + elseif proto == "static" then + if up == nil then + return "down" + end + if up == 1 then + return "up" + end + elseif proto == "dhcp" then + if up == nil then + return "down" + end + if up == 1 then + return "up" + end + end + return "unkown" +end + +interface = utl.class() + +function interface.__init__(self, ifname, network) + local wif = _wifi_lookup(ifname) + if wif then + self.wif = wifinet(wif) + self.ifname = _uci_state:get("wireless", 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) + if self.wif then + return self.wif:is_up() + else + return self:_ubus("up") or false + end +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) + 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 = _uci_state:get("wireless", 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.set_list(self, opt, val) + if val and type(val) == "table" and #val > 0 then + return _uci_real:set_list("wireless", self.sid, opt, val) + else + return _uci_real:delete("wireless", self.sid, opt) + end +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) + return (self.iwdata.up == "1") +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 + tostring(_uci_state:get("wireless", self.iwdata.device, "channel")) +end + +function wifinet.confchannel(self) + return tostring(_uci_state:get("wireless", self.iwdata.device, "channel")) +end + +function wifinet.bw(self) + return self.iwinfo.bw or + tostring(_uci_state:get("wireless", self.iwdata.device, "bw") or 0) +end + +function wifinet.confbw(self) + return tostring(_uci_state:get("wireless", self.iwdata.device, "bw") or 0) +end + +function wifinet.txpwr(self) + return self.iwinfo.txpwr or + tostring(_uci_state:get("wireless", self.iwdata.device, "txpwr")) +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/1_1.mi_Lua/luci/model/network/proto_ppp.lua b/1_1.mi_Lua/luci/model/network/proto_ppp.lua new file mode 100644 index 0000000..dfd545f --- /dev/null +++ b/1_1.mi_Lua/luci/model/network/proto_ppp.lua @@ -0,0 +1,104 @@ +--[[ +LuCI - Network model - 3G, PPP, PPtP, PPPoE and PPPoA protocol extension + +Copyright 2011 Jo-Philipp Wich + +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 netmod = luci.model.network + +local _, p +for _, p in ipairs({"ppp", "pptp", "pppoe", "pppoa", "3g", "l2tp"}) do + + local proto = netmod:register_protocol(p) + + function proto.get_i18n(self) + if p == "ppp" then + return luci.i18n.translate("PPP") + elseif p == "pptp" then + return luci.i18n.translate("PPtP") + elseif p == "3g" then + return luci.i18n.translate("UMTS/GPRS/EV-DO") + elseif p == "pppoe" then + return luci.i18n.translate("PPPoE") + elseif p == "pppoa" then + return luci.i18n.translate("PPPoATM") + elseif p == "l2tp" then + return luci.i18n.translate("L2TP") + end + end + + function proto.ifname(self) + return p .. "-" .. self.sid + end + + function proto.opkg_package(self) + if p == "ppp" then + return p + elseif p == "3g" then + return "comgt" + elseif p == "pptp" then + return "ppp-mod-pptp" + elseif p == "pppoe" then + return "ppp-mod-pppoe" + elseif p == "pppoa" then + return "ppp-mod-pppoa" + elseif p == "l2tp" then + return "xl2tpd" + end + end + + function proto.is_installed(self) + if p == "pppoa" then + return (nixio.fs.glob("/usr/lib/pppd/*/pppoatm.so")() ~= nil) + elseif p == "pppoe" then + return (nixio.fs.glob("/usr/lib/pppd/*/rp-pppoe.so")() ~= nil) + elseif p == "pptp" then + return (nixio.fs.glob("/usr/lib/pppd/*/pptp.so")() ~= nil) + elseif p == "3g" then + return nixio.fs.access("/lib/netifd/proto/3g.sh") + elseif p == "l2tp" then + return nixio.fs.access("/lib/netifd/proto/l2tp.sh") + else + return nixio.fs.access("/lib/netifd/proto/ppp.sh") + end + end + + function proto.is_floating(self) + return (p ~= "pppoe") + end + + function proto.is_virtual(self) + return true + end + + function proto.get_interfaces(self) + if self:is_floating() then + return nil + else + return netmod.protocol.get_interfaces(self) + end + end + + function proto.contains_interface(self, ifc) + if self:is_floating() then + return (netmod:ifnameof(ifc) == self:ifname()) + else + return netmod.protocol.contains_interface(self, ifc) + end + end + + netmod:register_pattern_virtual("^%s-%%w" % p) +end diff --git a/1_1.mi_Lua/luci/model/uci.lua b/1_1.mi_Lua/luci/model/uci.lua new file mode 100644 index 0000000..61ac344 --- /dev/null +++ b/1_1.mi_Lua/luci/model/uci.lua @@ -0,0 +1,404 @@ +--[[ +LuCI - UCI model + +Description: +Generalized UCI model + +FileId: +$Id: uci.lua 8127 2011-12-20 19:02:14Z jow $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/sauth.lua b/1_1.mi_Lua/luci/sauth.lua new file mode 100644 index 0000000..2aa8c2c --- /dev/null +++ b/1_1.mi_Lua/luci/sauth.lua @@ -0,0 +1,165 @@ +--[[ + +Session authentication +(c) 2008 Steven Barth + +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: sauth.lua 8900 2012-08-08 09:48:47Z jow $ + +]]-- + +--- 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" + +local XQLog = require("xiaoqiang.XQLog") + +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 tempid = luci.sys.uniqueid(16) + local tempfile = sessionpath .. "/" .. tempid + local sessfile = sessionpath .. "/" .. id + local f = nixio.open(tempfile, "w", 600) + f:writeall(data) + f:close() + fs.rename(tempfile, sessfile) +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 + + if not _checkid(id) then + XQLog.log(3,"Security Exception: Session ID is invalid! sauth.write") + return + end + + if type(data) ~= "table" then + XQLog.log(3,"Security Exception: Session data invalid! sauth.write") + return + end + + 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 + + if not _checkid(id) then + XQLog.log(3,"Security Exception: Session ID is invalid! sauth.read") + return nil + end + + if not sane(sessionpath .. "/" .. id) then + return nil + end + + local blob = _read(id) + local func = loadstring(blob) + setfenv(func, {}) + + local sess = func() + if type(sess) ~= "table" then + XQLog.log(3,"Security Exception: Session data invalid! sauth.read") + return nil + end + + 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) + if not _checkid(id) then + XQLog.log(3,"Security Exception: Session ID is invalid! sauth.kill") + else + fs.unlink(sessionpath .. "/" .. id) + end +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 + +--- Get available session data +function available() + 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 + local available = read(id) + if available then + return available + end + end + end + end + return nil +end \ No newline at end of file diff --git a/1_1.mi_Lua/luci/sgi/cgi.lua b/1_1.mi_Lua/luci/sgi/cgi.lua new file mode 100644 index 0000000..babf650 --- /dev/null +++ b/1_1.mi_Lua/luci/sgi/cgi.lua @@ -0,0 +1,95 @@ +--[[ +LuCI - SGI-Module for CGI + +Description: +Server Gateway Interface for CGI + +FileId: +$Id: cgi.lua 6535 2010-11-23 01:02:21Z soma $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/sgi/uhttpd.lua b/1_1.mi_Lua/luci/sgi/uhttpd.lua new file mode 100644 index 0000000..5915b69 --- /dev/null +++ b/1_1.mi_Lua/luci/sgi/uhttpd.lua @@ -0,0 +1,121 @@ +--[[ +LuCI - Server Gateway Interface for the uHTTPd server + +Copyright 2010 Jo-Philipp Wich + +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 = 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 function send(...) + return uhttpd.send(...) + end + + local function sendc(...) + if env.HTTP_VERSION > 1.0 then + return uhttpd.sendc(...) + else + return uhttpd.send(...) + end + end + + 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 + + if env.HTTP_VERSION > 1.0 then + hcache["Transfer-Encoding"] = "chunked" + end + + while coroutine.status(x) ~= "dead" do + local res, id, data1, data2 = coroutine.resume(x, req) + + if not res then + send(env.SERVER_PROTOCOL) + send(" 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(env.SERVER_PROTOCOL) + send(" ") + 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 + sendc(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/1_1.mi_Lua/luci/store.lua b/1_1.mi_Lua/luci/store.lua new file mode 100644 index 0000000..c33ef07 --- /dev/null +++ b/1_1.mi_Lua/luci/store.lua @@ -0,0 +1,16 @@ +--[[ + +LuCI - Lua Development Framework +(c) 2009 Steven Barth +(c) 2009 Jo-Philipp Wich + +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/1_1.mi_Lua/luci/sys.lua b/1_1.mi_Lua/luci/sys.lua new file mode 100644 index 0000000..3867214 --- /dev/null +++ b/1_1.mi_Lua/luci/sys.lua @@ -0,0 +1,966 @@ +--[[ +LuCI - System library + +Description: +Utilities for interaction with the Linux system + +FileId: +$Id: sys.lua 9623 2013-01-18 14:08:37Z jow $ + +License: +Copyright 2008 Steven Barth + +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 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 +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, 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 ][= 1 on error +function user.setpasswd(username, password) + if username and username:lower()=="admin" then + username = "root" + end + 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/1_1.mi_Lua/luci/sys/iptparser.lua b/1_1.mi_Lua/luci/sys/iptparser.lua new file mode 100644 index 0000000..90b00f2 --- /dev/null +++ b/1_1.mi_Lua/luci/sys/iptparser.lua @@ -0,0 +1,371 @@ +--[[ + +Iptables parser and query library +(c) 2008-2009 Jo-Philipp Wich +(c) 2008-2009 Steven Barth + +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: iptparser.lua 6826 2011-01-29 22:47:40Z jow $ + +]]-- + +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: +--
    +--
  • table - Match rules that are located within the given table +--
  • chain - Match rules that are located within the given chain +--
  • target - Match rules with the given target +--
  • protocol - Match rules that match the given protocol, rules with +-- protocol "all" are always matched +--
  • source - Match rules with the given source, rules with source +-- "0.0.0.0/0" (::/0) are always matched +--
  • destination - Match rules with the given destination, rules with +-- destination "0.0.0.0/0" (::/0) are always matched +--
  • inputif - Match rules with the given input interface, rules +-- with input interface "*" (=all) are always matched +--
  • outputif - Match rules with the given output interface, rules +-- with output interface "*" (=all) are always matched +--
  • flags - Match rules that match the given flags, current +-- supported values are "-f" (--fragment) +-- and "!f" (! --fragment) +--
  • options - Match rules containing all given options +--
+-- The return value is a list of tables representing the matched rules. +-- Each rule table contains the following fields: +--
    +--
  • index - The index number of the rule +--
  • table - The table where the rule is located, can be one +-- of "filter", "nat" or "mangle" +--
  • chain - The chain where the rule is located, e.g. "INPUT" +-- or "postrouting_wan" +--
  • target - The rule target, e.g. "REJECT" or "DROP" +--
  • protocol The matching protocols, e.g. "all" or "tcp" +--
  • flags - Special rule options ("--", "-f" or "!f") +--
  • inputif - Input interface of the rule, e.g. "eth0.0" +-- or "*" for all interfaces +--
  • outputif - Output interface of the rule,e.g. "eth0.0" +-- or "*" for all interfaces +--
  • source - The source ip range, e.g. "0.0.0.0/0" (::/0) +--
  • destination - The destination ip range, e.g. "0.0.0.0/0" (::/0) +--
  • options - A list of specific options of the rule, +-- e.g. { "reject-with", "tcp-reset" } +--
  • packets - The number of packets matched by the rule +--
  • bytes - The number of total bytes matched by the rule +--
+-- Example: +--
+-- ip = luci.sys.iptparser.IptParser()
+-- result = ip.find( {
+-- 	target="REJECT",
+-- 	protocol="tcp",
+-- 	options={ "reject-with", "tcp-reset" }
+-- } )
+-- 
+-- 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 - 1 do + rule_details["options"][i-10] = rule_parts[i] + 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/1_1.mi_Lua/luci/sys/zoneinfo.lua b/1_1.mi_Lua/luci/sys/zoneinfo.lua new file mode 100644 index 0000000..f5a12bf --- /dev/null +++ b/1_1.mi_Lua/luci/sys/zoneinfo.lua @@ -0,0 +1,28 @@ +--[[ +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/1_1.mi_Lua/luci/sys/zoneinfo/tzdata.lua b/1_1.mi_Lua/luci/sys/zoneinfo/tzdata.lua new file mode 100644 index 0000000..1a99f6a --- /dev/null +++ b/1_1.mi_Lua/luci/sys/zoneinfo/tzdata.lua @@ -0,0 +1,420 @@ +--[[ +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/1_1.mi_Lua/luci/sys/zoneinfo/tzoffset.lua b/1_1.mi_Lua/luci/sys/zoneinfo/tzoffset.lua new file mode 100644 index 0000000..bbe75d5 --- /dev/null +++ b/1_1.mi_Lua/luci/sys/zoneinfo/tzoffset.lua @@ -0,0 +1,162 @@ +--[[ +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/1_1.mi_Lua/luci/template.lua b/1_1.mi_Lua/luci/template.lua new file mode 100644 index 0000000..4c1816a --- /dev/null +++ b/1_1.mi_Lua/luci/template.lua @@ -0,0 +1,107 @@ +--[[ +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: template.lua 9558 2012-12-18 13:58:22Z jow $ + +License: +Copyright 2008 Steven Barth + +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/1_1.mi_Lua/luci/template/parser.so b/1_1.mi_Lua/luci/template/parser.so new file mode 100644 index 0000000..18d8b7a Binary files /dev/null and b/1_1.mi_Lua/luci/template/parser.so differ diff --git a/1_1.mi_Lua/luci/tools/firewall.lua b/1_1.mi_Lua/luci/tools/firewall.lua new file mode 100644 index 0000000..26240aa --- /dev/null +++ b/1_1.mi_Lua/luci/tools/firewall.lua @@ -0,0 +1,291 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011-2012 Jo-Philipp Wich + +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.tools.firewall", package.seeall) + +local ut = require "luci.util" +local ip = require "luci.ip" +local nx = require "nixio" + +local translate, translatef = luci.i18n.translate, luci.i18n.translatef + +local function tr(...) + return tostring(translate(...)) +end + +function fmt_neg(x) + if type(x) == "string" then + local v, neg = x:gsub("^ *! *", "") + if neg > 0 then + return v, "%s " % tr("not") + else + return x, "" + end + end + return x, "" +end + +function fmt_mac(x) + if x and #x > 0 then + local m, n + local l = { tr("MAC"), " " } + for m in ut.imatch(x) do + m, n = fmt_neg(m) + l[#l+1] = "%s%s" %{ n, m } + l[#l+1] = ", " + end + if #l > 1 then + l[#l] = nil + if #l > 3 then + l[1] = tr("MACs") + end + return table.concat(l, "") + end + end +end + +function fmt_port(x, d) + if x and #x > 0 then + local p, n + local l = { tr("port"), " " } + for p in ut.imatch(x) do + p, n = fmt_neg(p) + local a, b = p:match("(%d+)%D+(%d+)") + if a and b then + l[1] = tr("ports") + l[#l+1] = "%s%d-%d" %{ n, a, b } + else + l[#l+1] = "%s%d" %{ n, p } + end + l[#l+1] = ", " + end + if #l > 1 then + l[#l] = nil + if #l > 3 then + l[1] = tr("ports") + end + return table.concat(l, "") + end + end + return d and "%s" % d +end + +function fmt_ip(x, d) + if x and #x > 0 then + local l = { tr("IP"), " " } + local v, a, n + for v in ut.imatch(x) do + v, n = fmt_neg(v) + a, m = v:match("(%S+)/(%d+%.%S+)") + a = a or v + a = a:match(":") and ip.IPv6(a, m) or ip.IPv4(a, m) + if a and (a:is6() and a:prefix() < 128 or a:prefix() < 32) then + l[1] = tr("IP range") + l[#l+1] = "%s%s" %{ + a:minhost():string(), + a:maxhost():string(), + n, a:string() + } + else + l[#l+1] = "%s%s" %{ + n, + a and a:string() or v + } + end + l[#l+1] = ", " + end + if #l > 1 then + l[#l] = nil + if #l > 3 then + l[1] = tr("IPs") + end + return table.concat(l, "") + end + end + return d and "%s" % d +end + +function fmt_zone(x, d) + if x == "*" then + return "%s" % tr("any zone") + elseif x and #x > 0 then + return "%s" % x + elseif d then + return "%s" % d + end +end + +function fmt_icmp_type(x) + if x and #x > 0 then + local t, v, n + local l = { tr("type"), " " } + for v in ut.imatch(x) do + v, n = fmt_neg(v) + l[#l+1] = "%s%s" %{ n, v } + l[#l+1] = ", " + end + if #l > 1 then + l[#l] = nil + if #l > 3 then + l[1] = tr("types") + end + return table.concat(l, "") + end + end +end + +function fmt_proto(x, icmp_types) + if x and #x > 0 then + local v, n + local l = { } + local t = fmt_icmp_type(icmp_types) + for v in ut.imatch(x) do + v, n = fmt_neg(v) + if v == "tcpudp" then + l[#l+1] = "TCP" + l[#l+1] = ", " + l[#l+1] = "UDP" + l[#l+1] = ", " + elseif v ~= "all" then + local p = nx.getproto(v) + if p then + -- ICMP + if (p.proto == 1 or p.proto == 58) and t then + l[#l+1] = translatef( + "%s%s with %s", + n, p.aliases[1] or p.name, t + ) + else + l[#l+1] = "%s%s" %{ + n, + p.aliases[1] or p.name + } + end + l[#l+1] = ", " + end + end + end + if #l > 0 then + l[#l] = nil + return table.concat(l, "") + end + end +end + +function fmt_limit(limit, burst) + burst = tonumber(burst) + if limit and #limit > 0 then + local l, u = limit:match("(%d+)/(%w+)") + l = tonumber(l or limit) + u = u or "second" + if l then + if u:match("^s") then + u = tr("second") + elseif u:match("^m") then + u = tr("minute") + elseif u:match("^h") then + u = tr("hour") + elseif u:match("^d") then + u = tr("day") + end + if burst and burst > 0 then + return translatef("%d pkts. per %s, \ + burst %d pkts.", l, u, burst) + else + return translatef("%d pkts. per %s", l, u) + end + end + end +end + +function fmt_target(x, dest) + if dest and #dest > 0 then + if x == "ACCEPT" then + return tr("Accept forward") + elseif x == "REJECT" then + return tr("Refuse forward") + elseif x == "NOTRACK" then + return tr("Do not track forward") + else --if x == "DROP" then + return tr("Discard forward") + end + else + if x == "ACCEPT" then + return tr("Accept input") + elseif x == "REJECT" then + return tr("Refuse input") + elseif x == "NOTRACK" then + return tr("Do not track input") + else --if x == "DROP" then + return tr("Discard input") + end + end +end + + +function opt_enabled(s, t, ...) + if t == luci.cbi.Button then + local o = s:option(t, "__enabled") + function o.render(self, section) + if self.map:get(section, "enabled") ~= "0" then + self.title = tr("Rule is enabled") + self.inputtitle = tr("Disable") + self.inputstyle = "reset" + else + self.title = tr("Rule is disabled") + self.inputtitle = tr("Enable") + self.inputstyle = "apply" + end + t.render(self, section) + end + function o.write(self, section, value) + if self.map:get(section, "enabled") ~= "0" then + self.map:set(section, "enabled", "0") + else + self.map:del(section, "enabled") + end + end + return o + else + local o = s:option(t, "enabled", ...) + o.enabled = "" + o.disabled = "0" + o.default = o.enabled + return o + end +end + +function opt_name(s, t, ...) + local o = s:option(t, "name", ...) + + function o.cfgvalue(self, section) + return self.map:get(section, "name") or + self.map:get(section, "_name") or "-" + end + + function o.write(self, section, value) + if value ~= "-" then + self.map:set(section, "name", value) + self.map:del(section, "_name") + else + self:remove(section) + end + end + + function o.remove(self, section) + self.map:del(section, "name") + self.map:del(section, "_name") + end + + return o +end diff --git a/1_1.mi_Lua/luci/tools/proto.lua b/1_1.mi_Lua/luci/tools/proto.lua new file mode 100644 index 0000000..4df0269 --- /dev/null +++ b/1_1.mi_Lua/luci/tools/proto.lua @@ -0,0 +1,46 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2012 Jo-Philipp Wich + +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.tools.proto", package.seeall) + +function opt_macaddr(s, ifc, ...) + local v = luci.cbi.Value + local o = s:taboption("advanced", v, "macaddr", ...) + + o.placeholder = ifc and ifc:mac() + o.datatype = "macaddr" + + function o.cfgvalue(self, section) + local w = ifc and ifc:get_wifinet() + if w then + return w:get("macaddr") + else + return v.cfgvalue(self, section) + end + end + + function o.write(self, section, value) + local w = ifc and ifc:get_wifinet() + if w then + w:set("macaddr", value) + elseif value then + v.write(self, section, value) + else + v.remove(self, section) + end + end + + function o.remove(self, section) + self:write(section, nil) + end +end diff --git a/1_1.mi_Lua/luci/tools/status.lua b/1_1.mi_Lua/luci/tools/status.lua new file mode 100644 index 0000000..13d3ea4 --- /dev/null +++ b/1_1.mi_Lua/luci/tools/status.lua @@ -0,0 +1,216 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2011 Jo-Philipp Wich + +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.tools.status", package.seeall) + +local uci = require "luci.model.uci".cursor() + +local function dhcp_leases_common(family) + local rv = { } + local nfs = require "nixio.fs" + local leasefile = "/var/dhcp.leases" + + uci:foreach("dhcp", "dnsmasq", + function(s) + if s.leasefile and nfs.access(s.leasefile) then + leasefile = s.leasefile + return false + end + end) + + local fd = io.open(leasefile, "r") + if fd then + while true do + local ln = fd:read("*l") + if not ln then + break + else + local ts, mac, ip, name, duid = ln:match("^(%d+) (%S+) (%S+) (%S+) (%S+)") + if ts and mac and ip and name and duid then + if family == 4 and not ip:match(":") then + rv[#rv+1] = { + expires = os.difftime(tonumber(ts) or 0, os.time()), + macaddr = mac, + ipaddr = ip, + hostname = (name ~= "*") and name + } + elseif family == 6 and ip:match(":") then + rv[#rv+1] = { + expires = os.difftime(tonumber(ts) or 0, os.time()), + ip6addr = ip, + duid = (duid ~= "*") and duid, + hostname = (name ~= "*") and name + } + end + end + end + end + fd:close() + end + + return rv +end + +function dhcp_leases() + return dhcp_leases_common(4) +end + +function dhcp6_leases() + local nfs = require "nixio.fs" + local leasefile = "/tmp/hosts/6relayd" + local rv = {} + + if nfs.access(leasefile, "r") then + local fd = io.open(leasefile, "r") + if fd then + while true do + local ln = fd:read("*l") + if not ln then + break + else + local iface, duid, iaid, name, ts, id, length, ip = ln:match("^# (%S+) (%S+) (%S+) (%S+) (%d+) (%S+) (%S+) (.*)") + if ip then + rv[#rv+1] = { + expires = os.difftime(tonumber(ts) or 0, os.time()), + duid = duid, + ip6addr = ip, + hostname = (name ~= "-") and name + } + end + end + end + fd:close() + end + return rv + elseif luci.sys.call("dnsmasq --version 2>/dev/null | grep -q ' DHCPv6 '") == 0 then + return dhcp_leases_common(6) + end +end + +function wifi_networks() + local rv = { } + local ntm = require "luci.model.network".init() + + local dev + for _, dev in ipairs(ntm:get_wifidevs()) do + local rd = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n(), + networks = { } + } + + local net + for _, net in ipairs(dev:get_wifinets()) do + rd.networks[#rd.networks+1] = { + name = net:shortname(), + link = net:adminlink(), + up = net:is_up(), + mode = net:active_mode(), + ssid = net:active_ssid(), + bssid = net:active_bssid(), + encryption = net:active_encryption(), + frequency = net:frequency(), + channel = net:channel(), + signal = net:signal(), + quality = net:signal_percent(), + noise = net:noise(), + bitrate = net:bitrate(), + ifname = net:ifname(), + assoclist = net:assoclist(), + country = net:country(), + txpower = net:txpower(), + txpoweroff = net:txpower_offset() + } + end + + rv[#rv+1] = rd + end + + return rv +end + +function wifi_network(id) + local ntm = require "luci.model.network".init() + local net = ntm:get_wifinet(id) + if net then + local dev = net:get_device() + if dev then + return { + id = id, + name = net:shortname(), + link = net:adminlink(), + up = net:is_up(), + mode = net:active_mode(), + ssid = net:active_ssid(), + bssid = net:active_bssid(), + encryption = net:active_encryption(), + frequency = net:frequency(), + channel = net:channel(), + signal = net:signal(), + quality = net:signal_percent(), + noise = net:noise(), + bitrate = net:bitrate(), + ifname = net:ifname(), + assoclist = net:assoclist(), + country = net:country(), + txpower = net:txpower(), + txpoweroff = net:txpower_offset(), + device = { + up = dev:is_up(), + device = dev:name(), + name = dev:get_i18n() + } + } + end + end + return { } +end + +function switch_status(devs) + local dev + local switches = { } + for dev in devs:gmatch("[^%s,]+") do + local ports = { } + local swc = io.popen("swconfig dev %q show" % dev, "r") + if swc then + local l + repeat + l = swc:read("*l") + if l then + local port, up = l:match("port:(%d+) link:(%w+)") + if port then + local speed = l:match(" speed:(%d+)") + local duplex = l:match(" (%w+)-duplex") + local txflow = l:match(" (txflow)") + local rxflow = l:match(" (rxflow)") + local auto = l:match(" (auto)") + + ports[#ports+1] = { + port = tonumber(port) or 0, + speed = tonumber(speed) or 0, + link = (up == "up"), + duplex = (duplex == "full"), + rxflow = (not not rxflow), + txflow = (not not txflow), + auto = (not not auto) + } + end + end + until not l + swc:close() + end + switches[dev] = ports + end + return switches +end diff --git a/1_1.mi_Lua/luci/tools/webadmin.lua b/1_1.mi_Lua/luci/tools/webadmin.lua new file mode 100644 index 0000000..11232ae --- /dev/null +++ b/1_1.mi_Lua/luci/tools/webadmin.lua @@ -0,0 +1,173 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: webadmin.lua 4168 2009-01-27 17:15:14Z jow $ +]]-- + +module("luci.tools.webadmin", package.seeall) +local uci = require("luci.model.uci") +require("luci.sys") +require("luci.ip") + +function byte_format(byte) + local suff = {"B", "KB", "MB", "GB", "TB"} + for i=1, 5 do + if byte > 1024 and i < 5 then + byte = byte / 1024 + else + return string.format("%.2f %s", byte, suff[i]) + end + end +end + +function date_format(secs) + local suff = {"min", "h", "d"} + local mins = 0 + local hour = 0 + local days = 0 + + secs = math.floor(secs) + if secs > 60 then + mins = math.floor(secs / 60) + secs = secs % 60 + end + + if mins > 60 then + hour = math.floor(mins / 60) + mins = mins % 60 + end + + if hour > 24 then + days = math.floor(hour / 24) + hour = hour % 24 + end + + if days > 0 then + return string.format("%.0fd %02.0fh %02.0fmin %02.0fs", days, hour, mins, secs) + else + return string.format("%02.0fh %02.0fmin %02.0fs", hour, mins, secs) + end +end + +function network_get_addresses(net) + local state = uci.cursor_state() + state:load("network") + local addr = {} + local ipv4 = state:get("network", net, "ipaddr") + local mav4 = state:get("network", net, "netmask") + local ipv6 = state:get("network", net, "ip6addr") + + if ipv4 and #ipv4 > 0 then + if mav4 and #mav4 == 0 then mav4 = nil end + + ipv4 = luci.ip.IPv4(ipv4, mav4) + + if ipv4 then + table.insert(addr, ipv4:string()) + end + end + + if ipv6 then + table.insert(addr, ipv6) + end + + state:foreach("network", "alias", + function (section) + if section.interface == net then + if section.ipaddr and section.netmask then + local ipv4 = luci.ip.IPv4(section.ipaddr, section.netmask) + + if ipv4 then + table.insert(addr, ipv4:string()) + end + end + + if section.ip6addr then + table.insert(addr, section.ip6addr) + end + end + end + ) + + return addr +end + +function cbi_add_networks(field) + uci.cursor():foreach("network", "interface", + function (section) + if section[".name"] ~= "loopback" then + field:value(section[".name"]) + end + end + ) + field.titleref = luci.dispatcher.build_url("admin", "network", "network") +end + +function cbi_add_knownips(field) + for i, dataset in ipairs(luci.sys.net.arptable()) do + field:value(dataset["IP address"]) + end +end + +function network_get_zones(net) + local state = uci.cursor_state() + if not state:load("firewall") then + return nil + end + + local zones = {} + + state:foreach("firewall", "zone", + function (section) + local znet = section.network or section.name + if luci.util.contains(luci.util.split(znet, " "), net) then + table.insert(zones, section.name) + end + end + ) + + return zones +end + +function firewall_find_zone(name) + local find + + luci.model.uci.cursor():foreach("firewall", "zone", + function (section) + if section.name == name then + find = section[".name"] + end + end + ) + + return find +end + +function iface_get_network(iface) + local state = uci.cursor_state() + state:load("network") + local net + + state:foreach("network", "interface", + function (section) + local ifname = state:get( + "network", section[".name"], "ifname" + ) + + if iface == ifname then + net = section[".name"] + end + end + ) + + return net +end diff --git a/1_1.mi_Lua/luci/util.lua b/1_1.mi_Lua/luci/util.lua new file mode 100644 index 0000000..6260856 --- /dev/null +++ b/1_1.mi_Lua/luci/util.lua @@ -0,0 +1,855 @@ +--[[ +LuCI - Utility library + +Description: +Several common useful Lua functions + +License: +Copyright 2008 Steven Barth + +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) + 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) + v = _serialize_data(v) + 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]) + 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) + assert(not hasRecursion(val), "Recursion detected.") + return _serialize_data(val) +end + +function _serialize_data(val) + 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) .. " }" + else + return '"[unhandled data type:' .. type(val) .. ']"' + end +end + +-- Check weather a table has Recursion, if true, it cant be serialized +function hasRecursion(t) + if t == nil or type(t) ~= "table" then + return false + end + + local seen = {} + -- add root to seen + seen[t] = true + return hasR(t, seen) +end + +function hasR(t, seen) + for k, v in pairs(t) do + if type(k) == "table" then + if seen[k] then + -- check is recursion + local tmp = t + while true do + if tmp == k then + return true + else + tmp = seen[tmp] + if not tmp then + break + end + end + end + -- check end + end + + seen[k] = t + if hasR(k, seen) then + return true + end + end + + if type(v) == "table" then + if seen[v] then + -- check is recursion + local tmp = t + while true do + if tmp == v then + return true + else + tmp = seen[tmp] + if not tmp then + break + end + end + end + -- check end + end + + seen[v] = t + if hasR(v, seen) then + return true + end + end + end + + return false +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/1_1.mi_Lua/luci/version.lua b/1_1.mi_Lua/luci/version.lua new file mode 100644 index 0000000..2a45ce2 --- /dev/null +++ b/1_1.mi_Lua/luci/version.lua @@ -0,0 +1,14 @@ +local pcall, dofile, _G = pcall, dofile, _G + +module "luci.version" + +if pcall(dofile, "/etc/openwrt_release") and _G.DISTRIB_DESCRIPTION then + distname = "" + distversion = _G.DISTRIB_DESCRIPTION +else + distname = "OpenWrt Firmware" + distversion = "Attitude Adjustment (r40348)" +end + +luciname = "LuCI 0.11.1 Release" +luciversion = "0.11.1" diff --git a/1_1.mi_Lua/luci/view/error404.htm b/1_1.mi_Lua/luci/view/error404.htm new file mode 100644 index 0000000..c0c7662 --- /dev/null +++ b/1_1.mi_Lua/luci/view/error404.htm @@ -0,0 +1,19 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: error404.htm 9014 2012-08-14 13:08:18Z jow $ + +-%> +<%+header%> +

404 <%:Not Found%>

+

<%:Sorry, the object you requested was not found.%>

+<%:Unable to dispatch%>: <%=luci.http.request.env.PATH_INFO%> +<%+footer%> diff --git a/1_1.mi_Lua/luci/view/error500.htm b/1_1.mi_Lua/luci/view/error500.htm new file mode 100644 index 0000000..b00c4c3 --- /dev/null +++ b/1_1.mi_Lua/luci/view/error500.htm @@ -0,0 +1,19 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: error500.htm 9014 2012-08-14 13:08:18Z jow $ + +-%> +<%+header%> +

500 <%:Internal Server Error%>

+

<%:Sorry, the server encountered an unexpected error.%>

+
<%=message%>
+<%+footer%> diff --git a/1_1.mi_Lua/luci/view/firewall/cbi_addforward.htm b/1_1.mi_Lua/luci/view/firewall/cbi_addforward.htm new file mode 100644 index 0000000..3726f64 --- /dev/null +++ b/1_1.mi_Lua/luci/view/firewall/cbi_addforward.htm @@ -0,0 +1,115 @@ +<%- + local fw = require "luci.model.firewall".init() + local izl = { } + local ezl = { } + local _, z + for _, z in ipairs(fw:get_zones()) do + if z:name() ~= "wan" then + izl[#izl+1] = z + elseif z:name() ~= "lan" then + ezl[#ezl+1] = z + end + end +-%> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
<%:New port forward%>:
<%:Name%><%:Protocol%><%:External zone%><%:External port%><%:Internal zone%><%:Internal IP address%><%:Internal port%>
+ + + + + + + + + + + + + + + +
+ + +
diff --git a/1_1.mi_Lua/luci/view/firewall/cbi_addrule.htm b/1_1.mi_Lua/luci/view/firewall/cbi_addrule.htm new file mode 100644 index 0000000..463b2e0 --- /dev/null +++ b/1_1.mi_Lua/luci/view/firewall/cbi_addrule.htm @@ -0,0 +1,112 @@ +<% + local fw = require "luci.model.firewall".init() + local wz = fw:get_zone("wan") + local lz = fw:get_zone("lan") +%> + +
+ <% if wz and lz then %> +
+ + + + + + + + + + + + + + + + +
<%:Open ports on router%>:
<%:Name%><%:Protocol%><%:External port%>
+ + + + + + + +
+ + + + + + + + + + + + + + + + + +

<%:New forward rule%>:
<%:Name%><%:Source zone%><%:Destination zone%>
+ + + + + + + +
+ + + <% else %> + + <% end %> +
diff --git a/1_1.mi_Lua/luci/view/firewall/cbi_addsnat.htm b/1_1.mi_Lua/luci/view/firewall/cbi_addsnat.htm new file mode 100644 index 0000000..4e1681c --- /dev/null +++ b/1_1.mi_Lua/luci/view/firewall/cbi_addsnat.htm @@ -0,0 +1,66 @@ +<% + local fw = require "luci.model.firewall".init() + local nw = require "luci.model.network".init() + local wz = fw:get_zone("wan") + local lz = fw:get_zone("lan") +%> + +
+ <% if wz and lz then %> +
+ + + + + + + + + + + + + + + + + + + + +
<%:New source NAT%>:
<%:Name%><%:Source zone%><%:Destination zone%><%:To source IP%><%:To source port%>
+ + + + + + + + + + + +
+ + + <% else %> + + <% end %> +
diff --git a/1_1.mi_Lua/luci/view/footer.htm b/1_1.mi_Lua/luci/view/footer.htm new file mode 100644 index 0000000..d2c2a2e --- /dev/null +++ b/1_1.mi_Lua/luci/view/footer.htm @@ -0,0 +1,15 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: footer.htm 3552 2008-10-10 14:37:53Z Cyrus $ + +-%> +<% include("themes/" .. theme .. "/footer") %> \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/header.htm b/1_1.mi_Lua/luci/view/header.htm new file mode 100644 index 0000000..36bee1b --- /dev/null +++ b/1_1.mi_Lua/luci/view/header.htm @@ -0,0 +1,21 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: header.htm 4234 2009-02-09 13:17:26Z jow $ + +-%> + +<% + if not luci.dispatcher.context.template_header_sent then + include("themes/" .. theme .. "/header") + luci.dispatcher.context.template_header_sent = true + end +%> diff --git a/1_1.mi_Lua/luci/view/index.htm b/1_1.mi_Lua/luci/view/index.htm new file mode 100644 index 0000000..2ed60b2 --- /dev/null +++ b/1_1.mi_Lua/luci/view/index.htm @@ -0,0 +1,22 @@ +<% + local home = luci.dispatcher.build_url("web", "home") +%> + + + + + + + + +小米路由器 + + + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/indexer.htm b/1_1.mi_Lua/luci/view/indexer.htm new file mode 100644 index 0000000..ded34d2 --- /dev/null +++ b/1_1.mi_Lua/luci/view/indexer.htm @@ -0,0 +1,15 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: indexer.htm 3552 2008-10-10 14:37:53Z Cyrus $ + +-%> +<% include("themes/" .. theme .. "/indexer") %> \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/mobile/home.htm b/1_1.mi_Lua/luci/view/mobile/home.htm new file mode 100644 index 0000000..d0ac6b1 --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/home.htm @@ -0,0 +1,23 @@ + +<% + local XQVersion = require("xiaoqiang.XQVersion") + local ver = XQVersion.webVersion + local web = luci.dispatcher.build_url("web", "home") +%> + + + + + + + 小米路由器 + + + +

页面跳转中...

+<%include("mobile/inc/footer")%> + + + diff --git a/1_1.mi_Lua/luci/view/mobile/inc/footer.htm b/1_1.mi_Lua/luci/view/mobile/inc/footer.htm new file mode 100644 index 0000000..874e029 --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/inc/footer.htm @@ -0,0 +1,30 @@ + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/mobile/inc/header.htm b/1_1.mi_Lua/luci/view/mobile/inc/header.htm new file mode 100644 index 0000000..5bf4d74 --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/inc/header.htm @@ -0,0 +1,3 @@ +
+

小米路由器

+
\ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/mobile/init/agreement.htm b/1_1.mi_Lua/luci/view/mobile/init/agreement.htm new file mode 100644 index 0000000..6033a38 --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/init/agreement.htm @@ -0,0 +1,26 @@ + +<% +local ver = require("xiaoqiang.XQVersion").webVersion +%> + + + + + + + + 小米路由器 + + + + <%include("mobile/inc/header")%> +
+
+
+ <%include('web/inc/agreement')%> +
+
+
+ <%include("mobile/inc/footer")%> + + diff --git a/1_1.mi_Lua/luci/view/mobile/init/guide.htm b/1_1.mi_Lua/luci/view/mobile/init/guide.htm new file mode 100644 index 0000000..2add08e --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/init/guide.htm @@ -0,0 +1,340 @@ + +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local sys = require("xiaoqiang.util.XQSysUtil") +if sys.getInitInfo() then + luci.http.redirect(luci.dispatcher.build_url("web", "home")) +end +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local fun = require("xiaoqiang.common.XQFunction") +local wifiInfo = wifiUtil.getAllWifiInfo() +local ssid = "" +if wifiInfo[1] then + ssid = wifiInfo[1]['ssid'] +end + +local remote_addr = luci.http.getenv("REMOTE_ADDR") +local mac = luci.sys.net.ip4mac(remote_addr) +%> + + + + + + + 小米路由器 + + + + <%include("mobile/inc/header")%> +
+ + + + + + + + +
+ <%include("mobile/inc/footer")%> + + + + + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/mobile/init/hello.htm b/1_1.mi_Lua/luci/view/mobile/init/hello.htm new file mode 100644 index 0000000..3bac27c --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/init/hello.htm @@ -0,0 +1,111 @@ + +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local sys = require("xiaoqiang.util.XQSysUtil") +if sys.getInitInfo() then + luci.template.render("mobile/sysauth") +else + sys.setSysPasswordDefault() +end +%> + + + + + + + + 小米路由器 + + + + + + + <%include("mobile/inc/footer")%> + + + + + + diff --git a/1_1.mi_Lua/luci/view/mobile/sysauth.htm b/1_1.mi_Lua/luci/view/mobile/sysauth.htm new file mode 100644 index 0000000..75b92b1 --- /dev/null +++ b/1_1.mi_Lua/luci/view/mobile/sysauth.htm @@ -0,0 +1,51 @@ + +<% + local XQVersion = require("xiaoqiang.XQVersion") + local ver = XQVersion.webVersion + local sys = require("xiaoqiang.util.XQSysUtil") + local binded = sys.getInitInfo() and 'true' or 'false' + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local androidClient = XQVersion.androidClientRouter +%> + + + + + + + 小米路由器 + + + + <%include("mobile/inc/header")%> + + <%include("mobile/inc/footer")%> + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/themes/openwrt.org/footer.htm b/1_1.mi_Lua/luci/view/themes/openwrt.org/footer.htm new file mode 100644 index 0000000..32355f6 --- /dev/null +++ b/1_1.mi_Lua/luci/view/themes/openwrt.org/footer.htm @@ -0,0 +1,21 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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: footer.htm 7364 2011-08-13 09:52:12Z jow $ + +-%> +
+ + + +

Powered by <%= luci.__appname__ .. " (" .. luci.__version__ .. ")" %>

+ + diff --git a/1_1.mi_Lua/luci/view/themes/openwrt.org/header.htm b/1_1.mi_Lua/luci/view/themes/openwrt.org/header.htm new file mode 100644 index 0000000..d069f76 --- /dev/null +++ b/1_1.mi_Lua/luci/view/themes/openwrt.org/header.htm @@ -0,0 +1,186 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008-2010 Jo-Philipp Wich + +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: header.htm 9558 2012-12-18 13:58:22Z jow $ + +-%> +<% + local sys = require "luci.sys" + local http = require "luci.http" + local disp = require "luci.dispatcher" + + local hostname = sys.hostname() + local load1, load5, load15 = sys.loadavg() + + local request = disp.context.path + local request2 = disp.context.request + + local category = request[1] + local cattree = category and disp.node(category) + + local leaf = request2[#request2] + + local tree = disp.node() + local node = disp.context.dispatched + + local categories = disp.node_childs(tree) + + local c = tree + local i, r + + -- tag all nodes leading to this page + for i, r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end + end + + http.prepare_content("application/xhtml+xml") + + local function nodeurl(prefix, name, query) + local url = controller .. prefix .. name .. "/" + if query then + url = url .. http.build_querystring(query) + end + return pcdata(url) + end + + local function subtree(prefix, node, level) + if not level then + level = 1 + end + + local childs = disp.node_childs(node) + if #childs > 0 then +%> +
+
    + <% + local selected_node + local selected_name + local i, v + + for i, v in ipairs(childs) do + local nnode = node.nodes[v] + if nnode._menu_selected then + selected_node = nnode + selected_name = v + end + %> +
  • + <%=striptags(translate(nnode.title))%> +
  • + <% + end + %> +
+
+<% + if selected_node then + subtree(prefix .. selected_name .. "/", selected_node, level + 1) + end +%> +
+<% + end + end +-%> + + + + + + + + + + + +<% if node and node.css then %> +<% end -%> +<% if css then %> +<% end -%> + +<%=striptags( hostname .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI + + + + + + + +
+
+ <% if category then subtree("/" .. category .. "/", cattree) end %> +
+ +
+ + + <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") and category ~= "failsafe" then -%> +
+ <%:No password set!%>
+ <%:There is no password set on this router. Please configure a root password to protect the web interface and enable SSH.%>
+ "><%:Go to password configuration...%> +
+ <%- end -%> diff --git a/1_1.mi_Lua/luci/view/themes/xiaoqiang/footer.htm b/1_1.mi_Lua/luci/view/themes/xiaoqiang/footer.htm new file mode 100644 index 0000000..e69de29 diff --git a/1_1.mi_Lua/luci/view/themes/xiaoqiang/header.htm b/1_1.mi_Lua/luci/view/themes/xiaoqiang/header.htm new file mode 100644 index 0000000..84d0121 --- /dev/null +++ b/1_1.mi_Lua/luci/view/themes/xiaoqiang/header.htm @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/application.htm b/1_1.mi_Lua/luci/view/web/application.htm new file mode 100644 index 0000000..7aa15ff --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/application.htm @@ -0,0 +1,27 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +小米路由器 + + + +
+ <%include ("web/inc/header")%> + + + +
+

施工中,敬请期待...

+
+ <%include ("web/inc/footer")%> +
+<%include ("web/inc/g.js")%> +<%include ("web/inc/reboot.js")%> + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/gateway.htm b/1_1.mi_Lua/luci/view/web/gateway.htm new file mode 100644 index 0000000..eff5052 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/gateway.htm @@ -0,0 +1,130 @@ + + + + + + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/gateway.html b/1_1.mi_Lua/luci/view/web/gateway.html new file mode 100644 index 0000000..0f5a4e7 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/gateway.html @@ -0,0 +1,61 @@ + + + + + + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/inc/agreement.htm b/1_1.mi_Lua/luci/view/web/inc/agreement.htm new file mode 100644 index 0000000..ecad7f2 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/agreement.htm @@ -0,0 +1,558 @@ +

+ 用户许可使用协议 +

+

+ 【重要提示】 +

+

+ 请您在开始使用小米路由器系列产品(以下简称“本产品”)之前请务必仔细阅读并理解《用户许可使用协议》(以下简称“本协议”)中规定的所有权利和限制。 +

+

+ 小米科技有限责任公司(以下简称“小米”或“我们”)一向尊重并会严格保护用户在使用本产品时的合法权益(包括用户隐私、用户数据等)不受到任何侵犯。 +

+

+ 本产品包括但不限于小米路由器硬件与小米路由器相关软件(包括小米路由器软件操作系统和名为“小米路由”的移动设备端软件应用、PC电脑端软件应用和Mac电脑端软件应用以及小米路由器云服务等产品)及其相关的、均由小米开发的产品。本产品中相关的知识产权(包括本产品的一切版权、专利权、商标权等)均属于小米。 +

+

+ 本协议(包括本文最后部分的隐私政策)是用户(包括通过各种合法途径获取到本产品的自然人、法人或其他组织机构,以下简称“用户”或“您“)与小米之间针对本产品相关事项最终的、完整的且排他的协议,并取代、合并之前的当事人之间关于上述事项的讨论和协议。 +

+

+ 本协议将对用户使用本产品的行为产生法律约束力,您已承诺和保证有权利和能力订立本协议。用户开始使用本产品将视为已经接受本协议,请认真阅读并理解本协议中各条款,包括免除和限制小米责任的免责条款和对用户的权利限制(未成年人审阅时应由法定监护人陪同),如果您不能接受本协议中的全部条款,请勿开始使用本产品。(如果您已经购买我们的硬件产品但无法接受本协议中的全部条款,如需要,硬件产品部分的相关退货政策请查阅http://www.xiaomi.com ) +

+

+ 1、使用 +

+

+ 1.1 帐户 +

+

+ 您无需用户账户即可使用小米路由器。如果您想使用本产品更多功能,您需要注册小米账号并且于注册页面上提供相关的个人信息。您必须承诺和保证: +

+

+ 1.1.1 您提交的所有注册信息必须真实准确; +

+

+ 1.1.2 您使用小米路由器的行为必须合法; +

+

+ 1.1.3 您可以按照小米账号使用说明随时终止使用您的账户。 +

+

+ 本产品将会依据本协议第5条的规定保留或终止您的账户。您必须承诺对您的登录信息保密、不被其他人获取与使用,并且对您在本网站账户下的所有行为负责。您必须将任何有可能触犯法律的、未授权使用或怀疑为未授权使用的行为在第一时间通知本产品。本产品不对您因未能遵守上述要求而造成的损失承担法律责任。 +

+

+ 1.2 网络加速与故障检测服务 +

+

+ 在您使用本产品的过程中,有部分使用场景本产品会在征询您的同意之后对您在使用过程中的一部分网络访问行为进行检测。此举旨在帮助您进行网络加速与并在必要的时候执行故障检测服务。该检测全部由软件程序完成,不会有任何人为监控,只是使用相关的软件程序进行匹配并指引您打开相应的第三方内容或页面。我们承诺将全力确保您在使用本产品过程中的隐私不会被泄露。 +

+

+ 2、终端用户协议 +

+

+ 2.1 许可 +

+

+ 依据本协议规定,本产品将授予您以下不可转让的、非排他的许可: +

+

+ 2.1.1 使用本产品的权利; +

+

+ 2.1.2 在您所有的网络通信过程中下载、安装、使用本产品的权利。 +

+

+ 2.2 限制性条款 +

+

+ 本协议对您的授权将受到以下限制: +

+

+ 2.2.1 您不得对本产品进行任何形式的许可、出售、租赁、转让、发行或其他商业用途; +

+

+ 2.2.2 除非法律禁止此类限制,否则您不得对本产品的任何部分或衍生产品进行修改、翻译、改编、合并、利用、分解、改造或反向编译等; +

+

+ 2.2.3 您不得以创建相同或竞争服务为目的使用本产品; +

+

+ 2.2.4 除非法律明文规定,否则您不得对本产品的任何部分以任何形式或方法进行生产、复制、发行、出售、下载或显示等; +

+

+ 2.2.5 您不得删除或破坏包含在本产品中的任何版权声明或其他所有权标记。 +

+

+ 2.3 权利归属 +

+

+ 2.3.1 小米许可您使用、下载本产品; +

+

+ 2.3.2 小米(及其“授权人”,如有)拥有本产品的所有相关知识产权。 +

+

+ 2.4 费用 +

+

+ 您必须自行负担购买本产品的费用,个人上网或第三方(包括但不限于电信或移动通讯提供商)收取的通讯费、信息费等相关费用。如涉及电信增值服务,我们建议您与增值服务提供商确认相关费用问题。 +

+

+ 2.5 任何本产品的更新版本或未来版本、更新或者其他变更将受到本协议约束。 +

+

+ 3、用户内容 +

+

+ 3.1 用户内容 +

+

+ 3.1.1 用户内容是指该用户下载、发布或以其他方式使用本产品时产生的所有内容(例如:您的信息、图片、音乐或其他内容)。 +

+

+ 3.1.2 您是您的用户内容唯一的责任人,您将承担因您的用户内容披露而导致的您或任何第三方被识别的风险。 +

+

+ 3.1.3 您已同意您的用户内容受到第4条的限制。 +

+

+ 3.2 反馈 +

+

+ 3.2.1 您对小米提出的建议(或称“反馈”),即视为您向小米转让“反馈”的全部权利并同意小米有权利以任何合理方式使用此反馈及其相关信息。我们将视此类反馈信息为非保密且非专有; +

+

+ 3.2.2 您已同意您不会向小米提供任何您视为保密和专有的信息。 +

+

+ 3.3 我们将保留基于我们的判断检查用户分享内容的权利(而非义务) +

+

+ 无论通知与否,我们有权在任何时间以任何理由删除和移动您的用户分享内容。依据第5条规定,我们有权保留或终止您的账户。 +

+

+ 4、权利限制 +

+

+ 4.1 您已同意通过分享或其他方式使用本产品中的相关服务,在使用过程中,您将承担因下述行为所造成的风险而产生的全部法律责任: +

+

+ 4.1.1 破坏宪法所确定的基本原则的; +

+

+ 4.1.2 危害国家安全、泄露国家秘密、颠覆国家政权、破坏国家统一的; +

+

+ 4.1.3 损害国家荣誉和利益的; +

+

+ 4.1.4 煽动民族仇恨、民族歧视,破坏民族团结的; +

+

+ 4.1.5 破坏国家宗教政策,宣扬邪教和封建迷信的; +

+

+ 4.1.6 散布谣言,扰乱社会秩序,破坏社会稳定的; +

+

+ 4.1.7 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的; +

+

+ 4.1.8 侮辱或者诽谤他人,侵害他人合法权益的; +

+

+ 4.1.9 含有法律、行政法规禁止的其他内容的。 +

+

+ 4.2 您已同意不在本产品从事下列行为: +

+

+ 4.2.1 发布或分享电脑病毒、蠕虫、恶意代码、故意破坏或改变计算机系统或数据的软件; +

+

+ 4.2.2 未授权的情况下,收集其他用户的信息或数据,例如电子邮箱地址等; +

+

+ 4.2.3 用自动化的方式恶意使用本产品,给服务器造成过度的负担或以其他方式干扰或损害网站服务器和网络链接; +

+

+ 4.2.4 在未授权的情况下,尝试访问本产品的服务器数据或通信数据; +

+

+ 4.2.5 干扰、破坏本产品其他用户的使用。 +

+

+ 5、修改和终止 +

+

+ 5.1 修改 +

+

+ 5.1.1 本协议容许变更。如果本协议有任何实质性变更,我们将通过您的电子邮件或本产品的公告来通知您。变更通知之后,继续使用本产品则视为您已知晓此类变更并同意受条款约束。 +

+

+ 5.1.2 小米保留在任何时候无需通知而修改、保留或关闭本产品任何服务之权利。 +

+

+ 5.1.3 您已同意小米无需因修改、保留或关闭本产品任何服务的行为对您或第三方承担责任。 +

+

+ 5.2 终止 +

+

+ 5.2.1 本协议自您接受之日起生效,在您使用本产品的过程中持续有效,直至依据本协议终止; +

+

+ 5.2.2 尽管有上述规定,如果您使用本产品的时间早于您接受本协议的时间,您在此知晓并同意本协议于您第一次使用本产品时生效,除非依据本协议提前终止; +

+

+ 5.2.3 我们可能会(1)依据法律的规定,保留您使用本产品或者本网站账户的权利;(2)无论是否通知,我们将在任何时间以任何原因终止本协议,包括出于善意的相信您违反了我们可接受使用政策或本协议的其他规定; +

+

+ 5.2.4 不受前款规定所限,如果用户侵犯第三人的版权且小米接到版权所有人或版权所有人的合法代理人的通知后,小米保留终止本协议的权利; +

+

+ 5.2.5 一旦本协议终止,您使用本产品的权利即告终止。您应当知晓您的产品终止意味着您的用户内容将从我们的活动数据库中删除。小米不因终止本协议对您承担任何责任,包括终止您的用户账户和删除您的用户内容。 +

+

+ 6、第三方 +

+

+ 6.1 您已知晓或同意我们的部分服务是基于第三方的技术支持获得。 +

+

+ 例如苹果 iPhone 、安卓系统等。您已知晓本协议是在您与小米之间签订,而非您与上述第三方之间签订。小米是基于本产品所产生的内容、维护、支持服务、保证和由此产生的诉讼等事项的唯一责任人。您已同意遵守且授权给本产品限制您有条件地使用本产品的服务。 +

+

+ 6.2 第三方信息和服务 +

+

+ 6.2.1 本产品包含了第三方的部分信息和服务。小米不控制且不对第三方的信息和服务负责。 +

+

+ 6.2.2 小米仅为您使用方便之目的或为承诺和保证第三方之需要而提供此类信息和服务。 +

+

+ 6.2.3 您需对您使用第三方信息和服务产生的风险承担法律责任。 +

+

+ 6.2.4 当您访问第三方信息和服务时,适用第三方的条款和政策。 +

+

+ 6.3 其他用户 +

+

+ 6.3.1 本产品包含其他用户提供的用户内容。本产品不控制且不对用户内容承担法律责任。本产品没有检查、监控、审批、核准、承诺并保证用户内容的义务。您必须因使用用户内容和与其他用户互动产生的风险承担法律责任。 +

+

+ 6.3.2 您与其他用户的互动仅属于您与其他用户之间的行为,本产品对此类行为不承担任何法律责任。您已同意本产品对此类互动行为的结果不承担法律责任。 +

+

+ 7、赔偿 +

+

+ 7.1 您已同意无害地使用本产品,避免小米因下述行为或相关行为遭受来自第三方的任何投诉、诉讼、损失、损害、责任、成本和费用(包括律师费): +

+

+ 7.1.1 您使用本产品的行为; +

+

+ 7.1.2 您的用户内容; +

+

+ 7.1.3 您违反本协议的行为。 +

+

+ 7.2 小米保留专属抗辩权和请求赔偿的权利。 +

+

+ 7.3 您已同意,除非获得小米书面同意,您不得在您与小米共同对第三方提起的诉讼中单方和解。 +

+

+ 7.4 小米将尽合理努力将此类诉讼、诉讼行为或进程通知您。 +

+

+ 7.5 在任何情况下,本产品都不对您或任何第三方因本协议产生的任何间接性、后果性、惩戒性的、偶然的、特殊或惩罚性的损害赔偿承担责任。访问、使用本产品所产生的损坏计算机系统或移动通讯设备数据库的风险将由您个人承担。 +

+

+ 8、免责声明 +

+

+ 8.1 如发生下述情形,本产品不承担任何法律责任: +

+

+ 8.1.1 依据法律规定或相关政府部门的要求提供您的个人信息; +

+

+ 8.1.2 由于您的使用不当而导致任何个人信息的泄露; +

+

+ 8.1.3 任何由于黑客攻击,电脑病毒侵入,非法内容信息,骚扰信息的屏蔽,政府管制以及其他任何网络、技术、通信线路、信息安全管理措施等原因造成的服务中断、受阻等不能满足用户要求的情形; +

+

+ 8.1.4 用户因第三方如运营商的通讯线路故障、技术问题、网络、电脑故障、系统不稳定及其他因不可抗力造成的损失的情形; +

+

+ 8.1.5 使用本产品可能存在的来自他人匿名或冒名的含有威胁、诽谤、令人反感或非法内容的信息而招致的风险; +

+

+ 8.1.6 本产品明文声明,不以明示或默示及以任何形式对本产品及其合作公司服务之及时性、安全性、准确性做出担保。 +

+

+ 9、隐私政策 +

+

+ “小米路由器系列产品隐私政策”为本协议的一部分,您可以在本文的最后部分找到。请您认真阅读并理解隐私协议中的所有内容。 +

+

+ 10、通知 +

+

+ 10.1 用户必须在小米账号中提供您最近经常使用的有效的电子邮件地址。您所提供的电子邮件地址无法使用或者因任何原因我们无法将通知送达给您而产生的风险,本产品不承担责任。 +

+

+ 10.2 本产品发布的公告通知及向您所发送的包含此类通知的电子邮件毫无疑问构成有效通知。 +

+

+ 11、适用法律 +

+

+ 11.1 本协议适用中华人民共和国法律。 +

+

+ 11.2 如果双方发生纠纷,应本着友好的原则协商解决;如协商不成,应向小米所在地的法院提起诉讼。 +

+

+ 12、独立性 +

+

+ 本协议中的某些条款因故无法适用,则本协议的其他条款继续适用且无法适用的条款将会被修改,以便其能够依法适用。 +

+

+ 13、完整性 +

+

+ 13.1 本协议(包括隐私政策)是您和本产品之间关于本产品相关事项的最终的、完整的、排他的协议,且取代和合并之前当事人关于此类事项(包括之前的最终用户许可、服务条款和隐私政策)的讨论和协议。 +

+

+ 13.2 每部分的题目只为阅读之便而无任何法律或合同义务。 +

+

+ 13.3 除非小米书面同意,您不得转让本协议所规定的权利义务。任何违反上述规定企图转让的行为均无效。 +

+

+
+

+

+ 隐私政策 +

+

+ 您可以通过多种不同的方式使用我们的服务,例如登录小米官网购买小米路由器硬件产品、在不同的终端上使用小米路由软件产品、服务等。如果您与我们分享信息(例如,通过创建一个小米帐户),我们就能为您提供更好的服务,如显示相关程度更高的产品更新和广告、帮助您与他人联系或者更轻松快捷地与他人分享内容等。基于此目的,我们将向您解释我们对信息的收集和使用方式,以及您可采用什么方式来保护自己的隐私权。 +

+

+ 我们的隐私政策包括了以下几个方面的问题: +

+

+ • 我们收集哪些信息。 +

+

+ • 我们如何收集和使用信息。 +

+

+ • 您如何选择性提供这些信息,以及如何访问和更新这些信息。 +

+

+ • 信息的分享、安全以及隐私政策的适用范围和修订。 +

+

+ 1、我们收集的信息 +

+

+ 我们收集您的两种信息:个人信息(个人信息是可用于唯一地识别或联系某人的数据)和非个人信息(即不会与任何特定个人直接相关联的数据)。如果我们将非个人信息与个人信息合并在一起,在保持合并的期间内,此类信息将被视为个人信息。 +

+

+ 我们收集您的两种信息:个人信息(个人信息是可用于唯一地识别或联系某人的数据)和非个人信息(即不会与任何特定个人直接相关联的数据)。如果我们将非个人信息与个人信息合并在一起,在保持合并的期间内,此类信息将被视为个人信息。 +

+

+ 2、我们如何收集和利用的信息 +

+

+ 您与北京小米科技有限责任公司(以下简称“小米”或“我们”)及其关联公司进行互动时,您可能会被要求提供您同意使用我们基本产品服务所必需的某些个人信息。该个人信息可能与其他信息合并在一起,被用于改进我们的产品或服务等。下文是小米可能收集的个人信息的类型以及我们如何使用该信息的一些示例。 +

+

+ 2.1 个人信息的收集 +

+

+ • 当您创建小米账户、下载及更新小米软件、在小米手机在线零售店注册、参加在线调查或者参加其他与小米公司的互动时,我们会要求您提供个人信息,包括但不限于您的姓名、电话号码、电子邮件地址、邮寄地址等。 +

+

+ • 当您购买小米产品和服务时,我们会收集有关个人信息,包括但不限于:交货详情、银行帐号、信用卡详情、账单地址、信用核查以及其他财务信息、联系及交流的记录等。 +

+

+ • 当您使用小米产品与家人和朋友分享您的内容、发送信息和产品或者在小米论坛上邀请其他人时,小米会收集您提供的与上述人士有关的个人信息,如姓名、邮寄地址、电子邮件地址及电话号码等 +

+

+ • 当您首次使用并激活小米移动设备时,您的移动用户识别信息、移动设备唯一识别码以及您设备的大概地理位置信息将被发送给小米。上述信息的收集也可能适用于您更新系统或软件、恢复出厂设置等情况。 +

+

+ 2.2 个人信息的使用 +

+

+ • 小米将严格遵守本隐私政策及其更新所载明的内容来使用您的个人信息。您的个人信息将仅用于收集时即已确定并且经过您同意的目的,如有除此之外的任何其他用途,我们都会提前征得您的同意。 +

+

+ • 我们收集的个人信息将被用于向您提供小米的产品和服务、处理您的订单或履行您与小米之间的合同,以确保我们产品和服务的功能和安全、验证您的身份、防止并追究欺诈或其他不当使用的情形。 +

+

+ • 我们收集的个人信息将被用于我们的产品和服务开发,尽管一般情况下,我们为此目的仅使用综合信息和统计性信息。 +

+

+ • 我们收集的个人信息将被用于与您进行交流,例如,在小米产品或服务更新、发布的第一时间向您发出通知。 +

+

+ • 我们所收集的个人信息将被用于进行产品的个性化设计,并向您提供更为贴身的服务,例如:在我们的服务中进行推荐、展示专为您打造的内容和广告或者用于调研。 +

+

+ • 如果您参与小米举办的抽奖、竞赛或类似推广活动,我们会将您提供的个人信息用于管理此类活动。 +

+

+ • 您的移动用户识别信息、移动设备唯一识别码和地理位置信息可被用来激活您的保修服务和特定的软件许可,并可能邀请您参加调查。我们也会使用此等信息用于改善我们的产品和分析我们业务运营的效率。但我们不会用此等信息来追踪您的位置情况。 +

+

+ 2.3 非个人信息的使用 +

+

+ • 当您创建小米账户、下载小米软件及其更新、在小米手机在线零售店注册、参加在线调查或者参加其他与小米公司的互动时,我们会收集您诸如职业、语言、邮编、区号以及使用小米产品所在的时区等信息。 +

+

+ • 使用习惯和发现问题相关的信息——当您在使用小米路由器的部分应用时,我们会根据需要,匿名统计一部分您对网络使用的情况从而为您提供更好的上网体验。此外,当小米路由器系统发生非正常状态或崩溃时,我们将可能会收集一些便于诊断问题的环境信息如设备ID、互联网协议地址、路由数据包等。 +

+

+ • Cookies和其他技术收集的信息——小米的网站、在线服务、互动应用软件、电子邮件消息和广告宣传可能会使用cookies以及如像素标签和网站信标的其他技术来收集和存储您的非个人信息。 +

+

+ • 日志信息——当您访问小米服务器时,我们的服务器会自动记录某些日志信息。这类服务器日志信息可能包含如下信息:IP 地址、浏览器类型、浏览器语言、refer来源页、操作系统时间标记和点击流数据。 +

+

+ • 我们收集的诸如职业、语言、邮编、区号以及使用小米产品所在的时区等非个人信息,可以帮助我们更好地了解用户行为,改进我们的产品、服务和广告宣传。 +

+

+ • 日志信息——当您访问小米服务器时,我们的服务器会自动记录某些日志信息。这类服务器日志信息可能包含如下信息:IP 地址、浏览器类型、浏览器语言、refer来源页、操作系统时间标记和点击流数据。 +

+

+ • 我们可以通过分析小米“用户体验改进计划”获取的统计数据来持续不断地提升产品和服务的操作体验、运行性能、修复问题、改善功能设计等。 +

+

+ • 我们通过使用 cookies 和其他技术(例如像素标签)收集到的信息,为您带来更好的用户体验,并提高我们的总体服务品质。例如,通过保存您的语言偏好设置,我们可以用您的首选语言显示我们的服务。我们可以通过使用像素标签向用户发送可阅读格式的电子邮件,并告知我们邮件是否被打开。我们可将此等信息用于减少向用户发送电子邮件或者不向用户发送电子邮件。 +

+

+ 每个人对于隐私权的关注各有侧重,基于此,我们将明确指出我们收集信息的方式,以便您选择接受信息的提供方式。 +

+

+ • 您可以自由设定是否加入“用户体验改进计划”,即可以通过关闭“用户体验改进计划”项的开关从而退出该计划。 +

+

+ • 您可以从设备设置上修改您设备的定位设置,例如:变更或禁用定位方法或定位服务器,或修改您位置信息的准确性,从而改变向小米提供的位置信息。 +

+

+ • 您可以根据自己的需要来修改浏览器的设置以拒绝或接受 cookies,也可以随时从您存储设备中将其删除,或者在写入cookies时通知您。 +

+

+ 3、个人信息的访问和更新 +

+

+ 通过点击[https://account.xiaomi.com]来登录你的账户,您能够访问并更新自己的个人信息,您也可以删除部分个人信息或者要求我们删除您的个人账户,除非我们出于法律方面的原因而必须保留这些信息。 +

+

+ 无论您在何时使用我们的服务,我们都力求让您能够访问自己的个人信息。如果这些信息有误,我们会努力通过各种方式让您快速更新信息或删除信息(除非我们出于合法业务或法律方面的原因而必须保留这些信息)。在更新您的个人信息时,我们可能会要求您先验证自己的身份,然后再处理您的请求。 +

+

+ 对于那些无端重复、需要过多技术投入、对他人隐私权造成风险或者非常不切实际的请求,我们可能予以拒绝。 +

+

+ 只要我们能够让您访问和修改信息,而且其不需要过多投入,则我们会免费提供。我们力求对服务进行完善的维护,以保护信息免遭意外或恶意的破坏。因此,当您从我们的服务中删除信息后,我们可能不会立即从在用的 +

+

+ 服务器中删除这些信息的残留副本,也可能不会从备份系统中删除相应的信息。 +

+

+ 4、和第三方分享信息 +

+

+ 除非本隐私政策载明的有限共享,我们会严格保密您的个人信息并不会向第三方共享您的个人信息。 +

+

+ 您于此授权,以下情形我们将会向第三方共享您的个人信息而无需通过您的同意: +

+

+ • 我们因法律调查、诉讼、强制执行或其它法律强制性规定或要求,而同第三方共享这些个人信息。 +

+

+ • 我们将个人信息提供给我们的子公司、关联公司或其他可信赖的企业或个人,以便其代表我们处理个人信息。我们要求上述各方同意按照我们的规定、本隐私权政策以及其他任何适用的保密和安全措施来处理这些个人信息。 +

+

+ • 如果我们发生重组、合并或出售,则我们在将我们收集的一切个人信息进行转让之前,继续按照现行的隐私政策约束来保证其秘密性并会通知所有受到影响的用户。 +

+

+ 我们可能会基于经营或保护用户的需要,如为了展示我们产品或服务的整体使用趋势,同公众以及合作伙伴合理地分享汇总的非个人信息。 +

+

+ 5、信息安全 +

+

+ 我们努力为小米的用户提供保护,以免我们保存的信息在未经授权的情况下被访问、篡改、披露或破坏。为此,我们特别采取了以下措施: +

+

+ 我们使用 SSL 对许多服务进行加密。 +

+

+ 我们会审查信息收集、存储和处理方面的做法(包括物理性安全措施),以避免各种系统遭到未经授权的访问。 +

+

+ 我们只允许那些为了帮我们处理个人信息而需要知晓这些信息的小米员工、授权代为处理服务公司的人员访问个人信息,而且他们需要履行严格的合同保密义务,如果其未能履行这些义务,就可能会被追究法律责任或被终止其与小米的关系。 +

+

+ 对我们来说,您的信息的安全非常重要。因此,我们将不断努力保障您的个人信息安全,并实施存储和传输全程安全加密等保障手段,以免您的信息在未经授权的情况下被访问、使用或披露。同时某些加密数据的具体内容,除了用户自己,其他人都无权访问。 +

+

+ 6、隐私政策的适用范围 +

+

+ 我们的隐私政策不适用于第三方产品和/或服务。小米路由器系列产品和服务中可能含有第三方产品和服务,如:金山快盘。当您使用第三方产品或接收第三方服务时,他们可能获取您的信息,因此,我们在此提醒您注意阅读第三方的隐私政策。(在本协议最后部分有金山快盘产品与服务的相关说明) +

+

+ 同时,本隐私政策不适用于在您点击链接后的外部网站收集数据的行为。 +

+

+ 7、对儿童个人信息的收集和使用 +

+

+ 我们建议13周岁以下的儿童在其法定监护人的许可和指导下使用小米产品或服务。 +

+

+ 小米不会在明知对方为儿童的情况下收集其个人信息,也不会向任何第三方透露其个人信息,监护人有权拒绝小米及其关联公司进一步收集被监护人的个人信息,或要求小米及其关联公司删除该被监护人个人信息。如果我们发现我们收集了年龄不满13周岁的儿童的个人信息,我们将采取措施尽快地删除此等信息。 +

+

+ 8、本隐私政策的修订 +

+

+ 本隐私政策容许调整,未经您明示同意,我们不会削弱您按照本隐私权政策所应享有的权利,除非通过您提供的电子邮件地址向您发送通知或发布网站公告。 +

+

+ 9、特定产品服务的惯例 +

+

+ 以下备注了您可能使用的某些小米路由器相关产品和服务的特定隐私权惯例。 +

+

+ 金山快盘云同步服务 +

+

+ 您在使用小米路由器系列产品过程中会使用到由北京金山软件有限公司的产品“金山快盘”为您提供的“路由器云备份”功能。关于金山快盘的服务条款请查阅:http://www.kuaipan.cn/agreement/ +

+

+ 关于金山快盘: +

+

+ 金山快盘秉承极致、专注、快速的理念,凭借金山多年技术积累,将为金山其他业务提供支撑,同时致力于为用户提供稳定、安全、便捷的个人云存储服务。关于金山快盘的相关信息以及请查看:http://www.kuaipan.cn +

diff --git a/1_1.mi_Lua/luci/view/web/inc/footer.htm b/1_1.mi_Lua/luci/view/web/inc/footer.htm new file mode 100644 index 0000000..4e8843a --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/footer.htm @@ -0,0 +1,18 @@ +<% +local XQSysUtil = require "xiaoqiang.util.XQSysUtil" +local xqlanwanutil = require "xiaoqiang.util.XQLanWanUtil" +local macdefault = string.upper(xqlanwanutil.getDefaultMacAddress()) +local romVersion = XQSysUtil.getRomVersion() +local _romChannel = XQSysUtil.getChannel() +local romChannel = "开发版" +if _romChannel == "current" then + romChannel = "内测版" +end +if _romChannel == "release" then + romChannel = "稳定版" +end +%> +
+

<%:系统版本%>: MiWiFi Rom <%=romVersion%> <%=romChannel%>    <%:MAC地址%>: <%=macdefault%>

+

© 2014 <%:小米路由器%>|官方网站|官方微博|官方微信|用户社区|<%:服务热线%> 400-100-5678

+

\ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/inc/footermini.htm b/1_1.mi_Lua/luci/view/web/inc/footermini.htm new file mode 100644 index 0000000..cdcdf8d --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/footermini.htm @@ -0,0 +1,3 @@ +
+

© 2014 <%:小米路由器%>|<%:服务热线%> 400-100-5678

+

\ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/inc/g.js.base.htm b/1_1.mi_Lua/luci/view/web/inc/g.js.base.htm new file mode 100644 index 0000000..ee0f730 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/g.js.base.htm @@ -0,0 +1,231 @@ +<% + local XQVersion = require("xiaoqiang.XQVersion") + local XQSysUtil = require ("xiaoqiang.util.XQSysUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local ver = XQVersion.webVersion + local monitor = XQLanWanUtil.getWanMonitorStat() + local pcClient = XQVersion.pcClientServer + local macClient = XQVersion.macClientServer + local androidClient = XQVersion.androidClientServer + if monitor.WANLINKSTAT ~= "UP" then + pcClient = XQVersion.pcClientRouter + macClient = XQVersion.macClientRouter + androidClient = XQVersion.androidClientRouter + end + + local remote_addr = luci.http.getenv("REMOTE_ADDR") + local mac = luci.sys.net.ip4mac(remote_addr) + + -- URL ENV SWTICH + local XQConfigs = require "xiaoqiang.common.XQConfigs" + local pspBaseUrl + local xmServerUrl + if XQConfigs.SERVER_CONFIG == 0 then + pspBaseUrl = XQConfigs.PASSPORT_CONFIG_ONLINE_URL + xmServerUrl = XQConfigs.XQ_SERVER_ONLINE_API_URL + elseif XQConfigs.SERVER_CONFIG == 1 then + pspBaseUrl = XQConfigs.PASSPORT_CONFIG_PREVIEW_URL + xmServerUrl = XQConfigs.XQ_SERVER_STAGING_API_URL + end +%> + + + + + + + + + + + + diff --git a/1_1.mi_Lua/luci/view/web/inc/g.js.htm b/1_1.mi_Lua/luci/view/web/inc/g.js.htm new file mode 100644 index 0000000..d5a5fac --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/g.js.htm @@ -0,0 +1,161 @@ +<% + local XQVersion = require("xiaoqiang.XQVersion") + local XQSysUtil = require ("xiaoqiang.util.XQSysUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local router_name = XQSysUtil.getRouterName() or "小米路由器" + local isBinded = (XQSysUtil.getPassportBindInfo() and 'true') or 'false' +%> + + diff --git a/1_1.mi_Lua/luci/view/web/inc/head.htm b/1_1.mi_Lua/luci/view/web/inc/head.htm new file mode 100644 index 0000000..4408891 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/head.htm @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/inc/header.htm b/1_1.mi_Lua/luci/view/web/inc/header.htm new file mode 100644 index 0000000..db7536d --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/header.htm @@ -0,0 +1,20 @@ +<% + local XQSysUtil = require "xiaoqiang.util.XQSysUtil" + local homeUrl = '/' + if XQSysUtil.getInitInfo() then + homeUrl = luci.dispatcher.build_url("web", "home") + end +%> + +
+
+

小米路由器

+
+ +
+
+
diff --git a/1_1.mi_Lua/luci/view/web/inc/nav.htm b/1_1.mi_Lua/luci/view/web/inc/nav.htm new file mode 100644 index 0000000..18f9039 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/nav.htm @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/inc/reboot.js.htm b/1_1.mi_Lua/luci/view/web/inc/reboot.js.htm new file mode 100644 index 0000000..be43c54 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/reboot.js.htm @@ -0,0 +1,119 @@ +<% + local lanIp = require("xiaoqiang.XQVersion").webDefaultHost +%> + diff --git a/1_1.mi_Lua/luci/view/web/inc/upgrade.js.htm b/1_1.mi_Lua/luci/view/web/inc/upgrade.js.htm new file mode 100644 index 0000000..7b1bda2 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/inc/upgrade.js.htm @@ -0,0 +1,159 @@ +//check offline +global_event.checkOffline = false; +$(global_event).on('upgrade:isoffline', function(evt, data){ + global_event.checkOffline = true; + var imgUrl = 'http://'+ location.host +'/xiaoqiang/web/img/logo.png', + timer = null, + loadImg = function(){ + console.log(global_event.offline); + var img = new Image(); + img.onload = function(){ + if (global_event.offline) { + return; + } + window.clearTimeout(timer); + timer = window.setTimeout(function(){ + loadImg(); + }, 1500); + }; + img.onerror = function(){ + global_event.offline = true; + }; + img.src = imgUrl+'?' + (+new Date()); + }; + global_event.offline = false; + loadImg(); +}); +//flash ROM V2 +$(global_event).on('upgrade:downAndInstall', function(evt, data){ + $.getJSON('<%=luci.dispatcher.build_url("api", "xqsystem", "upgrade_rom")%>', {}, function(rsp){ + if (rsp.code == 0) { + //check download percent + $(global_event).trigger('upgrade:downloadPercent'); + //check shell status + $(global_event).trigger('upgread:flashCheck'); + }else{ + window.top.art.dialog({ + width: 400, + title: '升级失败', + content: rsp.msg + }).lock().time(3 * 1000); + setTimeout('self.location.reload(1)', 3 * 1000); + } + }); +}); +//check download file percent +$(global_event).on('upgrade:downloadPercent', function(evt, data){ + $('#dldProgress').show(); + $('#btnUpgread').hide(); +}); + +//check flash status +$(global_event).on('upgread:flashCheck', function(evt, data){ + var timer = window.setInterval(function(){ + $.ajax({ + url: '<%=luci.dispatcher.build_url("api", "xqsystem","upgrade_status")%>', + type: 'GET', + dataType: 'json', + cache: false + }) + .done(function(rsp){ + if (rsp.code == 0) { + console.log('ajax done',global_event.offline); + var status = rsp.status; + // 无需升级 + if (status == 0) { + window.clearInterval(timer); + $(global_event).trigger('upgrade:flashdone'); + } + if (status == 3) { + $("#btnCancel").show(); + } else { + $("#btnCancel").hide(); + } + if (/(3|5|11|12)/.test(status) && rsp.percent) { + $("#persent").html(rsp.percent); + $("#persentWidth").css("width", rsp.percent+"%"); + } + //flash fail + if(/(6|7|8|9|10)/.test(status)){ + window.clearInterval(timer); + $(global_event).trigger('upgrade:flashfail', {status: status}); + } + // flash rom ing + if (/(5|12)/.test(status)) { + if (!global_event.checkOffline) { + $(global_event).trigger('upgrade:flashstart'); + $(global_event).trigger('upgrade:isoffline'); + } + } + // flash success + if (status == 11) { + window.clearInterval(timer); + $(global_event).trigger('upgrade:flashdone'); + } + } + }) + .fail(function() { + // 和服务器断开连接 + console.log('ajax fail', global_event.offline); + if ( global_event.checkOffline ) { + if (global_event.offline) { + window.clearInterval(timer); + $(global_event).trigger('upgrade:flashdone'); + } + } else { + $(global_event).trigger('upgrade:isoffline'); + } + }); + }, 1500); +}); +//flash start +$(global_event).on('upgrade:flashstart', function(evt, data){ + if (global_event.wait) { + return; + } + global_event.wait = window.top.art.dialog({ + width:400, + cancel: false, + title:'固件安装中', + content :'正在安装固件, 请不要切断路由器电源' + }).lock(); +}); +//flash fail +$(global_event).on('upgrade:flashfail', function(evt, data){ + if (global_event.wait) { + global_event.wait.close(); + } + var msg = { + 6: '下载失败', + 7: '没有磁盘空间', + 8: '下载失败', + 9: '升级包校验失败', + 10: '刷写失败' + }; + var status = data.status; + window.top.art.dialog({ + width: 400, + title:'固件安装中', + content: msg[status] + ',固件安装失败,请刷新重试' + }).lock().time(2 * 1000); + window.setTimeout('self.location.reload(1)', 2 * 1000); +}); +//flash done +$(global_event).on('upgrade:flashdone', function(evt, data){ + if (global_event.wait) { + global_event.wait.close(); + } + $(global_event).trigger('reboot:wait', { + action : '升级路由器固件', + refresh : true + }); +}); +//绑定事件 +$(global_event).on ('upgrade:initEvent', function(evt, data){ + $('#btnUpgread').on('click', function(e){ + e.preventDefault(); + $(global_event).trigger('upgrade:downAndInstall'); + }); +}); diff --git a/1_1.mi_Lua/luci/view/web/index.htm b/1_1.mi_Lua/luci/view/web/index.htm new file mode 100644 index 0000000..c623964 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/index.htm @@ -0,0 +1,412 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local XQSysUtil = require("xiaoqiang.util.XQSysUtil") + local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") + local hardwareVersion = XQSysUtil.getHardware() + local romVersion = XQSysUtil.getRomVersion() + local sysInfo = XQSysUtil.getSysInfo() + local router_name = XQSysUtil.getRouterName() or "我" + local sysCore = (sysInfo.core == 2 and '双核') or '单核' + local sysCpu = sysCore .." ".. sysInfo.hz + local sysDisk = XQSysUtil.getDiskSpace() + local remote_addr = luci.http.getenv("REMOTE_ADDR") + --local mac = string.upper(luci.sys.net.ip4mac(remote_addr)) + local mac = XQLanWanUtil.getLanWanInfo("wan").mac +%> +<%include ("web/inc/head")%> +路由器状态 - 小米路由器 + + + + +<%include ("web/inc/g.js.base")%> + + + + +<%include ("web/inc/g.js")%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/init/agreement.htm b/1_1.mi_Lua/luci/view/web/init/agreement.htm new file mode 100644 index 0000000..6009bfb --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/init/agreement.htm @@ -0,0 +1,27 @@ +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local sys = require("xiaoqiang.util.XQSysUtil") +%> +<%include ("web/inc/head")%> +初始化引导 - 小米路由器 + + + +
+ <%include ("web/inc/header")%> +
+
+
+

小米路由器 用户使用协议

+
+
+
+ <%include('web/inc/agreement')%> +
+
+
+
+ <%include ("web/inc/footer")%> +
+ + diff --git a/1_1.mi_Lua/luci/view/web/init/guide.htm b/1_1.mi_Lua/luci/view/web/init/guide.htm new file mode 100644 index 0000000..0a97ca6 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/init/guide.htm @@ -0,0 +1,442 @@ +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local fun = require("xiaoqiang.common.XQFunction") +local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") +local sys = require("xiaoqiang.util.XQSysUtil") +if sys.getInitInfo() then + luci.http.redirect(luci.dispatcher.build_url("web", "home")) +end +local wifiInfo = wifiUtil.getAllWifiInfo() +local ssid = "" +local wanType = 2 +local AutoWanType = XQLanWanUtil.getAutoWanType() +if AutoWanType then + wanType = AutoWanType +end +if wifiInfo[1] then + ssid = wifiInfo[1]['ssid'] +end +local remote_addr = luci.http.getenv("REMOTE_ADDR") +local mac = luci.sys.net.ip4mac(remote_addr) +local lanType = wifiUtil.getDeviceWifiIndex(mac) +%> +<%include ("web/inc/head")%> +初始化引导 - 小米路由器 + + + +
+ <%include ("web/inc/header")%> +
+
+
+ + + + + + +
+
+ + +
+ + + + + + + + + +
+
+
+
+ <%include ("web/inc/footermini")%> +
+<%include ("web/inc/g.js.base")%> + + + diff --git a/1_1.mi_Lua/luci/view/web/init/hello.htm b/1_1.mi_Lua/luci/view/web/init/hello.htm new file mode 100644 index 0000000..f2ede4a --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/init/hello.htm @@ -0,0 +1,80 @@ +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local sys = require("xiaoqiang.util.XQSysUtil") +if sys.getInitInfo() then + luci.http.redirect(luci.dispatcher.build_url("web", "home")) +else + sys.setSysPasswordDefault() +end +%> +<%include ("web/inc/head")%> +初始化引导 - 小米路由器 + + + + +
+ <%include ("web/inc/header")%> + + <%include ("web/inc/footermini")%> +
+ +<%include ("web/inc/g.js.base")%> + + + diff --git a/1_1.mi_Lua/luci/view/web/init/webinitrdr.htm b/1_1.mi_Lua/luci/view/web/init/webinitrdr.htm new file mode 100644 index 0000000..1ca5b06 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/init/webinitrdr.htm @@ -0,0 +1,204 @@ + + + + + + + + + +小米路由器 + + + + +
+
+ +
+
+
+

你连接的小米路由器还未初始化

+

请稍候,会自动为你跳转到引导页面...

+

loading

+

如果未能跳转,请直接访问miwifi.com

+

+
+
+

Copyright © 2013 xiaomi.com

+ 小米,为发烧友而生! +
+
+ + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/manager.htm b/1_1.mi_Lua/luci/view/web/manager.htm new file mode 100644 index 0000000..d9f6df8 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/manager.htm @@ -0,0 +1,425 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local remote_addr = luci.http.getenv("REMOTE_ADDR") + local mac = luci.sys.net.ip4mac(remote_addr) +%> +<%include ("web/inc/head")%> +终端管理 - 小米路由器 + + + + + + +<%include ("web/inc/g.js.base")%> +<%include ("web/inc/g.js")%> + + + diff --git a/1_1.mi_Lua/luci/view/web/netdetection.htm b/1_1.mi_Lua/luci/view/web/netdetection.htm new file mode 100644 index 0000000..c1c17d0 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/netdetection.htm @@ -0,0 +1,251 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +网络检测 - 小米路由器 + + + +
+
+
+

诊断完成: 网络很差

+

+
+
+
+
+
+ + 网络连接状态 + 正在检测中... +
+ +
+
+
+ + 外网连接状态 + 正在检测中... +
+ +
+
+
+ + 路由硬件状态 + 正在检测中... +
+ +
+
+
+ + 连接速度状态 + 正在检测中... +
+ +
+ +
+ + +
+<%include ("web/inc/g.js.base")%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/netset.htm b/1_1.mi_Lua/luci/view/web/netset.htm new file mode 100644 index 0000000..303ed1c --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/netset.htm @@ -0,0 +1,210 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +路由设置 - 小米路由器 + + + + +<%include ("web/inc/g.js.base")%> +<%include ("web/inc/g.js")%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/plugin.htm b/1_1.mi_Lua/luci/view/web/plugin.htm new file mode 100644 index 0000000..bbe62ad --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/plugin.htm @@ -0,0 +1,661 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local cryptoUtil = require("xiaoqiang.util.XQCryptoUtil") + local XQSysUtil = require ("xiaoqiang.util.XQSysUtil") + local http = require ("luci.http") + local secretKey = "Ep9]B28z3!3D66*3CF_18663" + local routerName = XQSysUtil.getRouterName() or "miwifi" + local XQConfigs = require("xiaoqiang.common.XQConfigs") + local cmd = XQConfigs.THRIFT_TO_MQTT_GET_DEVICEID + local LuciUtil = require("luci.util") + local deviceId = LuciUtil.exec(cmd) + local from = "xiaomi_router" + local sign = cryptoUtil.md5Str(deviceId .. from .. routerName .. secretKey) + local xunleiurl = string.format("http://dynamic.i.xunlei.com/device_binding/entrance.php?deviceId=%s&from=%s&name=%s&sign=%s", http.urlencode(deviceId), http.urlencode(from), http.urlencode(routerName), http.urlencode(sign)) +%> +<%include ("web/inc/head")%> +应用管理 - 小米路由器 + + + + +
+ + + +<%include ("web/inc/g.js.base")%> + +<%include ("web/inc/g.js")%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/plugins/guest.htm b/1_1.mi_Lua/luci/view/web/plugins/guest.htm new file mode 100644 index 0000000..74802d7 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/plugins/guest.htm @@ -0,0 +1,178 @@ +<% +--[[ + Info 迅雷插件 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+ +
+
+

开启共享模式

+

新连接的设备允许访问小米路由盘

+
+
+ +
+
+
+
+

数据修改保护

+

开启保护后,小米路由盘上的数据不可修改

+
+
+ +
+
+ +
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/plugins/kuaipan.htm b/1_1.mi_Lua/luci/view/web/plugins/kuaipan.htm new file mode 100644 index 0000000..5bde2b6 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/plugins/kuaipan.htm @@ -0,0 +1,521 @@ +<% +--[[ + Info 快盘插件 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include('web/inc/head')%> +路由器云备份 + + + + + +
+ + + +
+ + +
+ +
+ + + + +
+ +
+ + +
+ + + +
+ +<%include('web/inc/g.js.base')%> + + + diff --git a/1_1.mi_Lua/luci/view/web/plugins/xunlei.htm b/1_1.mi_Lua/luci/view/web/plugins/xunlei.htm new file mode 100644 index 0000000..b299f4f --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/plugins/xunlei.htm @@ -0,0 +1,22 @@ +<% +--[[ + Info 迅雷插件 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include('web/inc/head')%> +小米路由器 + + + + + + +<%include('web/inc/g.js.base')%> + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/safeurl.htm b/1_1.mi_Lua/luci/view/web/safeurl.htm new file mode 100644 index 0000000..0398cc5 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/safeurl.htm @@ -0,0 +1,16 @@ + + + + + +

+ go on visite +

+ +
diff --git a/1_1.mi_Lua/luci/view/web/setting.htm b/1_1.mi_Lua/luci/view/web/setting.htm new file mode 100644 index 0000000..0476f36 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting.htm @@ -0,0 +1,290 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +路由设置 - 小米路由器 + + + + +<%include ("web/inc/g.js.base")%> +<%include ("web/inc/g.js")%> +<%include ("web/inc/reboot.js")%> + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/ddns.htm b/1_1.mi_Lua/luci/view/web/setting/ddns.htm new file mode 100644 index 0000000..d58e523 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/ddns.htm @@ -0,0 +1,409 @@ +<% +--[[ + Info DDNS +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

DDNS

+ +
+
+
+ + +
+
+
+<%include('web/inc/g.js.base')%> + + diff --git a/1_1.mi_Lua/luci/view/web/setting/developer.htm b/1_1.mi_Lua/luci/view/web/setting/developer.htm new file mode 100644 index 0000000..e7df355 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/developer.htm @@ -0,0 +1,165 @@ +<% +--[[ + Info Developer +]]-- +local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

开发者选项

+
+
+
+
+ + + +
+
" class="form form-horizontal" method="post" name="developer" id="developer" hidden='hidden'> +
+ + + +
+
+
+
+ +
+
+
+

通过SSH工具,输入ssh plugin@miwifi.com -p 2222 登录路由器,默认登录密码admin(登录后可通过passwd修改密码)

+
+
+
+
+ +<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/diskformat.htm b/1_1.mi_Lua/luci/view/web/setting/diskformat.htm new file mode 100644 index 0000000..eca9118 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/diskformat.htm @@ -0,0 +1,70 @@ +<% +--[[ + Info 格式化小强盘 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

格式化硬盘

+
+
+
+
+

格式化硬盘

+

执行该任务硬盘里所有的数据将被清空,格式化前确保数据已备份。

+
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/dmz.htm b/1_1.mi_Lua/luci/view/web/setting/dmz.htm new file mode 100644 index 0000000..359f8ae --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/dmz.htm @@ -0,0 +1,236 @@ +<% +--[[ + Info DMZ +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") + +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

DMZ

+ +
+
+ +
+ 开启DMZ功能可以将内网某一个设备的IP映射到外网,方便从外网访问到该设备。 +
+ + +
+
+<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/lamp.htm b/1_1.mi_Lua/luci/view/web/setting/lamp.htm new file mode 100644 index 0000000..9f85987 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/lamp.htm @@ -0,0 +1,156 @@ +<% +--[[ + Info 路由器重启恢复 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

LAMP

+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/log.htm b/1_1.mi_Lua/luci/view/web/setting/log.htm new file mode 100644 index 0000000..a6bf85f --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/log.htm @@ -0,0 +1,54 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

上传日志

+
+
+
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/nat.htm b/1_1.mi_Lua/luci/view/web/setting/nat.htm new file mode 100644 index 0000000..d1c5612 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/nat.htm @@ -0,0 +1,592 @@ +<% +--[[ + Info nat +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

端口转发

+ +
+
+ +
+

端口转发

+
+
+ + + +
+ +
+ + + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ +
+
+
+ +
+

规则列表

+
+ + + + + + + + + + + + + + + +
名称协议外部端口内部IP地址内部端口操作
+
+
+ +
+

范围转发

+
+ +
+ + + +
+ +
+ + + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ +
+
+
+ +
+

规则列表

+
+ + + + + + + + + + + + + +
名称协议起始端口结束端口目标IP操作
+
+
+
+
+ +
+
+
+
+ + + + + +<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/net_ipmacband.htm b/1_1.mi_Lua/luci/view/web/setting/net_ipmacband.htm new file mode 100644 index 0000000..80d5ddd --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/net_ipmacband.htm @@ -0,0 +1,317 @@ +<% +--[[ + Info upnp +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

DHCP静态IP分配

+
+
+
+
+

当前连接设备列表:

+ + + + + + + + + + + + +
设备名称IP地址MAC地址操作
+
+ +
+

绑定列表:可以从设备列表添加或者手工添加

+ + + + + + + + + + + +
IP地址MAC地址操作 全部解绑
+
+ +
+ +
+ +
+
+
+ + + +<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/net_lan.htm b/1_1.mi_Lua/luci/view/web/setting/net_lan.htm new file mode 100644 index 0000000..22aa40c --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/net_lan.htm @@ -0,0 +1,310 @@ +<% +--[[ + Info lan 口设置 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

内网设置

+
+
+
+
+ +
+ + + +
+
+ +
+
+
+
+
+
+
+ + + +
+
"> + + + +
+ + + 192.168.1. - + + +
+
+ + + + + + +
+
+ +
+
+
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/net_setup_mac.htm b/1_1.mi_Lua/luci/view/web/setting/net_setup_mac.htm new file mode 100644 index 0000000..8d0028c --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/net_setup_mac.htm @@ -0,0 +1,134 @@ +<% +--[[ + Info MAC 地址绑定 +]]-- + +local remote_addr = luci.http.getenv("REMOTE_ADDR") +local mac = string.upper(luci.sys.net.ip4mac(remote_addr)) +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

MAC地址克隆

+
+
+
+

你路由器当前使用的MAC地址是:获取中...
如需克隆MAC地址,请做如下操作:

+
+
+ + + + + +
+ +
+ +
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/net_wan.htm b/1_1.mi_Lua/luci/view/web/setting/net_wan.htm new file mode 100644 index 0000000..c917794 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/net_wan.htm @@ -0,0 +1,576 @@ +<% +--[[ + Info 网络连接设置 +]]-- +local ver = require("xiaoqiang.XQVersion").webVersion +local XQLanWanUtil = require("xiaoqiang.util.XQLanWanUtil") +local is_conn = XQLanWanUtil.getWanMonitorStat().WANLINKSTAT == "UP" +local autotype = luci.http.formvalue("mini") +local wanType = 2 +local getWanType = XQLanWanUtil.getAutoWanType() +if getWanType then + wanType = getWanType +end +local wan = XQLanWanUtil.getLanWanInfo("wan") +%> +<%include('web/inc/head')%> +小米路由器 + +<%if autotype ~= nil then%> + +<%end%> + + +
+
+

外网设置

+
+
+
+ +
+
+
+

+
+
+ + + + +
+
+ +
+ + + + + +
+ +
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/nginx.htm b/1_1.mi_Lua/luci/view/web/setting/nginx.htm new file mode 100644 index 0000000..09893ad --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/nginx.htm @@ -0,0 +1,104 @@ +<% +--[[ + Info 路由器重启恢复 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

关闭NGINX

+
+
+ +
+
+

关闭NGINX

+

关闭NGINX,可以禁止路由器预加载功能,专供专业人士使用。

+
+
+
NGINX状态检测中...
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/noflushd.htm b/1_1.mi_Lua/luci/view/web/setting/noflushd.htm new file mode 100644 index 0000000..15f2c64 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/noflushd.htm @@ -0,0 +1,75 @@ +<% +--[[ + Info Noflushd +]]-- +local ver = require("xiaoqiang.XQVersion").webVersion +%> + +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

硬盘自动休眠

+ +
+
+
+

开启此功能后小米路由器将在硬盘非工作状态下使其进入休眠状态,以延长硬盘使用寿命。

+

(建议正在使用SSH连接路由器的用户不要开启此功能)

+
+
+
+ +<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/passport.htm b/1_1.mi_Lua/luci/view/web/setting/passport.htm new file mode 100644 index 0000000..953639c --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/passport.htm @@ -0,0 +1,143 @@ +<% +--[[ + Info 路由器权限 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

修改管理密码

+
+
+
+
" class="form form-horizontal" method="post" name="passport" id="passport"> + + +
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/predownload.htm b/1_1.mi_Lua/luci/view/web/setting/predownload.htm new file mode 100644 index 0000000..6e25bf7 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/predownload.htm @@ -0,0 +1,74 @@ +<% +--[[ + Info Predownload +]]-- +local ver = require("xiaoqiang.XQVersion").webVersion +%> + +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

升级包预下载

+ +
+
+
+

开启此功能后后台会自动检测是否有可用升级包并自动下载。

+
+
+
+ +<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/qos.htm b/1_1.mi_Lua/luci/view/web/setting/qos.htm new file mode 100644 index 0000000..acc63d1 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/qos.htm @@ -0,0 +1,233 @@ +<% +--[[ + Info 应用限速 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

应用限速状态

+ +
+
+
+ +
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/qos_pro.htm b/1_1.mi_Lua/luci/view/web/setting/qos_pro.htm new file mode 100644 index 0000000..9b89430 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/qos_pro.htm @@ -0,0 +1,606 @@ +<% +--[[ + Info Qos +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

QoS状态

+ +
+
+ + +
+
+ + +<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/reboot.htm b/1_1.mi_Lua/luci/view/web/setting/reboot.htm new file mode 100644 index 0000000..66b8c40 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/reboot.htm @@ -0,0 +1,50 @@ +<% +--[[ + Info 路由器重启恢复 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

路由器关机&重启

+
+
+
+
+

重启路由器

+

路由器重启需要等待几十秒或更多时间,重启过程中,将会断开网络连接,稍后将自动重新连接网络。

+
+
+ +
+
+
+
+

关闭路由器

+

关闭路由器将断开其他设备的数据访问和网络连接,之后便可以安全的断开电源。(再次启动需要手工连接电源)

+
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/reset.htm b/1_1.mi_Lua/luci/view/web/setting/reset.htm new file mode 100644 index 0000000..13f540a --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/reset.htm @@ -0,0 +1,40 @@ +<% +--[[ + Info 路由器恢复出厂设置 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

恢复出厂设置

+
+
+
+
+

恢复出厂设置

+

清除路由器上所有的设置项目,包括绑定的小米账号,恢复到出厂状态。

+

+
+
+ +
+
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/sys_psp.htm b/1_1.mi_Lua/luci/view/web/setting/sys_psp.htm new file mode 100644 index 0000000..27aafd6 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/sys_psp.htm @@ -0,0 +1,196 @@ +<% +--[[ + Info 绑定小米账号 +]]-- + +local XQSysUtil = require "xiaoqiang.util.XQSysUtil" +local ver = require("xiaoqiang.XQVersion").webVersion +local isBinded = (XQSysUtil.getPassportBindInfo() and 'true') or 'false'; +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

小米账号管理

+
+
+
+ + +
+
+
+ + + +<%include('web/inc/g.js.base')%> + + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/sys_status.htm b/1_1.mi_Lua/luci/view/web/setting/sys_status.htm new file mode 100644 index 0000000..f37a632 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/sys_status.htm @@ -0,0 +1,113 @@ +<% +--[[ + Info 系统状态 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local XQSysUtil = require("xiaoqiang.util.XQSysUtil") +local romVersion = XQSysUtil.getRomVersion() +local hardwareVersion = XQSysUtil.getHardwareGPIO() +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

系统状态

+
+
+
+
+

版本信息

+
+
    +
  • 当前软件版本:<%=romVersion%>
  • +
  • 当前硬件版本:<%=hardwareVersion%>
  • +
+
+
+
+

LAN口状态

+
+
    +
  • MAC地址:
  • +
  • IP地址:
  • +
  • 子网掩码:
  • +
+
+
+
+

无线状态

+
+
    +
  • WiFi 2.4G:
  • +
  • SSID:
  • +
  • 信道:
  • +
  • 模式:
  • + +
+
    +
  • WiFi 5G:
  • +
  • SSID:
  • +
  • 信道:
  • +
  • 模式:
  • + +
+
+
+
+

WAN口状态

+
+
    +
  • MAC地址:
  • +
  • IP地址:
  • +
  • 连接类型:
  • +
  • 子网掩码:
  • +
  • 网关:
  • +
  • DNS服务器:
  • +
  • 备选DNS:
  • +
+
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/upgrade.htm b/1_1.mi_Lua/luci/view/web/setting/upgrade.htm new file mode 100644 index 0000000..b60e613 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/upgrade.htm @@ -0,0 +1,76 @@ + <% +--[[ + Info 路由器固件升级 +]]-- + +local XQSysUtil = require "xiaoqiang.util.XQSysUtil" +local ver = require("xiaoqiang.XQVersion").webVersion +local XQSysUtil = require("xiaoqiang.util.XQSysUtil") +local romVersion = XQSysUtil.getRomVersion() +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

升级检测

+
+
+
+

当前版本<%=romVersion%>正在检测更新,请稍候...

+ + + + +
+
+
+ +<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/upgrade_manual.htm b/1_1.mi_Lua/luci/view/web/setting/upgrade_manual.htm new file mode 100644 index 0000000..33b7b03 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/upgrade_manual.htm @@ -0,0 +1,139 @@ +<% +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

路由器固件手动升级

+
+
+
+
+

如因故无法进行系统OTA升级,或者您需要将路由器软件降级到前一版本时,您可以使用手工方式上传并安装固件。

+

注意:升级过程中请勿断开路由器电源,否则将导致路由器损坏而无法使用;升级完成后,路由器将会自动重新启动。

+
+
+
+ + + + + +
+
+ +
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/upload_config.htm b/1_1.mi_Lua/luci/view/web/setting/upload_config.htm new file mode 100644 index 0000000..3927482 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/upload_config.htm @@ -0,0 +1,42 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local XQSysUtil = require "xiaoqiang.util.XQSysUtil" + local config = XQSysUtil.getConfigInfo() +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

上传配置信息

+
+
+
+
+
<%=config%>
+
+
+ +
+ +
+
+
+<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/upnp.htm b/1_1.mi_Lua/luci/view/web/setting/upnp.htm new file mode 100644 index 0000000..a6ba31b --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/upnp.htm @@ -0,0 +1,96 @@ +<% +--[[ + Info upnp +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

UPnP状态

+ +
+
+ +
+

UPnP设备列表:

+ + + + + + + + + + + + + +
协议应用名称客户端IP内部端口外部端口
+
+
+
+<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/vpn.htm b/1_1.mi_Lua/luci/view/web/setting/vpn.htm new file mode 100644 index 0000000..ce4d226 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/vpn.htm @@ -0,0 +1,228 @@ +<% +--[[ + Info PPTP/L2TP +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

PPTP/L2TP

+
+
+
+
" class="form form-horizontal" method="post" name="vpn" id="vpn"> +
+ + + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+
+ +
+
+ +
+

当前状态:查询中...

+

+
+
+
+
+<%include('web/inc/g.js.base')%> + diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_filter.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_filter.htm new file mode 100644 index 0000000..6d6d640 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_filter.htm @@ -0,0 +1,395 @@ +<% +--[[ + Info upnp +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local request_uri = luci.http.getenv("REQUEST_URI") +local remote_addr = luci.http.getenv("REMOTE_ADDR") +local mac = luci.sys.net.ip4mac(remote_addr) +local lanType = wifiUtil.getDeviceWifiIndex(mac) +%> +<%include('web/inc/head')%> +小米路由器 + + + + +
+
+

无线访问控制

+ +
+
+ +
+
+

控制模式:

+

+ + +

+
+
+

设备列表:

+ + + + + + + + + + + +
当前连接设备设备信息连接时长连接速度操作
+
+
+

无线访问控制名单:

+ + + + + + + + +
设备信息操作
+
+
+ +
+
+
+
+ + +<%include('web/inc/g.js.base')%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_set.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_set.htm new file mode 100644 index 0000000..64d4d7e --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_set.htm @@ -0,0 +1,544 @@ +<% +--[[ + Info wifi 基本设置 +]]-- +function escape(str) + str = string.gsub( str, '<', '<') + str = string.gsub( str, '>', '>') + str = string.gsub( str, '"', '"') + str = string.gsub( str, "'", ''') + str = string.gsub( str, '&', '&') + return str +end +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local wifi_status = wifiUtil.getWifiStatus(1).up +local wifi5_status = wifiUtil.getWifiStatus(2).up + +local remote_addr = luci.http.getenv("REMOTE_ADDR") +local mac = luci.sys.net.ip4mac(remote_addr) +local lanType = wifiUtil.getDeviceWifiIndex(mac) +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

WiFi设置

+
+
+
+
+
" autocomplete="off"> +
+
+
+
+ +
+
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_set_mini.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_set_mini.htm new file mode 100644 index 0000000..bd347a0 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_set_mini.htm @@ -0,0 +1,324 @@ +<% +--[[ + Info wifi 基本设置 +]]-- +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local wifiIndex = tonumber(luci.http.formvalue("wifi_device")) +if not wifiIndex then + wifiIndex = 1 +end +local wifi_status = wifiUtil.getWifiStatus(wifiIndex).up +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

开启关闭WIFI,设置WIFI名称,密码等

+
+
+
+
+ + + +
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_set_pro.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_set_pro.htm new file mode 100644 index 0000000..efaf9aa --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_set_pro.htm @@ -0,0 +1,441 @@ +<% +--[[ + Info wifi 高级设置 +]]-- +local LuciJson = require("luci.json") +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local pddk24 = LuciJson.encode(wifiUtil.getDefaultWifiChannels(1)); +local pddk50 = LuciJson.encode(wifiUtil.getDefaultWifiChannels(2)); +local guestwifi1 = LuciJson.encode(wifiUtil.getGuestWifi(1)) +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

无线信道与强度

+
+
+
+
" method="post"> + +
+ + + + + +
+
+ + + + +
+ +
+ + + + + +
+
+ +
+
+
+ +
+ +
+
" method="post"> + +
+ + + + + +
+
+ + + + + +
+ +
+ + + + + +
+ +
+ +
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_setup_channel.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_setup_channel.htm new file mode 100644 index 0000000..e061580 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_setup_channel.htm @@ -0,0 +1,187 @@ +<% +--[[ + Info wifi 频道强度设置 +]]-- + +local ver = require("xiaoqiang.XQVersion").webVersion +local request_uri = luci.http.getenv("REQUEST_URI") +%> +<%include('web/inc/head')%> +小米路由器 + + +
+
+

WiFi信道强度设置

+
+
+
+
+
+ + + + +
+ + + + + +
+
+ + + + + +
+
+ + + + + +
+
+ + + + + +
+
+ +
+
+
+
+
+<%include('web/inc/g.js.base')%> + + + diff --git a/1_1.mi_Lua/luci/view/web/setting/wifi_txpwr.htm b/1_1.mi_Lua/luci/view/web/setting/wifi_txpwr.htm new file mode 100644 index 0000000..82734c7 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/setting/wifi_txpwr.htm @@ -0,0 +1,102 @@ +<% +--[[ + Info wifi 高级设置 +]]-- +local LuciJson = require("luci.json") +local ver = require("xiaoqiang.XQVersion").webVersion +local wifiUtil = require("xiaoqiang.util.XQWifiUtil") +local wifiTxpwr = wifiUtil.getWifiTxpwr(1) +%> +<%include('web/inc/head')%> +小米路由器 + + + +
+
+

WiFi信号强度

+
+
+
+
+
+ + + + + +
+ +
+ +
+
+
+
+ +<%include('web/inc/g.js.base')%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/sysauth.htm b/1_1.mi_Lua/luci/view/web/sysauth.htm new file mode 100644 index 0000000..c99e344 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/sysauth.htm @@ -0,0 +1,309 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local XQSysUtil = require "xiaoqiang.util.XQSysUtil" + -- local XQSecureUtil = require "xiaoqiang.util.XQSecureUtil" + if not XQSysUtil.getInitInfo() then + luci.http.redirect(luci.dispatcher.build_url("web", "init","hello")) + end + + local router_name = XQSysUtil.getRouterName() or "小米路由器" + local isBinded = (XQSysUtil.getPassportBindInfo() and 'true') or 'false' + local logType = 1 + if logtype then + logType = tonumber(logtype) or 1 + end + + local remote_addr = luci.http.getenv("REMOTE_ADDR") + local mac = luci.sys.net.ip4mac(remote_addr) + -- local xmLoginUrl = XQSecureUtil.passportLoginUrl() +%> +<%include ("web/inc/head")%> +登录 - 小米路由器 + + + + +
+
+ +
+
+ +
+ <%include ("web/inc/footermini")%> +
+<%include ("web/inc/g.js.base")%> + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/syslock.htm b/1_1.mi_Lua/luci/view/web/syslock.htm new file mode 100644 index 0000000..17586d9 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/syslock.htm @@ -0,0 +1,78 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +小米路由器 + + + + + +
+
+ +
+
+
+

路由器正在升级

+
+
+
+
+ 已更新0% +
+
+ +
+
+
+ <%include ("web/inc/footer")%> +
+<%include ("web/inc/g.js.base")%> + + + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/sysset.htm b/1_1.mi_Lua/luci/view/web/sysset.htm new file mode 100644 index 0000000..03ba797 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/sysset.htm @@ -0,0 +1,287 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +路由设置 - 小米路由器 + + + + +<%include ("web/inc/g.js.base")%> +<%include ("web/inc/g.js")%> +<%include ("web/inc/reboot.js")%> + + + diff --git a/1_1.mi_Lua/luci/view/web/urldetection.htm b/1_1.mi_Lua/luci/view/web/urldetection.htm new file mode 100644 index 0000000..883bf93 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/urldetection.htm @@ -0,0 +1,88 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion +%> +<%include ("web/inc/head")%> +小米路由器 + + + +
+
+
+

高级诊断

+
+
+
+ + +
+ +
+ +<%include ("web/inc/g.js.base")%> + \ No newline at end of file diff --git a/1_1.mi_Lua/luci/view/web/xmaccount.htm b/1_1.mi_Lua/luci/view/web/xmaccount.htm new file mode 100644 index 0000000..79d12c2 --- /dev/null +++ b/1_1.mi_Lua/luci/view/web/xmaccount.htm @@ -0,0 +1,45 @@ +<% + local ver = require("xiaoqiang.XQVersion").webVersion + local XQConfigs = require "xiaoqiang.common.XQConfigs" + local LuciUtil = require "luci.util" + + local getDvidCmd = XQConfigs.THRIFT_TO_MQTT_GET_DEVICEID + local deviceId = LuciUtil.exec(getDvidCmd) +%> +<%include ("web/inc/head")%> +登录 - 小米路由器 + + +<%include ("web/inc/g.js.base")%> + + + + \ No newline at end of file diff --git a/1_1.mi_Lua/mime.lua b/1_1.mi_Lua/mime.lua new file mode 100644 index 0000000..169eda2 --- /dev/null +++ b/1_1.mi_Lua/mime.lua @@ -0,0 +1,87 @@ +----------------------------------------------------------------------------- +-- MIME support for the Lua language. +-- Author: Diego Nehab +-- Conforming to RFCs 2045-2049 +-- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local ltn12 = require("ltn12") +local mime = require("mime.core") +local io = require("io") +local string = require("string") +module("mime") + +-- encode, decode and wrap algorithm tables +encodet = {} +decodet = {} +wrapt = {} + +-- creates a function that chooses a filter by name from a given table +local function choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then + base.error("unknown key (" .. base.tostring(name) .. ")", 3) + else return f(opt1, opt2) end + end +end + +-- define the encoding filters +encodet['base64'] = function() + return ltn12.filter.cycle(b64, "") +end + +encodet['quoted-printable'] = function(mode) + return ltn12.filter.cycle(qp, "", + (mode == "binary") and "=0D=0A" or "\r\n") +end + +-- define the decoding filters +decodet['base64'] = function() + return ltn12.filter.cycle(unb64, "") +end + +decodet['quoted-printable'] = function() + return ltn12.filter.cycle(unqp, "") +end + +local function format(chunk) + if chunk then + if chunk == "" then return "''" + else return string.len(chunk) end + else return "nil" end +end + +-- define the line-wrap filters +wrapt['text'] = function(length) + length = length or 76 + return ltn12.filter.cycle(wrp, length, length) +end +wrapt['base64'] = wrapt['text'] +wrapt['default'] = wrapt['text'] + +wrapt['quoted-printable'] = function() + return ltn12.filter.cycle(qpwrp, 76, 76) +end + +-- function that choose the encoding, decoding or wrap algorithm +encode = choose(encodet) +decode = choose(decodet) +wrap = choose(wrapt) + +-- define the end-of-line normalization filter +function normalize(marker) + return ltn12.filter.cycle(eol, 0, marker) +end + +-- high level stuffing filter +function stuff() + return ltn12.filter.cycle(dot, 2) +end diff --git a/1_1.mi_Lua/mime.so.1.0.2 b/1_1.mi_Lua/mime.so.1.0.2 new file mode 100644 index 0000000..61835c1 Binary files /dev/null and b/1_1.mi_Lua/mime.so.1.0.2 differ diff --git a/1_1.mi_Lua/net_tools.so b/1_1.mi_Lua/net_tools.so new file mode 100644 index 0000000..4750981 Binary files /dev/null and b/1_1.mi_Lua/net_tools.so differ diff --git a/1_1.mi_Lua/nixio.so b/1_1.mi_Lua/nixio.so new file mode 100644 index 0000000..75416c8 Binary files /dev/null and b/1_1.mi_Lua/nixio.so differ diff --git a/1_1.mi_Lua/nixio/fs.lua b/1_1.mi_Lua/nixio/fs.lua new file mode 100644 index 0000000..8883835 --- /dev/null +++ b/1_1.mi_Lua/nixio/fs.lua @@ -0,0 +1,175 @@ +--[[ +nixio - Linux I/O library for lua + +Copyright 2009 Steven Barth + +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 table = require "table" +local nixio = require "nixio" +local type, ipairs, setmetatable = type, ipairs, setmetatable +require "nixio.util" + + +module ("nixio.fs", function(m) setmetatable(m, {__index = nixio.fs}) end) + + +function readfile(path, limit) + local fd, code, msg = nixio.open(path, "r") + local data + if not fd then + return nil, code, msg + end + + data, code, msg = fd:readall(limit) + + fd:close() + return data, code, msg +end + + +function writefile(path, data) + local fd, code, msg, stat = nixio.open(path, "w") + if not fd then + return nil, code, msg + end + + stat, code, msg = fd:writeall(data) + + fd:close() + return stat, code, msg +end + +function datacopy(src, dest, size) + local fdin, code, msg = nixio.open(src, "r") + if not fdin then + return nil, code, msg + end + + local fdout, code, msg = nixio.open(dest, "w") + if not fdout then + return nil, code, msg + end + + local stat, code, msg, sent = fdin:copy(fdout, size) + fdin:close() + fdout:close() + + return stat, code, msg, sent +end + +function copy(src, dest) + local stat, code, msg, res = nixio.fs.lstat(src) + if not stat then + return nil, code, msg + end + + if stat.type == "dir" then + if nixio.fs.stat(dest, type) ~= "dir" then + res, code, msg = nixio.fs.mkdir(dest) + else + stat = true + end + elseif stat.type == "lnk" then + res, code, msg = nixio.fs.symlink(nixio.fs.readlink(src), dest) + elseif stat.type == "reg" then + res, code, msg = datacopy(src, dest) + end + + if not res then + return nil, code, msg + end + + nixio.fs.utimes(dest, stat.atime, stat.mtime) + + if nixio.fs.lchown then + nixio.fs.lchown(dest, stat.uid, stat.gid) + end + + if stat.type ~= "lnk" then + nixio.fs.chmod(dest, stat.modedec) + end + + return true +end + +function move(src, dest) + local stat, code, msg = nixio.fs.rename(src, dest) + if not stat and code == nixio.const.EXDEV then + stat, code, msg = copy(src, dest) + if stat then + stat, code, msg = nixio.fs.unlink(src) + end + end + return stat, code, msg +end + +function mkdirr(dest, mode) + if nixio.fs.stat(dest, "type") == "dir" then + return true + else + local stat, code, msg = nixio.fs.mkdir(dest, mode) + if not stat and code == nixio.const.ENOENT then + stat, code, msg = mkdirr(nixio.fs.dirname(dest), mode) + if stat then + stat, code, msg = nixio.fs.mkdir(dest, mode) + end + end + return stat, code, msg + end +end + +local function _recurse(cb, src, dest) + local type = nixio.fs.lstat(src, "type") + if type ~= "dir" then + return cb(src, dest) + else + local stat, se, code, msg, s, c, m = true, nixio.const.sep + if dest then + s, c, m = cb(src, dest) + stat, code, msg = stat and s, c or code, m or msg + end + + for e in nixio.fs.dir(src) do + if dest then + s, c, m = _recurse(cb, src .. se .. e, dest .. se .. e) + else + s, c, m = _recurse(cb, src .. se .. e) + end + stat, code, msg = stat and s, c or code, m or msg + end + + if not dest then -- Postfix + s, c, m = cb(src) + stat, code, msg = stat and s, c or code, m or msg + end + + return stat, code, msg + end +end + +function copyr(src, dest) + return _recurse(copy, src, dest) +end + +function mover(src, dest) + local stat, code, msg = nixio.fs.rename(src, dest) + if not stat and code == nixio.const.EXDEV then + stat, code, msg = _recurse(copy, src, dest) + if stat then + stat, code, msg = _recurse(nixio.fs.remove, src) + end + end + return stat, code, msg +end + +function remover(src) + return _recurse(nixio.fs.remove, src) +end \ No newline at end of file diff --git a/1_1.mi_Lua/nixio/util.lua b/1_1.mi_Lua/nixio/util.lua new file mode 100644 index 0000000..63d2f62 --- /dev/null +++ b/1_1.mi_Lua/nixio/util.lua @@ -0,0 +1,270 @@ +--[[ +nixio - Linux I/O library for lua + +Copyright 2009 Steven Barth + +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 table = require "table" +local nixio = require "nixio" +local getmetatable, assert, pairs, type = getmetatable, assert, pairs, type +local tostring = tostring + +module "nixio.util" + +local BUFFERSIZE = nixio.const.buffersize +local ZIOBLKSIZE = 65536 +local socket = nixio.meta_socket +local tls_socket = nixio.meta_tls_socket +local file = nixio.meta_file +local uname = nixio.uname() +local ZBUG = uname.sysname == "Linux" and uname.release:sub(1, 3) == "2.4" + +function consume(iter, append) + local tbl = append or {} + if iter then + for obj in iter do + tbl[#tbl+1] = obj + end + end + return tbl +end + +local meta = {} + +function meta.is_socket(self) + return (getmetatable(self) == socket) +end + +function meta.is_tls_socket(self) + return (getmetatable(self) == tls_socket) +end + +function meta.is_file(self) + return (getmetatable(self) == file) +end + +function meta.readall(self, len) + local block, code, msg = self:read(len or BUFFERSIZE) + + if not block then + return nil, code, msg, "" + elseif #block == 0 then + return "", nil, nil, "" + end + + local data, total = {block}, #block + + while not len or len > total do + block, code, msg = self:read(len and (len - total) or BUFFERSIZE) + + if not block then + return nil, code, msg, table.concat(data) + elseif #block == 0 then + break + end + + data[#data+1], total = block, total + #block + end + + local data = #data > 1 and table.concat(data) or data[1] + return data, nil, nil, data +end +meta.recvall = meta.readall + +function meta.writeall(self, data) + data = tostring(data) + local sent, code, msg = self:write(data) + + if not sent then + return nil, code, msg, 0 + end + + local total = sent + + while total < #data do + sent, code, msg = self:write(data, total) + + if not sent then + return nil, code, msg, total + end + + total = total + sent + end + + return total, nil, nil, total +end +meta.sendall = meta.writeall + +function meta.linesource(self, limit) + limit = limit or BUFFERSIZE + local buffer = "" + local bpos = 0 + return function(flush) + local line, endp, _ + + if flush then + line = buffer:sub(bpos + 1) + buffer = type(flush) == "string" and flush or "" + bpos = 0 + return line + end + + while not line do + _, endp, line = buffer:find("(.-)\r?\n", bpos + 1) + if line then + bpos = endp + return line + elseif #buffer < limit + bpos then + local newblock, code, msg = self:read(limit + bpos - #buffer) + if not newblock then + return nil, code, msg + elseif #newblock == 0 then + return nil + end + buffer = buffer:sub(bpos + 1) .. newblock + bpos = 0 + else + return nil, 0 + end + end + end +end + +function meta.blocksource(self, bs, limit) + bs = bs or BUFFERSIZE + return function() + local toread = bs + if limit then + if limit < 1 then + return nil + elseif limit < toread then + toread = limit + end + end + + local block, code, msg = self:read(toread) + + if not block then + return nil, code, msg + elseif #block == 0 then + return nil + else + if limit then + limit = limit - #block + end + + return block + end + end +end + +function meta.sink(self, close) + return function(chunk, src_err) + if not chunk and not src_err and close then + if self.shutdown then + self:shutdown() + end + self:close() + elseif chunk and #chunk > 0 then + return self:writeall(chunk) + end + return true + end +end + +function meta.copy(self, fdout, size) + local source = self:blocksource(nil, size) + local sink = fdout:sink() + local sent, chunk, code, msg = 0 + + repeat + chunk, code, msg = source() + sink(chunk, code, msg) + sent = chunk and (sent + #chunk) or sent + until not chunk + return not code and sent or nil, code, msg, sent +end + +function meta.copyz(self, fd, size) + local sent, lsent, code, msg = 0 + local splicable + + if not ZBUG and self:is_file() then + local ftype = self:stat("type") + if nixio.sendfile and fd:is_socket() and ftype == "reg" then + repeat + lsent, code, msg = nixio.sendfile(fd, self, size or ZIOBLKSIZE) + if lsent then + sent = sent + lsent + size = size and (size - lsent) + end + until (not lsent or lsent == 0 or (size and size == 0)) + if lsent or (not lsent and sent == 0 and + code ~= nixio.const.ENOSYS and code ~= nixio.const.EINVAL) then + return lsent and sent, code, msg, sent + end + elseif nixio.splice and not fd:is_tls_socket() and ftype == "fifo" then + splicable = true + end + end + + if nixio.splice and fd:is_file() and not splicable then + splicable = not self:is_tls_socket() and fd:stat("type") == "fifo" + end + + if splicable then + repeat + lsent, code, msg = nixio.splice(self, fd, size or ZIOBLKSIZE) + if lsent then + sent = sent + lsent + size = size and (size - lsent) + end + until (not lsent or lsent == 0 or (size and size == 0)) + if lsent or (not lsent and sent == 0 and + code ~= nixio.const.ENOSYS and code ~= nixio.const.EINVAL) then + return lsent and sent, code, msg, sent + end + end + + return self:copy(fd, size) +end + +if tls_socket then + function tls_socket.close(self) + return self.socket:close() + end + + function tls_socket.getsockname(self) + return self.socket:getsockname() + end + + function tls_socket.getpeername(self) + return self.socket:getpeername() + end + + function tls_socket.getsockopt(self, ...) + return self.socket:getsockopt(...) + end + tls_socket.getopt = tls_socket.getsockopt + + function tls_socket.setsockopt(self, ...) + return self.socket:setsockopt(...) + end + tls_socket.setopt = tls_socket.setsockopt +end + +for k, v in pairs(meta) do + file[k] = v + socket[k] = v + if tls_socket then + tls_socket[k] = v + end +end diff --git a/1_1.mi_Lua/posix.so b/1_1.mi_Lua/posix.so new file mode 100644 index 0000000..f014dc0 Binary files /dev/null and b/1_1.mi_Lua/posix.so differ diff --git a/1_1.mi_Lua/rc4.lua b/1_1.mi_Lua/rc4.lua new file mode 100644 index 0000000..52d029e --- /dev/null +++ b/1_1.mi_Lua/rc4.lua @@ -0,0 +1,77 @@ + +local string = require("string") +local bit = require("bit") + +module("rc4") + +local function swapStateIndicies(state) + local t = state.schedule[state.i] + state.schedule[state.i] = state.schedule[state.j] + state.schedule[state.j] = t +end + +local function swapIndicies(sch, i, j) + local t = sch[i] + sch[i] = sch[j] + sch[j] = t +end + +local function createKeySchedule(sKey) + local nKeyLength = string.len(sKey) + local tKey = { string.byte(sKey, 1, nKeyLength) } + if nKeyLength < 1 or nKeyLength > 256 then + error("Key length out of bounds. 1 <= length <= 256") + end + local tSch = {} + for i = 0, 255 do + tSch[i] = i + end + local j = 0 + for i = 0, 255 do + j = (j + tSch[i] + tKey[(i % nKeyLength) + 1]) % 256 + swapIndicies(tSch, i, j) + end + return tSch +end + +local function keyGeneration(state, nCount) + local K = {} + for i = 1, nCount do + state.i = (state.i + 1) % 256 + state.j = (state.j + state.schedule[state.i - 1]) % 256 + swapStateIndicies(state) + K[#K+1] = state.schedule[(state.schedule[ state.i - 1] + state.schedule[ state.j - 1] - 1) % 256] + end + return K +end + +local function cipher(sMessage, state) + local nCount = string.len(sMessage) + local K = keyGeneration(state, nCount) + local sOutput = "" + for i = 1, nCount do + sOutput = sOutput .. string.char(bit.bxor( K[i], string.byte(sMessage, i))) + end + return sOutput +end + +function new(sKey, bEncryption) + local tSch = createKeySchedule(sKey) + local nS1 = 0 + local nS2 = 0 + local state = { + i = nS1, + j = nS2, + schedule = tSch + } + local tSession = {} + local sFuncName = "decrypt" + if bEncryption then + sFuncName = "encrypt" + end + tSession[sFuncName] = function(sMessage) + local sOutput = cipher(sMessage, state) + return sOutput + end + return tSession +end \ No newline at end of file diff --git a/1_1.mi_Lua/service/util/ServiceErrorUtil.lua b/1_1.mi_Lua/service/util/ServiceErrorUtil.lua new file mode 100644 index 0000000..b83bf39 --- /dev/null +++ b/1_1.mi_Lua/service/util/ServiceErrorUtil.lua @@ -0,0 +1,24 @@ +module ("service.util.ServiceErrorUtil", package.seeall) + +function getErrorMessage(errorCode) + local errorList = {} + + errorList[0] = _("") + errorList[1] = _("parameter missing") + errorList[2] = _("Parameter empty") + errorList[3] = _("Parameter format error") + errorList[5] = _("invalid app id") + + errorList[1056] = _("invalid device id") + errorList[1057] = _("resource is not ready") + + errorList[1559] = _("datacenter error") + + errorList[2010] = _("datacenter error") + + if (errorList[errorCode] == nil) then + return translate(_("未知错误")) + else + return translate(errorList[errorCode]) + end +end diff --git a/1_1.mi_Lua/sha1.lua b/1_1.mi_Lua/sha1.lua new file mode 100644 index 0000000..12971b7 --- /dev/null +++ b/1_1.mi_Lua/sha1.lua @@ -0,0 +1,718 @@ +-- +-- SHA-1 secure hash computation, and HMAC-SHA1 signature computation, +-- in pure Lua (tested on Lua 5.1) +-- +-- Latest version always at: http://regex.info/blog/lua/sha1 +-- +-- Copyright 2009 Jeffrey Friedl +-- jfriedl@yahoo.com +-- http://regex.info/blog/ +-- +-- +-- Version 1 [May 28, 2009] +-- +-- +-- Lua is a pathetic, horrid, turd of a language. Not only doesn't it have +-- bitwise integer operators like OR and AND, it doesn't even have integers +-- (and those, relatively speaking, are its good points). Yet, this +-- implements the SHA-1 digest hash in pure Lua. While coding it, I felt as +-- if I were chiseling NAND gates out of rough blocks of silicon. Those not +-- already familiar with this woeful language may, upon seeing this code, +-- throw up in their own mouth. +-- +-- It's not super fast.... a 10k-byte message takes about 2 seconds on a +-- circa-2008 mid-level server, but it should be plenty adequate for short +-- messages, such as is often needed during authentication handshaking. +-- +-- Algorithm: http://www.itl.nist.gov/fipspubs/fip180-1.htm +-- +-- This file creates four entries in the global namespace: +-- +-- local hash_as_hex = sha1(message) -- returns a hex string +-- local hash_as_data = sha1_binary(message) -- returns raw bytes +-- +-- local hmac_as_hex = hmac_sha1(key, message) -- hex string +-- local hmac_as_data = hmac_sha1_binary(key, message) -- raw bytes +-- +-- Pass sha1() a string, and it returns a hash as a 40-character hex string. +-- For example, the call +-- +-- local hash = sha1 "http://regex.info/blog/" +-- +-- puts the 40-character string +-- +-- "7f103bf600de51dfe91062300c14738b32725db5" +-- +-- into the variable 'hash' +-- +-- Pass sha1_hmac() a key and a message, and it returns the signature as a +-- 40-byte hex string. +-- +-- +-- The two "_binary" versions do the same, but return the 20-byte string of raw data +-- that the 40-byte hex strings represent. +-- + +------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------ +local string = require("string") +local table = require("table") +local math = require("math") +local base = _G + +module("sha1") + +-- +-- Return a W32 object for the number zero +-- +local function ZERO() + return { + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + } +end + +local hex_to_bits = { + ["0"] = { false, false, false, false }, + ["1"] = { false, false, false, true }, + ["2"] = { false, false, true, false }, + ["3"] = { false, false, true, true }, + + ["4"] = { false, true, false, false }, + ["5"] = { false, true, false, true }, + ["6"] = { false, true, true, false }, + ["7"] = { false, true, true, true }, + + ["8"] = { true, false, false, false }, + ["9"] = { true, false, false, true }, + ["A"] = { true, false, true, false }, + ["B"] = { true, false, true, true }, + + ["C"] = { true, true, false, false }, + ["D"] = { true, true, false, true }, + ["E"] = { true, true, true, false }, + ["F"] = { true, true, true, true }, + + ["a"] = { true, false, true, false }, + ["b"] = { true, false, true, true }, + ["c"] = { true, true, false, false }, + ["d"] = { true, true, false, true }, + ["e"] = { true, true, true, false }, + ["f"] = { true, true, true, true }, +} + +-- +-- Given a string of 8 hex digits, return a W32 object representing that number +-- +local function from_hex(hex) + + base.assert(base.type(hex) == 'string') + base.assert(hex:match('^[0123456789abcdefABCDEF]+$')) + base.assert(#hex == 8) + + local W32 = { } + + for letter in hex:gmatch('.') do + local b = hex_to_bits[letter] + base.assert(b) + table.insert(W32, 1, b[1]) + table.insert(W32, 1, b[2]) + table.insert(W32, 1, b[3]) + table.insert(W32, 1, b[4]) + end + + return W32 +end + +local function COPY(old) + local W32 = { } + for k,v in base.pairs(old) do + W32[k] = v + end + + return W32 +end + +local function ADD(first, ...) + + local a = COPY(first) + + local C, b, sum + + for v = 1, base.select('#', ...) do + b = base.select(v, ...) + C = 0 + + for i = 1, #a do + sum = (a[i] and 1 or 0) + + (b[i] and 1 or 0) + + C + + if sum == 0 then + a[i] = false + C = 0 + elseif sum == 1 then + a[i] = true + C = 0 + elseif sum == 2 then + a[i] = false + C = 1 + else + a[i] = true + C = 1 + end + end + -- we drop any ending carry + + end + + return a +end + +local function XOR(first, ...) + + local a = COPY(first) + local b + for v = 1, base.select('#', ...) do + b = base.select(v, ...) + for i = 1, #a do + a[i] = a[i] ~= b[i] + end + end + + return a + +end + +local function AND(a, b) + + local c = ZERO() + + for i = 1, #a do + -- only need to set true bits; other bits remain false + if a[i] and b[i] then + c[i] = true + end + end + + return c +end + +local function OR(a, b) + + local c = ZERO() + + for i = 1, #a do + -- only need to set true bits; other bits remain false + if a[i] or b[i] then + c[i] = true + end + end + + return c +end + +local function OR3(a, b, c) + + local d = ZERO() + + for i = 1, #a do + -- only need to set true bits; other bits remain false + if a[i] or b[i] or c[i] then + d[i] = true + end + end + + return d +end + +local function NOT(a) + + local b = ZERO() + + for i = 1, #a do + -- only need to set true bits; other bits remain false + if not a[i] then + b[i] = true + end + end + + return b +end + +local function ROTATE(bits, a) + + local b = COPY(a) + + while bits > 0 do + bits = bits - 1 + table.insert(b, 1, table.remove(b)) + end + + return b + +end + + +local binary_to_hex = { + ["0000"] = "0", + ["0001"] = "1", + ["0010"] = "2", + ["0011"] = "3", + ["0100"] = "4", + ["0101"] = "5", + ["0110"] = "6", + ["0111"] = "7", + ["1000"] = "8", + ["1001"] = "9", + ["1010"] = "a", + ["1011"] = "b", + ["1100"] = "c", + ["1101"] = "d", + ["1110"] = "e", + ["1111"] = "f", +} + +function asHEX(a) + + local hex = "" + local i = 1 + while i < #a do + local binary = (a[i + 3] and '1' or '0') + .. + (a[i + 2] and '1' or '0') + .. + (a[i + 1] and '1' or '0') + .. + (a[i + 0] and '1' or '0') + + hex = binary_to_hex[binary] .. hex + + i = i + 4 + end + + return hex + +end + +local x67452301 = from_hex("67452301") +local xEFCDAB89 = from_hex("EFCDAB89") +local x98BADCFE = from_hex("98BADCFE") +local x10325476 = from_hex("10325476") +local xC3D2E1F0 = from_hex("C3D2E1F0") + +local x5A827999 = from_hex("5A827999") +local x6ED9EBA1 = from_hex("6ED9EBA1") +local x8F1BBCDC = from_hex("8F1BBCDC") +local xCA62C1D6 = from_hex("CA62C1D6") + + +function sha1(msg) + + base.assert(base.type(msg) == 'string') + base.assert(#msg < 0x7FFFFFFF) -- have no idea what would happen if it were large + + local H0 = x67452301 + local H1 = xEFCDAB89 + local H2 = x98BADCFE + local H3 = x10325476 + local H4 = xC3D2E1F0 + + local msg_len_in_bits = #msg * 8 + + local first_append = string.char(0x80) -- append a '1' bit plus seven '0' bits + + local non_zero_message_bytes = #msg +1 +8 -- the +1 is the appended bit 1, the +8 are for the final appended length + local current_mod = non_zero_message_bytes % 64 + local second_append = "" + if current_mod ~= 0 then + second_append = string.rep(string.char(0), 64 - current_mod) + end + + -- now to append the length as a 64-bit number. + local B1, R1 = math.modf(msg_len_in_bits / 0x01000000) + local B2, R2 = math.modf( 0x01000000 * R1 / 0x00010000) + local B3, R3 = math.modf( 0x00010000 * R2 / 0x00000100) + local B4 = 0x00000100 * R3 + + local L64 = string.char( 0) .. string.char( 0) .. string.char( 0) .. string.char( 0) -- high 32 bits + .. string.char(B1) .. string.char(B2) .. string.char(B3) .. string.char(B4) -- low 32 bits + + + + msg = msg .. first_append .. second_append .. L64 + + base.assert(#msg % 64 == 0) + + --local fd = io.open("/tmp/msg", "wb") + --fd:write(msg) + --fd:close() + + local chunks = #msg / 64 + + local W = { } + local start, A, B, C, D, E, f, K, TEMP + local chunk = 0 + + while chunk < chunks do + -- + -- break chunk up into W[0] through W[15] + -- + start = chunk * 64 + 1 + chunk = chunk + 1 + + for t = 0, 15 do + W[t] = from_hex(string.format("%02x%02x%02x%02x", msg:byte(start, start + 3))) + start = start + 4 + end + + -- + -- build W[16] through W[79] + -- + for t = 16, 79 do + -- For t = 16 to 79 let Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16). + W[t] = ROTATE(1, XOR(W[t-3], W[t-8], W[t-14], W[t-16])) + end + + A = H0 + B = H1 + C = H2 + D = H3 + E = H4 + + for t = 0, 79 do + if t <= 19 then + -- (B AND C) OR ((NOT B) AND D) + f = OR(AND(B, C), AND(NOT(B), D)) + K = x5A827999 + elseif t <= 39 then + -- B XOR C XOR D + f = XOR(B, C, D) + K = x6ED9EBA1 + elseif t <= 59 then + -- (B AND C) OR (B AND D) OR (C AND D + f = OR3(AND(B, C), AND(B, D), AND(C, D)) + K = x8F1BBCDC + else + -- B XOR C XOR D + f = XOR(B, C, D) + K = xCA62C1D6 + end + + -- TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt; + TEMP = ADD(ROTATE(5, A), f, E, W[t], K) + + E = D + D = C + C = ROTATE(30, B) + B = A + A = TEMP + + --printf("t = %2d: %s %s %s %s %s", t, A:HEX(), B:HEX(), C:HEX(), D:HEX(), E:HEX()) + end + + -- Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E. + H0 = ADD(H0, A) + H1 = ADD(H1, B) + H2 = ADD(H2, C) + H3 = ADD(H3, D) + H4 = ADD(H4, E) + end + + return asHEX(H0) .. asHEX(H1) .. asHEX(H2) .. asHEX(H3) .. asHEX(H4) +end + +local function hex_to_binary(hex) + return hex:gsub('..', function(hexval) + return string.char(base.tonumber(hexval, 16)) + end) +end + +function sha1_binary(msg) + return hex_to_binary(sha1(msg)) +end + +local xor_with_0x5c = { + [string.char( 0)] = string.char( 92), [string.char( 1)] = string.char( 93), + [string.char( 2)] = string.char( 94), [string.char( 3)] = string.char( 95), + [string.char( 4)] = string.char( 88), [string.char( 5)] = string.char( 89), + [string.char( 6)] = string.char( 90), [string.char( 7)] = string.char( 91), + [string.char( 8)] = string.char( 84), [string.char( 9)] = string.char( 85), + [string.char( 10)] = string.char( 86), [string.char( 11)] = string.char( 87), + [string.char( 12)] = string.char( 80), [string.char( 13)] = string.char( 81), + [string.char( 14)] = string.char( 82), [string.char( 15)] = string.char( 83), + [string.char( 16)] = string.char( 76), [string.char( 17)] = string.char( 77), + [string.char( 18)] = string.char( 78), [string.char( 19)] = string.char( 79), + [string.char( 20)] = string.char( 72), [string.char( 21)] = string.char( 73), + [string.char( 22)] = string.char( 74), [string.char( 23)] = string.char( 75), + [string.char( 24)] = string.char( 68), [string.char( 25)] = string.char( 69), + [string.char( 26)] = string.char( 70), [string.char( 27)] = string.char( 71), + [string.char( 28)] = string.char( 64), [string.char( 29)] = string.char( 65), + [string.char( 30)] = string.char( 66), [string.char( 31)] = string.char( 67), + [string.char( 32)] = string.char(124), [string.char( 33)] = string.char(125), + [string.char( 34)] = string.char(126), [string.char( 35)] = string.char(127), + [string.char( 36)] = string.char(120), [string.char( 37)] = string.char(121), + [string.char( 38)] = string.char(122), [string.char( 39)] = string.char(123), + [string.char( 40)] = string.char(116), [string.char( 41)] = string.char(117), + [string.char( 42)] = string.char(118), [string.char( 43)] = string.char(119), + [string.char( 44)] = string.char(112), [string.char( 45)] = string.char(113), + [string.char( 46)] = string.char(114), [string.char( 47)] = string.char(115), + [string.char( 48)] = string.char(108), [string.char( 49)] = string.char(109), + [string.char( 50)] = string.char(110), [string.char( 51)] = string.char(111), + [string.char( 52)] = string.char(104), [string.char( 53)] = string.char(105), + [string.char( 54)] = string.char(106), [string.char( 55)] = string.char(107), + [string.char( 56)] = string.char(100), [string.char( 57)] = string.char(101), + [string.char( 58)] = string.char(102), [string.char( 59)] = string.char(103), + [string.char( 60)] = string.char( 96), [string.char( 61)] = string.char( 97), + [string.char( 62)] = string.char( 98), [string.char( 63)] = string.char( 99), + [string.char( 64)] = string.char( 28), [string.char( 65)] = string.char( 29), + [string.char( 66)] = string.char( 30), [string.char( 67)] = string.char( 31), + [string.char( 68)] = string.char( 24), [string.char( 69)] = string.char( 25), + [string.char( 70)] = string.char( 26), [string.char( 71)] = string.char( 27), + [string.char( 72)] = string.char( 20), [string.char( 73)] = string.char( 21), + [string.char( 74)] = string.char( 22), [string.char( 75)] = string.char( 23), + [string.char( 76)] = string.char( 16), [string.char( 77)] = string.char( 17), + [string.char( 78)] = string.char( 18), [string.char( 79)] = string.char( 19), + [string.char( 80)] = string.char( 12), [string.char( 81)] = string.char( 13), + [string.char( 82)] = string.char( 14), [string.char( 83)] = string.char( 15), + [string.char( 84)] = string.char( 8), [string.char( 85)] = string.char( 9), + [string.char( 86)] = string.char( 10), [string.char( 87)] = string.char( 11), + [string.char( 88)] = string.char( 4), [string.char( 89)] = string.char( 5), + [string.char( 90)] = string.char( 6), [string.char( 91)] = string.char( 7), + [string.char( 92)] = string.char( 0), [string.char( 93)] = string.char( 1), + [string.char( 94)] = string.char( 2), [string.char( 95)] = string.char( 3), + [string.char( 96)] = string.char( 60), [string.char( 97)] = string.char( 61), + [string.char( 98)] = string.char( 62), [string.char( 99)] = string.char( 63), + [string.char(100)] = string.char( 56), [string.char(101)] = string.char( 57), + [string.char(102)] = string.char( 58), [string.char(103)] = string.char( 59), + [string.char(104)] = string.char( 52), [string.char(105)] = string.char( 53), + [string.char(106)] = string.char( 54), [string.char(107)] = string.char( 55), + [string.char(108)] = string.char( 48), [string.char(109)] = string.char( 49), + [string.char(110)] = string.char( 50), [string.char(111)] = string.char( 51), + [string.char(112)] = string.char( 44), [string.char(113)] = string.char( 45), + [string.char(114)] = string.char( 46), [string.char(115)] = string.char( 47), + [string.char(116)] = string.char( 40), [string.char(117)] = string.char( 41), + [string.char(118)] = string.char( 42), [string.char(119)] = string.char( 43), + [string.char(120)] = string.char( 36), [string.char(121)] = string.char( 37), + [string.char(122)] = string.char( 38), [string.char(123)] = string.char( 39), + [string.char(124)] = string.char( 32), [string.char(125)] = string.char( 33), + [string.char(126)] = string.char( 34), [string.char(127)] = string.char( 35), + [string.char(128)] = string.char(220), [string.char(129)] = string.char(221), + [string.char(130)] = string.char(222), [string.char(131)] = string.char(223), + [string.char(132)] = string.char(216), [string.char(133)] = string.char(217), + [string.char(134)] = string.char(218), [string.char(135)] = string.char(219), + [string.char(136)] = string.char(212), [string.char(137)] = string.char(213), + [string.char(138)] = string.char(214), [string.char(139)] = string.char(215), + [string.char(140)] = string.char(208), [string.char(141)] = string.char(209), + [string.char(142)] = string.char(210), [string.char(143)] = string.char(211), + [string.char(144)] = string.char(204), [string.char(145)] = string.char(205), + [string.char(146)] = string.char(206), [string.char(147)] = string.char(207), + [string.char(148)] = string.char(200), [string.char(149)] = string.char(201), + [string.char(150)] = string.char(202), [string.char(151)] = string.char(203), + [string.char(152)] = string.char(196), [string.char(153)] = string.char(197), + [string.char(154)] = string.char(198), [string.char(155)] = string.char(199), + [string.char(156)] = string.char(192), [string.char(157)] = string.char(193), + [string.char(158)] = string.char(194), [string.char(159)] = string.char(195), + [string.char(160)] = string.char(252), [string.char(161)] = string.char(253), + [string.char(162)] = string.char(254), [string.char(163)] = string.char(255), + [string.char(164)] = string.char(248), [string.char(165)] = string.char(249), + [string.char(166)] = string.char(250), [string.char(167)] = string.char(251), + [string.char(168)] = string.char(244), [string.char(169)] = string.char(245), + [string.char(170)] = string.char(246), [string.char(171)] = string.char(247), + [string.char(172)] = string.char(240), [string.char(173)] = string.char(241), + [string.char(174)] = string.char(242), [string.char(175)] = string.char(243), + [string.char(176)] = string.char(236), [string.char(177)] = string.char(237), + [string.char(178)] = string.char(238), [string.char(179)] = string.char(239), + [string.char(180)] = string.char(232), [string.char(181)] = string.char(233), + [string.char(182)] = string.char(234), [string.char(183)] = string.char(235), + [string.char(184)] = string.char(228), [string.char(185)] = string.char(229), + [string.char(186)] = string.char(230), [string.char(187)] = string.char(231), + [string.char(188)] = string.char(224), [string.char(189)] = string.char(225), + [string.char(190)] = string.char(226), [string.char(191)] = string.char(227), + [string.char(192)] = string.char(156), [string.char(193)] = string.char(157), + [string.char(194)] = string.char(158), [string.char(195)] = string.char(159), + [string.char(196)] = string.char(152), [string.char(197)] = string.char(153), + [string.char(198)] = string.char(154), [string.char(199)] = string.char(155), + [string.char(200)] = string.char(148), [string.char(201)] = string.char(149), + [string.char(202)] = string.char(150), [string.char(203)] = string.char(151), + [string.char(204)] = string.char(144), [string.char(205)] = string.char(145), + [string.char(206)] = string.char(146), [string.char(207)] = string.char(147), + [string.char(208)] = string.char(140), [string.char(209)] = string.char(141), + [string.char(210)] = string.char(142), [string.char(211)] = string.char(143), + [string.char(212)] = string.char(136), [string.char(213)] = string.char(137), + [string.char(214)] = string.char(138), [string.char(215)] = string.char(139), + [string.char(216)] = string.char(132), [string.char(217)] = string.char(133), + [string.char(218)] = string.char(134), [string.char(219)] = string.char(135), + [string.char(220)] = string.char(128), [string.char(221)] = string.char(129), + [string.char(222)] = string.char(130), [string.char(223)] = string.char(131), + [string.char(224)] = string.char(188), [string.char(225)] = string.char(189), + [string.char(226)] = string.char(190), [string.char(227)] = string.char(191), + [string.char(228)] = string.char(184), [string.char(229)] = string.char(185), + [string.char(230)] = string.char(186), [string.char(231)] = string.char(187), + [string.char(232)] = string.char(180), [string.char(233)] = string.char(181), + [string.char(234)] = string.char(182), [string.char(235)] = string.char(183), + [string.char(236)] = string.char(176), [string.char(237)] = string.char(177), + [string.char(238)] = string.char(178), [string.char(239)] = string.char(179), + [string.char(240)] = string.char(172), [string.char(241)] = string.char(173), + [string.char(242)] = string.char(174), [string.char(243)] = string.char(175), + [string.char(244)] = string.char(168), [string.char(245)] = string.char(169), + [string.char(246)] = string.char(170), [string.char(247)] = string.char(171), + [string.char(248)] = string.char(164), [string.char(249)] = string.char(165), + [string.char(250)] = string.char(166), [string.char(251)] = string.char(167), + [string.char(252)] = string.char(160), [string.char(253)] = string.char(161), + [string.char(254)] = string.char(162), [string.char(255)] = string.char(163), +} + +local xor_with_0x36 = { + [string.char( 0)] = string.char( 54), [string.char( 1)] = string.char( 55), + [string.char( 2)] = string.char( 52), [string.char( 3)] = string.char( 53), + [string.char( 4)] = string.char( 50), [string.char( 5)] = string.char( 51), + [string.char( 6)] = string.char( 48), [string.char( 7)] = string.char( 49), + [string.char( 8)] = string.char( 62), [string.char( 9)] = string.char( 63), + [string.char( 10)] = string.char( 60), [string.char( 11)] = string.char( 61), + [string.char( 12)] = string.char( 58), [string.char( 13)] = string.char( 59), + [string.char( 14)] = string.char( 56), [string.char( 15)] = string.char( 57), + [string.char( 16)] = string.char( 38), [string.char( 17)] = string.char( 39), + [string.char( 18)] = string.char( 36), [string.char( 19)] = string.char( 37), + [string.char( 20)] = string.char( 34), [string.char( 21)] = string.char( 35), + [string.char( 22)] = string.char( 32), [string.char( 23)] = string.char( 33), + [string.char( 24)] = string.char( 46), [string.char( 25)] = string.char( 47), + [string.char( 26)] = string.char( 44), [string.char( 27)] = string.char( 45), + [string.char( 28)] = string.char( 42), [string.char( 29)] = string.char( 43), + [string.char( 30)] = string.char( 40), [string.char( 31)] = string.char( 41), + [string.char( 32)] = string.char( 22), [string.char( 33)] = string.char( 23), + [string.char( 34)] = string.char( 20), [string.char( 35)] = string.char( 21), + [string.char( 36)] = string.char( 18), [string.char( 37)] = string.char( 19), + [string.char( 38)] = string.char( 16), [string.char( 39)] = string.char( 17), + [string.char( 40)] = string.char( 30), [string.char( 41)] = string.char( 31), + [string.char( 42)] = string.char( 28), [string.char( 43)] = string.char( 29), + [string.char( 44)] = string.char( 26), [string.char( 45)] = string.char( 27), + [string.char( 46)] = string.char( 24), [string.char( 47)] = string.char( 25), + [string.char( 48)] = string.char( 6), [string.char( 49)] = string.char( 7), + [string.char( 50)] = string.char( 4), [string.char( 51)] = string.char( 5), + [string.char( 52)] = string.char( 2), [string.char( 53)] = string.char( 3), + [string.char( 54)] = string.char( 0), [string.char( 55)] = string.char( 1), + [string.char( 56)] = string.char( 14), [string.char( 57)] = string.char( 15), + [string.char( 58)] = string.char( 12), [string.char( 59)] = string.char( 13), + [string.char( 60)] = string.char( 10), [string.char( 61)] = string.char( 11), + [string.char( 62)] = string.char( 8), [string.char( 63)] = string.char( 9), + [string.char( 64)] = string.char(118), [string.char( 65)] = string.char(119), + [string.char( 66)] = string.char(116), [string.char( 67)] = string.char(117), + [string.char( 68)] = string.char(114), [string.char( 69)] = string.char(115), + [string.char( 70)] = string.char(112), [string.char( 71)] = string.char(113), + [string.char( 72)] = string.char(126), [string.char( 73)] = string.char(127), + [string.char( 74)] = string.char(124), [string.char( 75)] = string.char(125), + [string.char( 76)] = string.char(122), [string.char( 77)] = string.char(123), + [string.char( 78)] = string.char(120), [string.char( 79)] = string.char(121), + [string.char( 80)] = string.char(102), [string.char( 81)] = string.char(103), + [string.char( 82)] = string.char(100), [string.char( 83)] = string.char(101), + [string.char( 84)] = string.char( 98), [string.char( 85)] = string.char( 99), + [string.char( 86)] = string.char( 96), [string.char( 87)] = string.char( 97), + [string.char( 88)] = string.char(110), [string.char( 89)] = string.char(111), + [string.char( 90)] = string.char(108), [string.char( 91)] = string.char(109), + [string.char( 92)] = string.char(106), [string.char( 93)] = string.char(107), + [string.char( 94)] = string.char(104), [string.char( 95)] = string.char(105), + [string.char( 96)] = string.char( 86), [string.char( 97)] = string.char( 87), + [string.char( 98)] = string.char( 84), [string.char( 99)] = string.char( 85), + [string.char(100)] = string.char( 82), [string.char(101)] = string.char( 83), + [string.char(102)] = string.char( 80), [string.char(103)] = string.char( 81), + [string.char(104)] = string.char( 94), [string.char(105)] = string.char( 95), + [string.char(106)] = string.char( 92), [string.char(107)] = string.char( 93), + [string.char(108)] = string.char( 90), [string.char(109)] = string.char( 91), + [string.char(110)] = string.char( 88), [string.char(111)] = string.char( 89), + [string.char(112)] = string.char( 70), [string.char(113)] = string.char( 71), + [string.char(114)] = string.char( 68), [string.char(115)] = string.char( 69), + [string.char(116)] = string.char( 66), [string.char(117)] = string.char( 67), + [string.char(118)] = string.char( 64), [string.char(119)] = string.char( 65), + [string.char(120)] = string.char( 78), [string.char(121)] = string.char( 79), + [string.char(122)] = string.char( 76), [string.char(123)] = string.char( 77), + [string.char(124)] = string.char( 74), [string.char(125)] = string.char( 75), + [string.char(126)] = string.char( 72), [string.char(127)] = string.char( 73), + [string.char(128)] = string.char(182), [string.char(129)] = string.char(183), + [string.char(130)] = string.char(180), [string.char(131)] = string.char(181), + [string.char(132)] = string.char(178), [string.char(133)] = string.char(179), + [string.char(134)] = string.char(176), [string.char(135)] = string.char(177), + [string.char(136)] = string.char(190), [string.char(137)] = string.char(191), + [string.char(138)] = string.char(188), [string.char(139)] = string.char(189), + [string.char(140)] = string.char(186), [string.char(141)] = string.char(187), + [string.char(142)] = string.char(184), [string.char(143)] = string.char(185), + [string.char(144)] = string.char(166), [string.char(145)] = string.char(167), + [string.char(146)] = string.char(164), [string.char(147)] = string.char(165), + [string.char(148)] = string.char(162), [string.char(149)] = string.char(163), + [string.char(150)] = string.char(160), [string.char(151)] = string.char(161), + [string.char(152)] = string.char(174), [string.char(153)] = string.char(175), + [string.char(154)] = string.char(172), [string.char(155)] = string.char(173), + [string.char(156)] = string.char(170), [string.char(157)] = string.char(171), + [string.char(158)] = string.char(168), [string.char(159)] = string.char(169), + [string.char(160)] = string.char(150), [string.char(161)] = string.char(151), + [string.char(162)] = string.char(148), [string.char(163)] = string.char(149), + [string.char(164)] = string.char(146), [string.char(165)] = string.char(147), + [string.char(166)] = string.char(144), [string.char(167)] = string.char(145), + [string.char(168)] = string.char(158), [string.char(169)] = string.char(159), + [string.char(170)] = string.char(156), [string.char(171)] = string.char(157), + [string.char(172)] = string.char(154), [string.char(173)] = string.char(155), + [string.char(174)] = string.char(152), [string.char(175)] = string.char(153), + [string.char(176)] = string.char(134), [string.char(177)] = string.char(135), + [string.char(178)] = string.char(132), [string.char(179)] = string.char(133), + [string.char(180)] = string.char(130), [string.char(181)] = string.char(131), + [string.char(182)] = string.char(128), [string.char(183)] = string.char(129), + [string.char(184)] = string.char(142), [string.char(185)] = string.char(143), + [string.char(186)] = string.char(140), [string.char(187)] = string.char(141), + [string.char(188)] = string.char(138), [string.char(189)] = string.char(139), + [string.char(190)] = string.char(136), [string.char(191)] = string.char(137), + [string.char(192)] = string.char(246), [string.char(193)] = string.char(247), + [string.char(194)] = string.char(244), [string.char(195)] = string.char(245), + [string.char(196)] = string.char(242), [string.char(197)] = string.char(243), + [string.char(198)] = string.char(240), [string.char(199)] = string.char(241), + [string.char(200)] = string.char(254), [string.char(201)] = string.char(255), + [string.char(202)] = string.char(252), [string.char(203)] = string.char(253), + [string.char(204)] = string.char(250), [string.char(205)] = string.char(251), + [string.char(206)] = string.char(248), [string.char(207)] = string.char(249), + [string.char(208)] = string.char(230), [string.char(209)] = string.char(231), + [string.char(210)] = string.char(228), [string.char(211)] = string.char(229), + [string.char(212)] = string.char(226), [string.char(213)] = string.char(227), + [string.char(214)] = string.char(224), [string.char(215)] = string.char(225), + [string.char(216)] = string.char(238), [string.char(217)] = string.char(239), + [string.char(218)] = string.char(236), [string.char(219)] = string.char(237), + [string.char(220)] = string.char(234), [string.char(221)] = string.char(235), + [string.char(222)] = string.char(232), [string.char(223)] = string.char(233), + [string.char(224)] = string.char(214), [string.char(225)] = string.char(215), + [string.char(226)] = string.char(212), [string.char(227)] = string.char(213), + [string.char(228)] = string.char(210), [string.char(229)] = string.char(211), + [string.char(230)] = string.char(208), [string.char(231)] = string.char(209), + [string.char(232)] = string.char(222), [string.char(233)] = string.char(223), + [string.char(234)] = string.char(220), [string.char(235)] = string.char(221), + [string.char(236)] = string.char(218), [string.char(237)] = string.char(219), + [string.char(238)] = string.char(216), [string.char(239)] = string.char(217), + [string.char(240)] = string.char(198), [string.char(241)] = string.char(199), + [string.char(242)] = string.char(196), [string.char(243)] = string.char(197), + [string.char(244)] = string.char(194), [string.char(245)] = string.char(195), + [string.char(246)] = string.char(192), [string.char(247)] = string.char(193), + [string.char(248)] = string.char(206), [string.char(249)] = string.char(207), + [string.char(250)] = string.char(204), [string.char(251)] = string.char(205), + [string.char(252)] = string.char(202), [string.char(253)] = string.char(203), + [string.char(254)] = string.char(200), [string.char(255)] = string.char(201), +} + + +local blocksize = 64 -- 512 bits + +function hmac_sha1(key, text) + base.assert(base.type(key) == 'string', "key passed to hmac_sha1 should be a string") + base.assert(base.type(text) == 'string', "text passed to hmac_sha1 should be a string") + + if #key > blocksize then + key = sha1_binary(key) + end + + local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. string.rep(string.char(0x36), blocksize - #key) + local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. string.rep(string.char(0x5c), blocksize - #key) + + return sha1(key_xord_with_0x5c .. sha1_binary(key_xord_with_0x36 .. text)) +end + +function hmac_sha1_binary(key, text) + return hex_to_binary(hmac_sha1(key, text)) +end \ No newline at end of file diff --git a/1_1.mi_Lua/slaxdom.lua b/1_1.mi_Lua/slaxdom.lua new file mode 100644 index 0000000..a1c96f7 --- /dev/null +++ b/1_1.mi_Lua/slaxdom.lua @@ -0,0 +1,53 @@ +local SLAXML = require "slaxml" +local string = require "string" +local table = require "table" + +module "slaxdom" + +function SLAXML:dom(xml,opts) + if not opts then opts={} end + local rich = not opts.simple + local push, pop = table.insert, table.remove + local stack = {} + local doc = { type="document", name="#doc", kids={} } + local current = doc + local builder = SLAXML:parser{ + startElement = function(name,nsURI) + local el = { type="element", name=name, kids={}, el=rich and {} or nil, attr={}, nsURI=nsURI, parent=rich and current or nil } + if current==doc then + if doc.root then error(("Encountered element '%s' when the document already has a root '%s' element"):format(name,doc.root.name)) end + doc.root = el + end + push(current.kids,el) + if current.el then push(current.el,el) end + current = el + push(stack,el) + end, + attribute = function(name,value,nsURI) + if not current or current.type~="element" then error(("Encountered an attribute %s=%s but I wasn't inside an element"):format(name,value)) end + local attr = {type='attribute',name=name,nsURI=nsURI,value=value,parent=rich and current or nil} + if rich then current.attr[name] = value end + push(current.attr,attr) + end, + closeElement = function(name) + if current.name~=name or current.type~="element" then error(("Received a close element notification for '%s' but was inside a '%s' %s"):format(name,current.name,current.type)) end + pop(stack) + current = stack[#stack] + end, + text = function(value) + if current.type~='document' then + if current.type~="element" then error(("Received a text notification '%s' but was inside a %s"):format(value,current.type)) end + push(current.kids,{type='text',name='#text',value=value,parent=rich and current or nil}) + end + end, + comment = function(value) + push(current.kids,{type='comment',name='#comment',value=value,parent=rich and current or nil}) + end, + pi = function(name,value) + push(current.kids,{type='pi',name=name,value=value,parent=rich and current or nil}) + end + } + builder:parse(xml,opts) + return doc +end +return SLAXML diff --git a/1_1.mi_Lua/slaxml.lua b/1_1.mi_Lua/slaxml.lua new file mode 100644 index 0000000..7bc8c27 --- /dev/null +++ b/1_1.mi_Lua/slaxml.lua @@ -0,0 +1,221 @@ +local string = require "string" +local table = require "table" +local base = _G + +module "slaxml" + +local SLAXML = { + VERSION = "0.5.1", + _call = { + pi = function(target,content) + print(string.format("",target,content)) + end, + comment = function(content) + print(string.format("",content)) + end, + startElement = function(name,nsURI) + print(string.format("<%s%s>",name,nsURI and (" ("..nsURI..")") or "")) + end, + attribute = function(name,value,nsURI) + print(string.format(" %s=%q%s",name,value,nsURI and (" ("..nsURI..")") or "")) + end, + text = function(text) + print(string.format(" text: %q",text)) + end, + closeElement = function(name,nsURI) + print(string.format("",name)) + end, + } +} + +function SLAXML:parser(callbacks) + return { _call=callbacks or self._call, parse=SLAXML.parse } +end + +function SLAXML:parse(xml,options) + if not options then options = { stripWhitespace=false } end + + -- Cache references for maximum speed + local find, sub, gsub, char, push, pop = string.find, string.sub, string.gsub, string.char, table.insert, table.remove + local first, last, match1, match2, match3, pos2, nsURI + local pos = 1 + local state = "text" + local textStart = 1 + local currentElement={} + local currentAttributes={} + local currentAttributeCt + local nsStack = {} + + local entityMap = { ["lt"]="<", ["gt"]=">", ["amp"]="&", ["quot"]='"', ["apos"]="'" } + local entitySwap = function(orig,n,s) return entityMap[s] or n=="#" and char(s) or orig end + local function unescape(str) return gsub( str, '(&(#?)([%d%a]+);)', entitySwap ) end + + local function finishText() + if first>textStart and self._call.text then + local text = sub(xml,textStart,first-1) + if options.stripWhitespace then + text = gsub(text,'^%s+','') + text = gsub(text,'%s+$','') + if #text==0 then text=nil end + end + if text then self._call.text(unescape(text)) end + end + end + + local function findPI() + first, last, match1, match2 = find( xml, '^<%?([:%a_][:%w_.-]*) ?(.-)%?>', pos ) + if first then + finishText() + if self._call.pi then self._call.pi(match1,match2) end + pos = last+1 + textStart = pos + return true + end + end + + local function findComment() + first, last, match1 = find( xml, '^', pos ) + if first then + finishText() + if self._call.comment then self._call.comment(match1) end + pos = last+1 + textStart = pos + return true + end + end + + local function nsForPrefix(prefix) + for i=#nsStack,1,-1 do if nsStack[i][prefix] then return nsStack[i][prefix] end end + error(("Cannot find namespace for prefix %s"):format(prefix)) + end + + local function startElement() + first, last, match1 = find( xml, '^<([%a_][%w_.-]*)', pos ) + if first then + currentElement[2] = nil + finishText() + pos = last+1 + first,last,match2 = find(xml, '^:([%a_][%w_.-]*)', pos ) + if first then + currentElement[1] = match2 + currentElement[2] = nsForPrefix(match1) + match1 = match2 + pos = last+1 + else + currentElement[1] = match1 + for i=#nsStack,1,-1 do if nsStack[i]['!'] then currentElement[2] = nsStack[i]['!']; break end end + end + currentAttributeCt = 0 + push(nsStack,{}) + return true + end + end + + local function findAttribute() + first, last, match1 = find( xml, '^%s+([:%a_][:%w_.-]*)%s*=%s*', pos ) + if first then + pos2 = last+1 + first, last, match2 = find( xml, '^"([^<"]*)"', pos2 ) -- FIXME: disallow non-entity ampersands + if first then + pos = last+1 + match2 = unescape(match2) + else + first, last, match2 = find( xml, "^'([^<']*)'", pos2 ) -- FIXME: disallow non-entity ampersands + if first then + pos = last+1 + match2 = unescape(match2) + end + end + end + if match1 and match2 then + local currentAttribute = {match1,match2} + local prefix,name = string.match(match1,'^([^:]+):([^:]+)$') + if prefix then + if prefix=='xmlns' then + nsStack[#nsStack][name] = match2 + else + currentAttribute[1] = name + currentAttribute[3] = nsForPrefix(prefix) + end + else + if match1=='xmlns' then + nsStack[#nsStack]['!'] = match2 + currentElement[2] = match2 + end + end + currentAttributeCt = currentAttributeCt + 1 + currentAttributes[currentAttributeCt] = currentAttribute + return true + end + end + + local function findCDATA() + first, last, match1 = find( xml, '^', pos ) + if first then + finishText() + if self._call.text then self._call.text(match1) end + pos = last+1 + textStart = pos + return true + end + end + + local function closeElement() + first, last, match1 = find( xml, '^%s*(/?)>', pos ) + if first then + state = "text" + pos = last+1 + textStart = pos + + if self._call.startElement then self._call.startElement(base.unpack(currentElement)) end + if self._call.attribute then + for i=1,currentAttributeCt do self._call.attribute(base.unpack(currentAttributes[i])) end end + + if match1=="/" then + pop(nsStack) + if self._call.closeElement then self._call.closeElement(base.unpack(currentElement)) end + end + return true + end + end + + local function findElementClose() + first, last, match1, match2 = find( xml, '^', pos ) + if first then + nsURI = nil + for i=#nsStack,1,-1 do if nsStack[i]['!'] then nsURI = nsStack[i]['!']; break end end + else + first, last, match2, match1 = find( xml, '^', pos ) + if first then nsURI = nsForPrefix(match2) end + end + if first then + finishText() + if self._call.closeElement then self._call.closeElement(match1,nsURI) end + pos = last+1 + textStart = pos + pop(nsStack) + return true + end + end + + while pos<#xml do + if state=="text" then + if not (findPI() or findComment() or findCDATA() or findElementClose()) then + if startElement() then + state = "attributes" + else + first, last = find( xml, '^[^<]+', pos ) + pos = (first and last or pos) + 1 + end + end + elseif state=="attributes" then + if not findAttribute() then + if not closeElement() then + error("Was in an element and couldn't find attributes or the close.") + end + end + end + end +end + +return SLAXML diff --git a/1_1.mi_Lua/socket.lua b/1_1.mi_Lua/socket.lua new file mode 100644 index 0000000..211adcd --- /dev/null +++ b/1_1.mi_Lua/socket.lua @@ -0,0 +1,133 @@ +----------------------------------------------------------------------------- +-- LuaSocket helper module +-- Author: Diego Nehab +-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local math = require("math") +local socket = require("socket.core") +module("socket") + +----------------------------------------------------------------------------- +-- Exported auxiliar functions +----------------------------------------------------------------------------- +function connect(address, port, laddress, lport) + local sock, err = socket.tcp() + if not sock then return nil, err end + if laddress then + local res, err = sock:bind(laddress, lport, -1) + if not res then return nil, err end + end + local res, err = sock:connect(address, port) + if not res then return nil, err end + return sock +end + +function bind(host, port, backlog) + local sock, err = socket.tcp() + if not sock then return nil, err end + sock:setoption("reuseaddr", true) + local res, err = sock:bind(host, port) + if not res then return nil, err end + res, err = sock:listen(backlog) + if not res then return nil, err end + return sock +end + +try = newtry() + +function choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) + else return f(opt1, opt2) end + end +end + +----------------------------------------------------------------------------- +-- Socket sources and sinks, conforming to LTN12 +----------------------------------------------------------------------------- +-- create namespaces inside LuaSocket namespace +sourcet = {} +sinkt = {} + +BLOCKSIZE = 2048 + +sinkt["close-when-done"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then + sock:close() + return 1 + else return sock:send(chunk) end + end + }) +end + +sinkt["keep-open"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if chunk then return sock:send(chunk) + else return 1 end + end + }) +end + +sinkt["default"] = sinkt["keep-open"] + +sink = choose(sinkt) + +sourcet["by-length"] = function(sock, length) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if length <= 0 then return nil end + local size = math.min(socket.BLOCKSIZE, length) + local chunk, err = sock:receive(size) + if err then return nil, err end + length = length - string.len(chunk) + return chunk + end + }) +end + +sourcet["until-closed"] = function(sock) + local done + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if done then return nil end + local chunk, err, partial = sock:receive(socket.BLOCKSIZE) + if not err then return chunk + elseif err == "closed" then + sock:close() + done = 1 + return partial + else return nil, err end + end + }) +end + + +sourcet["default"] = sourcet["until-closed"] + +source = choose(sourcet) + diff --git a/1_1.mi_Lua/socket.so.2.0.2 b/1_1.mi_Lua/socket.so.2.0.2 new file mode 100644 index 0000000..f27b836 Binary files /dev/null and b/1_1.mi_Lua/socket.so.2.0.2 differ diff --git a/1_1.mi_Lua/socket/ftp.lua b/1_1.mi_Lua/socket/ftp.lua new file mode 100644 index 0000000..598f65d --- /dev/null +++ b/1_1.mi_Lua/socket/ftp.lua @@ -0,0 +1,281 @@ +----------------------------------------------------------------------------- +-- FTP support for the Lua language +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local table = require("table") +local string = require("string") +local math = require("math") +local socket = require("socket") +local url = require("socket.url") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +module("socket.ftp") + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout in seconds before the program gives up on a connection +TIMEOUT = 60 +-- default port for ftp service +PORT = 21 +-- this is the default anonymous password. used when no password is +-- provided in url. should be changed to your e-mail. +USER = "ftp" +PASSWORD = "anonymous@anonymous.org" + +----------------------------------------------------------------------------- +-- Low level FTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function open(server, port, create) + local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create)) + local f = base.setmetatable({ tp = tp }, metat) + -- make sure everything gets closed in an exception + f.try = socket.newtry(function() f:close() end) + return f +end + +function metat.__index:portconnect() + self.try(self.server:settimeout(TIMEOUT)) + self.data = self.try(self.server:accept()) + self.try(self.data:settimeout(TIMEOUT)) +end + +function metat.__index:pasvconnect() + self.data = self.try(socket.tcp()) + self.try(self.data:settimeout(TIMEOUT)) + self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) +end + +function metat.__index:login(user, password) + self.try(self.tp:command("user", user or USER)) + local code, reply = self.try(self.tp:check{"2..", 331}) + if code == 331 then + self.try(self.tp:command("pass", password or PASSWORD)) + self.try(self.tp:check("2..")) + end + return 1 +end + +function metat.__index:pasv() + self.try(self.tp:command("pasv")) + local code, reply = self.try(self.tp:check("2..")) + local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) + self.try(a and b and c and d and p1 and p2, reply) + self.pasvt = { + ip = string.format("%d.%d.%d.%d", a, b, c, d), + port = p1*256 + p2 + } + if self.server then + self.server:close() + self.server = nil + end + return self.pasvt.ip, self.pasvt.port +end + +function metat.__index:port(ip, port) + self.pasvt = nil + if not ip then + ip, port = self.try(self.tp:getcontrol():getsockname()) + self.server = self.try(socket.bind(ip, 0)) + ip, port = self.try(self.server:getsockname()) + self.try(self.server:settimeout(TIMEOUT)) + end + local pl = math.mod(port, 256) + local ph = (port - pl)/256 + local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") + self.try(self.tp:command("port", arg)) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:send(sendt) + self.try(self.pasvt or self.server, "need port or pasv first") + -- if there is a pasvt table, we already sent a PASV command + -- we just get the data connection into self.data + if self.pasvt then self:pasvconnect() end + -- get the transfer argument and command + local argument = sendt.argument or + url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = sendt.command or "stor" + -- send the transfer command and check the reply + self.try(self.tp:command(command, argument)) + local code, reply = self.try(self.tp:check{"2..", "1.."}) + -- if there is not a a pasvt table, then there is a server + -- and we already sent a PORT command + if not self.pasvt then self:portconnect() end + -- get the sink, source and step for the transfer + local step = sendt.step or ltn12.pump.step + local readt = {self.tp.c} + local checkstep = function(src, snk) + -- check status in control connection while downloading + local readyt = socket.select(readt, nil, 0) + if readyt[tp] then code = self.try(self.tp:check("2..")) end + return step(src, snk) + end + local sink = socket.sink("close-when-done", self.data) + -- transfer all data and check error + self.try(ltn12.pump.all(sendt.source, sink, checkstep)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + -- done with data connection + self.data:close() + -- find out how many bytes were sent + local sent = socket.skip(1, self.data:getstats()) + self.data = nil + return sent +end + +function metat.__index:receive(recvt) + self.try(self.pasvt or self.server, "need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument = recvt.argument or + url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = recvt.command or "retr" + self.try(self.tp:command(command, argument)) + local code = self.try(self.tp:check{"1..", "2.."}) + if not self.pasvt then self:portconnect() end + local source = socket.source("until-closed", self.data) + local step = recvt.step or ltn12.pump.step + self.try(ltn12.pump.all(source, recvt.sink, step)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + self.data:close() + self.data = nil + return 1 +end + +function metat.__index:cwd(dir) + self.try(self.tp:command("cwd", dir)) + self.try(self.tp:check(250)) + return 1 +end + +function metat.__index:type(type) + self.try(self.tp:command("type", type)) + self.try(self.tp:check(200)) + return 1 +end + +function metat.__index:greet() + local code = self.try(self.tp:check{"1..", "2.."}) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + return 1 +end + +function metat.__index:quit() + self.try(self.tp:command("quit")) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:close() + if self.data then self.data:close() end + if self.server then self.server:close() end + return self.tp:close() +end + +----------------------------------------------------------------------------- +-- High level FTP API +----------------------------------------------------------------------------- +local function override(t) + if t.url then + local u = url.parse(t.url) + for i,v in base.pairs(t) do + u[i] = v + end + return u + else return t end +end + +local function tput(putt) + putt = override(putt) + socket.try(putt.host, "missing hostname") + local f = open(putt.host, putt.port, putt.create) + f:greet() + f:login(putt.user, putt.password) + if putt.type then f:type(putt.type) end + f:pasv() + local sent = f:send(putt) + f:quit() + f:close() + return sent +end + +local default = { + path = "/", + scheme = "ftp" +} + +local function parse(u) + local t = socket.try(url.parse(u, default)) + socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") + socket.try(t.host, "missing hostname") + local pat = "^type=(.)$" + if t.params then + t.type = socket.skip(2, string.find(t.params, pat)) + socket.try(t.type == "a" or t.type == "i", + "invalid type '" .. t.type .. "'") + end + return t +end + +local function sput(u, body) + local putt = parse(u) + putt.source = ltn12.source.string(body) + return tput(putt) +end + +put = socket.protect(function(putt, body) + if base.type(putt) == "string" then return sput(putt, body) + else return tput(putt) end +end) + +local function tget(gett) + gett = override(gett) + socket.try(gett.host, "missing hostname") + local f = open(gett.host, gett.port, gett.create) + f:greet() + f:login(gett.user, gett.password) + if gett.type then f:type(gett.type) end + f:pasv() + f:receive(gett) + f:quit() + return f:close() +end + +local function sget(u) + local gett = parse(u) + local t = {} + gett.sink = ltn12.sink.table(t) + tget(gett) + return table.concat(t) +end + +command = socket.protect(function(cmdt) + cmdt = override(cmdt) + socket.try(cmdt.host, "missing hostname") + socket.try(cmdt.command, "missing command") + local f = open(cmdt.host, cmdt.port, cmdt.create) + f:greet() + f:login(cmdt.user, cmdt.password) + f.try(f.tp:command(cmdt.command, cmdt.argument)) + if cmdt.check then f.try(f.tp:check(cmdt.check)) end + f:quit() + return f:close() +end) + +get = socket.protect(function(gett) + if base.type(gett) == "string" then return sget(gett) + else return tget(gett) end +end) + diff --git a/1_1.mi_Lua/socket/http.lua b/1_1.mi_Lua/socket/http.lua new file mode 100644 index 0000000..ad8db1e --- /dev/null +++ b/1_1.mi_Lua/socket/http.lua @@ -0,0 +1,350 @@ +----------------------------------------------------------------------------- +-- HTTP/1.1 client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: http.lua,v 1.71 2007/10/13 23:55:20 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +------------------------------------------------------------------------------- +local socket = require("socket") +local url = require("socket.url") +local ltn12 = require("ltn12") +local mime = require("mime") +local string = require("string") +local base = _G +local table = require("table") +module("socket.http") + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- connection timeout in seconds +TIMEOUT = 60 +-- default port for document retrieval +PORT = 80 +-- user agent field sent in request +USERAGENT = socket._VERSION + +----------------------------------------------------------------------------- +-- Reads MIME headers from a connection, unfolding where needed +----------------------------------------------------------------------------- +local function receiveheaders(sock, headers) + local line, name, value, err + headers = headers or {} + -- get first line + line, err = sock:receive() + if err then return nil, err end + -- headers go until a blank line is found + while line ~= "" do + -- get field-name and value + name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) + if not (name and value) then return nil, "malformed reponse headers" end + name = string.lower(name) + -- get next line (value might be folded) + line, err = sock:receive() + if err then return nil, err end + -- unfold any folded values + while string.find(line, "^%s") do + value = value .. line + line = sock:receive() + if err then return nil, err end + end + -- save pair in table + if headers[name] then headers[name] = headers[name] .. ", " .. value + else headers[name] = value end + end + return headers +end + +----------------------------------------------------------------------------- +-- Extra sources and sinks +----------------------------------------------------------------------------- +socket.sourcet["http-chunked"] = function(sock, headers) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + -- get chunk size, skip extention + local line, err = sock:receive() + if err then return nil, err end + local size = base.tonumber(string.gsub(line, ";.*", ""), 16) + if not size then return nil, "invalid chunk size" end + -- was it the last chunk? + if size > 0 then + -- if not, get chunk and skip terminating CRLF + local chunk, err, part = sock:receive(size) + if chunk then sock:receive() end + return chunk, err + else + -- if it was, read trailers into headers table + headers, err = receiveheaders(sock, headers) + if not headers then return nil, err end + end + end + }) +end + +socket.sinkt["http-chunked"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then return sock:send("0\r\n\r\n") end + local size = string.format("%X\r\n", string.len(chunk)) + return sock:send(size .. chunk .. "\r\n") + end + }) +end + +----------------------------------------------------------------------------- +-- Low level HTTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function open(host, port, create) + -- create socket with user connect function, or with default + local c = socket.try((create or socket.tcp)()) + local h = base.setmetatable({ c = c }, metat) + -- create finalized try + h.try = socket.newtry(function() h:close() end) + -- set timeout before connecting + h.try(c:settimeout(TIMEOUT)) + h.try(c:connect(host, port or PORT)) + -- here everything worked + return h +end + +function metat.__index:sendrequestline(method, uri) + local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) + return self.try(self.c:send(reqline)) +end + +function metat.__index:sendheaders(headers) + local h = "\r\n" + for i, v in base.pairs(headers) do + h = i .. ": " .. v .. "\r\n" .. h + end + self.try(self.c:send(h)) + return 1 +end + +function metat.__index:sendbody(headers, source, step) + source = source or ltn12.source.empty() + step = step or ltn12.pump.step + -- if we don't know the size in advance, send chunked and hope for the best + local mode = "http-chunked" + if headers["content-length"] then mode = "keep-open" end + return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) +end + +function metat.__index:receivestatusline() + local status = self.try(self.c:receive(5)) + -- identify HTTP/0.9 responses, which do not contain a status line + -- this is just a heuristic, but is what the RFC recommends + if status ~= "HTTP/" then return nil, status end + -- otherwise proceed reading a status line + status = self.try(self.c:receive("*l", status)) + local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) + return self.try(base.tonumber(code), status) +end + +function metat.__index:receiveheaders() + return self.try(receiveheaders(self.c)) +end + +function metat.__index:receivebody(headers, sink, step) + sink = sink or ltn12.sink.null() + step = step or ltn12.pump.step + local length = base.tonumber(headers["content-length"]) + local t = headers["transfer-encoding"] -- shortcut + local mode = "default" -- connection close + if t and t ~= "identity" then mode = "http-chunked" + elseif base.tonumber(headers["content-length"]) then mode = "by-length" end + return self.try(ltn12.pump.all(socket.source(mode, self.c, length), + sink, step)) +end + +function metat.__index:receive09body(status, sink, step) + local source = ltn12.source.rewind(socket.source("until-closed", self.c)) + source(status) + return self.try(ltn12.pump.all(source, sink, step)) +end + +function metat.__index:close() + return self.c:close() +end + +----------------------------------------------------------------------------- +-- High level HTTP API +----------------------------------------------------------------------------- +local function adjusturi(reqt) + local u = reqt + -- if there is a proxy, we need the full url. otherwise, just a part. + if not reqt.proxy and not PROXY then + u = { + path = socket.try(reqt.path, "invalid path 'nil'"), + params = reqt.params, + query = reqt.query, + fragment = reqt.fragment + } + end + return url.build(u) +end + +local function adjustproxy(reqt) + local proxy = reqt.proxy or PROXY + if proxy then + proxy = url.parse(proxy) + return proxy.host, proxy.port or 3128 + else + return reqt.host, reqt.port + end +end + +local function adjustheaders(reqt) + -- default headers + local lower = { + ["user-agent"] = USERAGENT, + ["host"] = reqt.host, + ["connection"] = "close, TE", + ["te"] = "trailers" + } + -- if we have authentication information, pass it along + if reqt.user and reqt.password then + lower["authorization"] = + "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password)) + end + -- override with user headers + for i,v in base.pairs(reqt.headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +-- default url parts +local default = { + host = "", + port = PORT, + path ="/", + scheme = "http" +} + +local function adjustrequest(reqt) + -- parse url if provided + local nreqt = reqt.url and url.parse(reqt.url, default) or {} + -- explicit components override url + for i,v in base.pairs(reqt) do nreqt[i] = v end + if nreqt.port == "" then nreqt.port = 80 end + socket.try(nreqt.host and nreqt.host ~= "", + "invalid host '" .. base.tostring(nreqt.host) .. "'") + -- compute uri if user hasn't overriden + nreqt.uri = reqt.uri or adjusturi(nreqt) + -- ajust host and port if there is a proxy + nreqt.host, nreqt.port = adjustproxy(nreqt) + -- adjust headers in request + nreqt.headers = adjustheaders(nreqt) + return nreqt +end + +local function shouldredirect(reqt, code, headers) + return headers.location and + string.gsub(headers.location, "%s", "") ~= "" and + (reqt.redirect ~= false) and + (code == 301 or code == 302) and + (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") + and (not reqt.nredirects or reqt.nredirects < 5) +end + +local function shouldreceivebody(reqt, code) + if reqt.method == "HEAD" then return nil end + if code == 204 or code == 304 then return nil end + if code >= 100 and code < 200 then return nil end + return 1 +end + +-- forward declarations +local trequest, tredirect + +function tredirect(reqt, location) + local result, code, headers, status = trequest { + -- the RFC says the redirect URL has to be absolute, but some + -- servers do not respect that + url = url.absolute(reqt.url, location), + source = reqt.source, + sink = reqt.sink, + headers = reqt.headers, + proxy = reqt.proxy, + nredirects = (reqt.nredirects or 0) + 1, + create = reqt.create + } + -- pass location header back as a hint we redirected + headers = headers or {} + headers.location = headers.location or location + return result, code, headers, status +end + +function trequest(reqt) + -- we loop until we get what we want, or + -- until we are sure there is no way to get it + local nreqt = adjustrequest(reqt) + local h = open(nreqt.host, nreqt.port, nreqt.create) + -- send request line and headers + h:sendrequestline(nreqt.method, nreqt.uri) + h:sendheaders(nreqt.headers) + -- if there is a body, send it + if nreqt.source then + h:sendbody(nreqt.headers, nreqt.source, nreqt.step) + end + local code, status = h:receivestatusline() + -- if it is an HTTP/0.9 server, simply get the body and we are done + if not code then + h:receive09body(status, nreqt.sink, nreqt.step) + return 1, 200 + end + local headers + -- ignore any 100-continue messages + while code == 100 do + headers = h:receiveheaders() + code, status = h:receivestatusline() + end + headers = h:receiveheaders() + -- at this point we should have a honest reply from the server + -- we can't redirect if we already used the source, so we report the error + if shouldredirect(nreqt, code, headers) and not nreqt.source then + h:close() + return tredirect(reqt, headers.location) + end + -- here we are finally done + if shouldreceivebody(nreqt, code) then + h:receivebody(headers, nreqt.sink, nreqt.step) + end + h:close() + return 1, code, headers, status +end + +local function srequest(u, b) + local t = {} + local reqt = { + url = u, + sink = ltn12.sink.table(t) + } + if b then + reqt.source = ltn12.source.string(b) + reqt.headers = { + ["content-length"] = string.len(b), + ["content-type"] = "application/x-www-form-urlencoded" + } + reqt.method = "POST" + end + local code, headers, status = socket.skip(1, trequest(reqt)) + return table.concat(t), code, headers, status +end + +request = socket.protect(function(reqt, body) + if base.type(reqt) == "string" then return srequest(reqt, body) + else return trequest(reqt) end +end) diff --git a/1_1.mi_Lua/socket/smtp.lua b/1_1.mi_Lua/socket/smtp.lua new file mode 100644 index 0000000..8f3cfcf --- /dev/null +++ b/1_1.mi_Lua/socket/smtp.lua @@ -0,0 +1,251 @@ +----------------------------------------------------------------------------- +-- SMTP client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local coroutine = require("coroutine") +local string = require("string") +local math = require("math") +local os = require("os") +local socket = require("socket") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +local mime = require("mime") +module("socket.smtp") + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout for connection +TIMEOUT = 60 +-- default server used to send e-mails +SERVER = "localhost" +-- default port +PORT = 25 +-- domain used in HELO command and default sendmail +-- If we are under a CGI, try to get from environment +DOMAIN = os.getenv("SERVER_NAME") or "localhost" +-- default time zone (means we don't know) +ZONE = "-0000" + +--------------------------------------------------------------------------- +-- Low level SMTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function metat.__index:greet(domain) + self.try(self.tp:check("2..")) + self.try(self.tp:command("EHLO", domain or DOMAIN)) + return socket.skip(1, self.try(self.tp:check("2.."))) +end + +function metat.__index:mail(from) + self.try(self.tp:command("MAIL", "FROM:" .. from)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:rcpt(to) + self.try(self.tp:command("RCPT", "TO:" .. to)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:data(src, step) + self.try(self.tp:command("DATA")) + self.try(self.tp:check("3..")) + self.try(self.tp:source(src, step)) + self.try(self.tp:send("\r\n.\r\n")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:quit() + self.try(self.tp:command("QUIT")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:close() + return self.tp:close() +end + +function metat.__index:login(user, password) + self.try(self.tp:command("AUTH", "LOGIN")) + self.try(self.tp:check("3..")) + self.try(self.tp:command(mime.b64(user))) + self.try(self.tp:check("3..")) + self.try(self.tp:command(mime.b64(password))) + return self.try(self.tp:check("2..")) +end + +function metat.__index:plain(user, password) + local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) + self.try(self.tp:command("AUTH", auth)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:auth(user, password, ext) + if not user or not password then return 1 end + if string.find(ext, "AUTH[^\n]+LOGIN") then + return self:login(user, password) + elseif string.find(ext, "AUTH[^\n]+PLAIN") then + return self:plain(user, password) + else + self.try(nil, "authentication not supported") + end +end + +-- send message or throw an exception +function metat.__index:send(mailt) + self:mail(mailt.from) + if base.type(mailt.rcpt) == "table" then + for i,v in base.ipairs(mailt.rcpt) do + self:rcpt(v) + end + else + self:rcpt(mailt.rcpt) + end + self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) +end + +function open(server, port, create) + local tp = socket.try(tp.connect(server or SERVER, port or PORT, + TIMEOUT, create)) + local s = base.setmetatable({tp = tp}, metat) + -- make sure tp is closed if we get an exception + s.try = socket.newtry(function() + s:close() + end) + return s +end + +-- convert headers to lowercase +local function lower_headers(headers) + local lower = {} + for i,v in base.pairs(headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +--------------------------------------------------------------------------- +-- Multipart message source +----------------------------------------------------------------------------- +-- returns a hopefully unique mime boundary +local seqno = 0 +local function newboundary() + seqno = seqno + 1 + return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), + math.random(0, 99999), seqno) +end + +-- send_message forward declaration +local send_message + +-- yield the headers all at once, it's faster +local function send_headers(headers) + local h = "\r\n" + for i,v in base.pairs(headers) do + h = i .. ': ' .. v .. "\r\n" .. h + end + coroutine.yield(h) +end + +-- yield multipart message body from a multipart message table +local function send_multipart(mesgt) + -- make sure we have our boundary and send headers + local bd = newboundary() + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or 'multipart/mixed' + headers['content-type'] = headers['content-type'] .. + '; boundary="' .. bd .. '"' + send_headers(headers) + -- send preamble + if mesgt.body.preamble then + coroutine.yield(mesgt.body.preamble) + coroutine.yield("\r\n") + end + -- send each part separated by a boundary + for i, m in base.ipairs(mesgt.body) do + coroutine.yield("\r\n--" .. bd .. "\r\n") + send_message(m) + end + -- send last boundary + coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") + -- send epilogue + if mesgt.body.epilogue then + coroutine.yield(mesgt.body.epilogue) + coroutine.yield("\r\n") + end +end + +-- yield message body from a source +local function send_source(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from source + while true do + local chunk, err = mesgt.body() + if err then coroutine.yield(nil, err) + elseif chunk then coroutine.yield(chunk) + else break end + end +end + +-- yield message body from a string +local function send_string(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from string + coroutine.yield(mesgt.body) +end + +-- message source +function send_message(mesgt) + if base.type(mesgt.body) == "table" then send_multipart(mesgt) + elseif base.type(mesgt.body) == "function" then send_source(mesgt) + else send_string(mesgt) end +end + +-- set defaul headers +local function adjust_headers(mesgt) + local lower = lower_headers(mesgt.headers) + lower["date"] = lower["date"] or + os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE) + lower["x-mailer"] = lower["x-mailer"] or socket._VERSION + -- this can't be overriden + lower["mime-version"] = "1.0" + return lower +end + +function message(mesgt) + mesgt.headers = adjust_headers(mesgt) + -- create and return message source + local co = coroutine.create(function() send_message(mesgt) end) + return function() + local ret, a, b = coroutine.resume(co) + if ret then return a, b + else return nil, a end + end +end + +--------------------------------------------------------------------------- +-- High level SMTP API +----------------------------------------------------------------------------- +send = socket.protect(function(mailt) + local s = open(mailt.server, mailt.port, mailt.create) + local ext = s:greet(mailt.domain) + s:auth(mailt.user, mailt.password, ext) + s:send(mailt) + s:quit() + return s:close() +end) diff --git a/1_1.mi_Lua/socket/tp.lua b/1_1.mi_Lua/socket/tp.lua new file mode 100644 index 0000000..0683869 --- /dev/null +++ b/1_1.mi_Lua/socket/tp.lua @@ -0,0 +1,123 @@ +----------------------------------------------------------------------------- +-- Unified SMTP/FTP subsystem +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local socket = require("socket") +local ltn12 = require("ltn12") +module("socket.tp") + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +TIMEOUT = 60 + +----------------------------------------------------------------------------- +-- Implementation +----------------------------------------------------------------------------- +-- gets server reply (works for SMTP and FTP) +local function get_reply(c) + local code, current, sep + local line, err = c:receive() + local reply = line + if err then return nil, err end + code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + if not code then return nil, "invalid server reply" end + if sep == "-" then -- reply is multiline + repeat + line, err = c:receive() + if err then return nil, err end + current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + reply = reply .. "\n" .. line + -- reply ends with same code + until code == current and sep == " " + end + return code, reply +end + +-- metatable for sock object +local metat = { __index = {} } + +function metat.__index:check(ok) + local code, reply = get_reply(self.c) + if not code then return nil, reply end + if base.type(ok) ~= "function" then + if base.type(ok) == "table" then + for i, v in base.ipairs(ok) do + if string.find(code, v) then + return base.tonumber(code), reply + end + end + return nil, reply + else + if string.find(code, ok) then return base.tonumber(code), reply + else return nil, reply end + end + else return ok(base.tonumber(code), reply) end +end + +function metat.__index:command(cmd, arg) + if arg then + return self.c:send(cmd .. " " .. arg.. "\r\n") + else + return self.c:send(cmd .. "\r\n") + end +end + +function metat.__index:sink(snk, pat) + local chunk, err = c:receive(pat) + return snk(chunk, err) +end + +function metat.__index:send(data) + return self.c:send(data) +end + +function metat.__index:receive(pat) + return self.c:receive(pat) +end + +function metat.__index:getfd() + return self.c:getfd() +end + +function metat.__index:dirty() + return self.c:dirty() +end + +function metat.__index:getcontrol() + return self.c +end + +function metat.__index:source(source, step) + local sink = socket.sink("keep-open", self.c) + local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) + return ret, err +end + +-- closes the underlying c +function metat.__index:close() + self.c:close() + return 1 +end + +-- connect with server and return c object +function connect(host, port, timeout, create) + local c, e = (create or socket.tcp)() + if not c then return nil, e end + c:settimeout(timeout or TIMEOUT) + local r, e = c:connect(host, port) + if not r then + c:close() + return nil, e + end + return base.setmetatable({c = c}, metat) +end + diff --git a/1_1.mi_Lua/socket/url.lua b/1_1.mi_Lua/socket/url.lua new file mode 100644 index 0000000..0e31d8a --- /dev/null +++ b/1_1.mi_Lua/socket/url.lua @@ -0,0 +1,297 @@ +----------------------------------------------------------------------------- +-- URI parsing, composition and relative URL resolution +-- LuaSocket toolkit. +-- Author: Diego Nehab +-- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local base = _G +local table = require("table") +module("socket.url") + +----------------------------------------------------------------------------- +-- Module version +----------------------------------------------------------------------------- +_VERSION = "URL 1.0.1" + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function escape(s) + return string.gsub(s, "([^A-Za-z0-9_])", function(c) + return string.format("%%%02x", string.byte(c)) + end) +end + +----------------------------------------------------------------------------- +-- Protects a path segment, to prevent it from interfering with the +-- url parsing. +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +local function make_set(t) + local s = {} + for i,v in base.ipairs(t) do + s[t[i]] = 1 + end + return s +end + +-- these are allowed withing a path segment, along with alphanum +-- other characters must be escaped +local segment_set = make_set { + "-", "_", ".", "!", "~", "*", "'", "(", + ")", ":", "@", "&", "=", "+", "$", ",", +} + +local function protect_segment(s) + return string.gsub(s, "([^A-Za-z0-9_])", function (c) + if segment_set[c] then return c + else return string.format("%%%02x", string.byte(c)) end + end) +end + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function unescape(s) + return string.gsub(s, "%%(%x%x)", function(hex) + return string.char(base.tonumber(hex, 16)) + end) +end + +----------------------------------------------------------------------------- +-- Builds a path from a base path and a relative path +-- Input +-- base_path +-- relative_path +-- Returns +-- corresponding absolute path +----------------------------------------------------------------------------- +local function absolute_path(base_path, relative_path) + if string.sub(relative_path, 1, 1) == "/" then return relative_path end + local path = string.gsub(base_path, "[^/]*$", "") + path = path .. relative_path + path = string.gsub(path, "([^/]*%./)", function (s) + if s ~= "./" then return s else return "" end + end) + path = string.gsub(path, "/%.$", "/") + local reduced + while reduced ~= path do + reduced = path + path = string.gsub(reduced, "([^/]*/%.%./)", function (s) + if s ~= "../../" then return "" else return s end + end) + end + path = string.gsub(reduced, "([^/]*/%.%.)$", function (s) + if s ~= "../.." then return "" else return s end + end) + return path +end + +----------------------------------------------------------------------------- +-- Parses a url and returns a table with all its parts according to RFC 2396 +-- The following grammar describes the names given to the URL parts +-- ::= :///;?# +-- ::= @: +-- ::= [:] +-- :: = {/} +-- Input +-- url: uniform resource locator of request +-- default: table with default values for each field +-- Returns +-- table with the following fields, where RFC naming conventions have +-- been preserved: +-- scheme, authority, userinfo, user, password, host, port, +-- path, params, query, fragment +-- Obs: +-- the leading '/' in {/} is considered part of +----------------------------------------------------------------------------- +function parse(url, default) + -- initialize default parameters + local parsed = {} + for i,v in base.pairs(default or parsed) do parsed[i] = v end + -- empty url is parsed to nil + if not url or url == "" then return nil, "invalid url" end + -- remove whitespace + -- url = string.gsub(url, "%s", "") + -- get fragment + url = string.gsub(url, "#(.*)$", function(f) + parsed.fragment = f + return "" + end) + -- get scheme + url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", + function(s) parsed.scheme = s; return "" end) + -- get authority + url = string.gsub(url, "^//([^/]*)", function(n) + parsed.authority = n + return "" + end) + -- get query stringing + url = string.gsub(url, "%?(.*)", function(q) + parsed.query = q + return "" + end) + -- get params + url = string.gsub(url, "%;(.*)", function(p) + parsed.params = p + return "" + end) + -- path is whatever was left + if url ~= "" then parsed.path = url end + local authority = parsed.authority + if not authority then return parsed end + authority = string.gsub(authority,"^([^@]*)@", + function(u) parsed.userinfo = u; return "" end) + authority = string.gsub(authority, ":([^:]*)$", + function(p) parsed.port = p; return "" end) + if authority ~= "" then parsed.host = authority end + local userinfo = parsed.userinfo + if not userinfo then return parsed end + userinfo = string.gsub(userinfo, ":([^:]*)$", + function(p) parsed.password = p; return "" end) + parsed.user = userinfo + return parsed +end + +----------------------------------------------------------------------------- +-- Rebuilds a parsed URL from its components. +-- Components are protected if any reserved or unallowed characters are found +-- Input +-- parsed: parsed URL, as returned by parse +-- Returns +-- a stringing with the corresponding URL +----------------------------------------------------------------------------- +function build(parsed) + local ppath = parse_path(parsed.path or "") + local url = build_path(ppath) + if parsed.params then url = url .. ";" .. parsed.params end + if parsed.query then url = url .. "?" .. parsed.query end + local authority = parsed.authority + if parsed.host then + authority = parsed.host + if parsed.port then authority = authority .. ":" .. parsed.port end + local userinfo = parsed.userinfo + if parsed.user then + userinfo = parsed.user + if parsed.password then + userinfo = userinfo .. ":" .. parsed.password + end + end + if userinfo then authority = userinfo .. "@" .. authority end + end + if authority then url = "//" .. authority .. url end + if parsed.scheme then url = parsed.scheme .. ":" .. url end + if parsed.fragment then url = url .. "#" .. parsed.fragment end + -- url = string.gsub(url, "%s", "") + return url +end + +----------------------------------------------------------------------------- +-- Builds a absolute URL from a base and a relative URL according to RFC 2396 +-- Input +-- base_url +-- relative_url +-- Returns +-- corresponding absolute url +----------------------------------------------------------------------------- +function absolute(base_url, relative_url) + if base.type(base_url) == "table" then + base_parsed = base_url + base_url = build(base_parsed) + else + base_parsed = parse(base_url) + end + local relative_parsed = parse(relative_url) + if not base_parsed then return relative_url + elseif not relative_parsed then return base_url + elseif relative_parsed.scheme then return relative_url + else + relative_parsed.scheme = base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority = base_parsed.authority + if not relative_parsed.path then + relative_parsed.path = base_parsed.path + if not relative_parsed.params then + relative_parsed.params = base_parsed.params + if not relative_parsed.query then + relative_parsed.query = base_parsed.query + end + end + else + relative_parsed.path = absolute_path(base_parsed.path or "", + relative_parsed.path) + end + end + return build(relative_parsed) + end +end + +----------------------------------------------------------------------------- +-- Breaks a path into its segments, unescaping the segments +-- Input +-- path +-- Returns +-- segment: a table with one entry per segment +----------------------------------------------------------------------------- +function parse_path(path) + local parsed = {} + path = path or "" + --path = string.gsub(path, "%s", "") + string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) + for i = 1, table.getn(parsed) do + parsed[i] = unescape(parsed[i]) + end + if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end + if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end + return parsed +end + +----------------------------------------------------------------------------- +-- Builds a path component from its segments, escaping protected characters. +-- Input +-- parsed: path segments +-- unsafe: if true, segments are not protected before path is built +-- Returns +-- path: corresponding path stringing +----------------------------------------------------------------------------- +function build_path(parsed, unsafe) + local path = "" + local n = table.getn(parsed) + if unsafe then + for i = 1, n-1 do + path = path .. parsed[i] + path = path .. "/" + end + if n > 0 then + path = path .. parsed[n] + if parsed.is_directory then path = path .. "/" end + end + else + for i = 1, n-1 do + path = path .. protect_segment(parsed[i]) + path = path .. "/" + end + if n > 0 then + path = path .. protect_segment(parsed[n]) + if parsed.is_directory then path = path .. "/" end + end + end + if parsed.is_absolute then path = "/" .. path end + return path +end diff --git a/1_1.mi_Lua/ssl.lua b/1_1.mi_Lua/ssl.lua new file mode 100644 index 0000000..18a07b3 --- /dev/null +++ b/1_1.mi_Lua/ssl.lua @@ -0,0 +1,93 @@ +------------------------------------------------------------------------------ +-- LuaSec 0.4 +-- Copyright (C) 2006-2009 Bruno Silvestre +-- +------------------------------------------------------------------------------ + +module("ssl", package.seeall) + +require("ssl.core") +require("ssl.context") + + +_VERSION = "0.4" +_COPYRIGHT = "LuaSec 0.4 - Copyright (C) 2006-2009 Bruno Silvestre\n" .. + "LuaSocket 2.0.2 - Copyright (C) 2004-2007 Diego Nehab" + +-- Export functions +rawconnection = core.rawconnection +rawcontext = context.rawcontext + +-- +-- +-- +local function optexec(func, param, ctx) + if param then + if type(param) == "table" then + return func(ctx, unpack(param)) + else + return func(ctx, param) + end + end + return true +end + +-- +-- +-- +function newcontext(cfg) + local succ, msg, ctx + -- Create the context + ctx, msg = context.create(cfg.protocol) + if not ctx then return nil, msg end + -- Mode + succ, msg = context.setmode(ctx, cfg.mode) + if not succ then return nil, msg end + -- Load the key + if cfg.key then + succ, msg = context.loadkey(ctx, cfg.key, cfg.password) + if not succ then return nil, msg end + end + -- Load the certificate + if cfg.certificate then + succ, msg = context.loadcert(ctx, cfg.certificate) + if not succ then return nil, msg end + end + -- Load the CA certificates + if cfg.cafile or cfg.capath then + succ, msg = context.locations(ctx, cfg.cafile, cfg.capath) + if not succ then return nil, msg end + end + -- Set the verification options + succ, msg = optexec(context.setverify, cfg.verify, ctx) + if not succ then return nil, msg end + -- Set SSL options + succ, msg = optexec(context.setoptions, cfg.options, ctx) + if not succ then return nil, msg end + -- Set the depth for certificate verification + if cfg.depth then + succ, msg = context.setdepth(ctx, cfg.depth) + if not succ then return nil, msg end + end + return ctx +end + +-- +-- +-- +function wrap(sock, cfg) + local ctx, msg + if type(cfg) == "table" then + ctx, msg = newcontext(cfg) + if not ctx then return nil, msg end + else + ctx = cfg + end + local s, msg = core.create(ctx) + if s then + core.setfd(s, sock:getfd()) + sock:setfd(core.invalidfd) + return s + end + return nil, msg +end diff --git a/1_1.mi_Lua/ssl.so b/1_1.mi_Lua/ssl.so new file mode 100644 index 0000000..ffc0cc6 Binary files /dev/null and b/1_1.mi_Lua/ssl.so differ diff --git a/1_1.mi_Lua/ssl/https.lua b/1_1.mi_Lua/ssl/https.lua new file mode 100644 index 0000000..19c19fe --- /dev/null +++ b/1_1.mi_Lua/ssl/https.lua @@ -0,0 +1,138 @@ +---------------------------------------------------------------------------- +-- LuaSec 0.4 +-- Copyright (C) 2009 PUC-Rio +-- +-- Author: Pablo Musa +-- Author: Tomas Guisasola +--------------------------------------------------------------------------- + +local socket = require("socket") +local ssl = require("ssl") +local ltn12 = require("ltn12") +local http = require("socket.http") +local url = require("socket.url") + +local table = require("table") +local string = require("string") + +local try = socket.try +local type = type +local pairs = pairs +local getmetatable = getmetatable + +module("ssl.https") + +_VERSION = "0.4" +_COPYRIGHT = "LuaSec 0.4 - Copyright (C) 2009 PUC-Rio" + +-- Default settings +PORT = 443 + +local cfg = { + protocol = "tlsv1", + options = "all", + verify = "none", +} + +-------------------------------------------------------------------- +-- Auxiliar Functions +-------------------------------------------------------------------- + +-- Insert default HTTPS port. +local function default_https_port(u) + return url.build(url.parse(u, {port = PORT})) +end + +-- Convert an URL to a table according to Luasocket needs. +local function urlstring_totable(url, body, result_table) + url = { + url = default_https_port(url), + method = body and "POST" or "GET", + sink = ltn12.sink.table(result_table) + } + if body then + url.source = ltn12.source.string(body) + url.headers = { + ["content-length"] = #body, + ["content-type"] = "application/x-www-form-urlencoded", + } + end + return url +end + +-- Forward calls to the real connection object. +local function reg(conn) + local mt = getmetatable(conn.sock).__index + for name, method in pairs(mt) do + if type(method) == "function" then + conn[name] = function (self, ...) + return method(self.sock, ...) + end + end + end +end + +-- Return a function which performs the SSL/TLS connection. +local function tcp(params) + params = params or {} + -- Default settings + for k, v in pairs(cfg) do + params[k] = params[k] or v + end + -- Force client mode + params.mode = "client" + -- 'create' function for LuaSocket + return function () + local conn = {} + conn.sock = try(socket.tcp()) + local st = getmetatable(conn.sock).__index.settimeout + function conn:settimeout(...) + return st(self.sock, ...) + end + -- Replace TCP's connection function + function conn:connect(host, port) + try(self.sock:connect(host, port)) + self.sock = try(ssl.wrap(self.sock, params)) + try(self.sock:dohandshake()) + reg(self, getmetatable(self.sock)) + return 1 + end + return conn + end +end + +-------------------------------------------------------------------- +-- Main Function +-------------------------------------------------------------------- + +-- Make a HTTP request over secure connection. This function receives +-- the same parameters of LuaSocket's HTTP module (except 'proxy' and +-- 'redirect') plus LuaSec parameters. +-- +-- @param url mandatory (string or table) +-- @param body optional (string) +-- @return (string if url == string or 1), code, headers, status +-- +function request(url, body) + local result_table = {} + local stringrequest = type(url) == "string" + if stringrequest then + url = urlstring_totable(url, body, result_table) + else + url.url = default_https_port(url.url) + end + if http.PROXY or url.proxy then + return nil, "proxy not supported" + elseif url.redirect then + return nil, "redirect not supported" + elseif url.create then + return nil, "create function not permitted" + end + -- New 'create' function to establish a secure connection + url.create = tcp(url) + local res, code, headers, status = http.request(url) + if res and stringrequest then + return table.concat(result_table), code, headers, status + end + return res, code, headers, status +end diff --git a/1_1.mi_Lua/sysapi/miqos.lua b/1_1.mi_Lua/sysapi/miqos.lua new file mode 100644 index 0000000..749c388 --- /dev/null +++ b/1_1.mi_Lua/sysapi/miqos.lua @@ -0,0 +1,82 @@ +#!/usr/bin/lua + + +-- local px = require "Posix" +local socket= require 'socket' +local json= require 'json' + +local cfg_host='127.0.0.1' +local cfg_port='1035' + +module("sysapi.miqos", package.seeall) + +function cmd(action) + local con=assert(socket.connect(cfg_host,cfg_port)) + local s,err = con:send(action..'\n') + -- logger(7,'send act: ' .. action) + if err then + logger(7, 'establish conn failed.') + return json.decode('{"status":-1}') + end + + local data='' + while true do + local line, err = con:receive() + if not line then + if err == 'closed' then + con:close() + return json.decode(data) + else + logger(7,'receive err: ' .. err) + con:close() + return json.decode('{"status":-1}') + end + else + --logger(7,'receive line: ' .. line) + data = data .. line + end + end + con:close() + return json.decode('{"status":-1}') +end + +--[[ +px.openlog("miqos","np",LOG_USER) + +function logger(loglevel,msg) + px.syslog(loglevel,msg) +end + +function print_r(root,ind) + local indent=" " .. ind + + for k,v in pairs(root) do + if(type(v) == "table") then + print(indent .. k .. " = {") + print_r(v,indent) + print(indent .. "}") + else + print(indent .. k .. "=" .. v) + end + end + +end + +function main() + local data='' + for i,v in ipairs(arg) do + data = data .. ' ' .. v + end + + local str=act(data) + if str then + print("{") + print_r(json.decode(str),"") + print("}") + end +end + +main() +--]] + + diff --git a/1_1.mi_Lua/tags b/1_1.mi_Lua/tags new file mode 100644 index 0000000..a2afc27 --- /dev/null +++ b/1_1.mi_Lua/tags @@ -0,0 +1,1972 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ +!_TAG_PROGRAM_NAME Exuberant Ctags // +!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ +!_TAG_PROGRAM_VERSION 5.9~svn20110310 // +"Failed to execute " .. (type(c.target) ./luci/dispatcher.lua /^ "Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") ..$/;" f +ADD ./sha1.lua /^local function ADD(first, ...)$/;" f +AND ./sha1.lua /^local function AND(a, b)$/;" f +AbstractSection.__init__ ./luci/cbi.lua /^function AbstractSection.__init__(self, map, sectiontype, ...)$/;" f +AbstractSection.add_dynamic ./luci/cbi.lua /^function AbstractSection.add_dynamic(self, field, optional)$/;" f +AbstractSection.cfgvalue ./luci/cbi.lua /^function AbstractSection.cfgvalue(self, section)$/;" f +AbstractSection.create ./luci/cbi.lua /^function AbstractSection.create(self, section)$/;" f +AbstractSection.has_tabs ./luci/cbi.lua /^function AbstractSection.has_tabs(self)$/;" f +AbstractSection.option ./luci/cbi.lua /^function AbstractSection.option(self, class, option, ...)$/;" f +AbstractSection.parse_dynamic ./luci/cbi.lua /^function AbstractSection.parse_dynamic(self, section)$/;" f +AbstractSection.parse_optionals ./luci/cbi.lua /^function AbstractSection.parse_optionals(self, section)$/;" f +AbstractSection.push_events ./luci/cbi.lua /^function AbstractSection.push_events(self)$/;" f +AbstractSection.remove ./luci/cbi.lua /^function AbstractSection.remove(self, section)$/;" f +AbstractSection.render_tab ./luci/cbi.lua /^function AbstractSection.render_tab(self, tab, ...)$/;" f +AbstractSection.tab ./luci/cbi.lua /^function AbstractSection.tab(self, tab, title, desc)$/;" f +AbstractSection.taboption ./luci/cbi.lua /^function AbstractSection.taboption(self, tab, ...)$/;" f +AbstractValue.__init__ ./luci/cbi.lua /^function AbstractValue.__init__(self, map, section, option, ...)$/;" f +AbstractValue.add_error ./luci/cbi.lua /^function AbstractValue.add_error(self, section, type, msg)$/;" f +AbstractValue.additional ./luci/cbi.lua /^function AbstractValue.additional(self, value)$/;" f +AbstractValue.cbid ./luci/cbi.lua /^function AbstractValue.cbid(self, section)$/;" f +AbstractValue.cfgvalue ./luci/cbi.lua /^function AbstractValue.cfgvalue(self, section)$/;" f +AbstractValue.depends ./luci/cbi.lua /^function AbstractValue.depends(self, field, value)$/;" f +AbstractValue.formcreated ./luci/cbi.lua /^function AbstractValue.formcreated(self, section)$/;" f +AbstractValue.formvalue ./luci/cbi.lua /^function AbstractValue.formvalue(self, section)$/;" f +AbstractValue.mandatory ./luci/cbi.lua /^function AbstractValue.mandatory(self, value)$/;" f +AbstractValue.parse ./luci/cbi.lua /^function AbstractValue.parse(self, section, novld)$/;" f +AbstractValue.prepare ./luci/cbi.lua /^function AbstractValue.prepare(self)$/;" f +AbstractValue.remove ./luci/cbi.lua /^function AbstractValue.remove(self, section)$/;" f +AbstractValue.render ./luci/cbi.lua /^function AbstractValue.render(self, s, scope)$/;" f +AbstractValue.validate ./luci/cbi.lua /^function AbstractValue.validate(self, value)$/;" f +AbstractValue.write ./luci/cbi.lua /^function AbstractValue.write(self, section, value)$/;" f +ActiveDecoder.__init__ ./luci/json.lua /^function ActiveDecoder.__init__(self, source, customnull)$/;" f +ActiveDecoder.fetch ./luci/json.lua /^function ActiveDecoder.fetch(self)$/;" f +ActiveDecoder.get ./luci/json.lua /^function ActiveDecoder.get(self)$/;" f +Button.__init__ ./luci/cbi.lua /^function Button.__init__(self, ...)$/;" f +COPY ./sha1.lua /^local function COPY(old)$/;" f +Compound.__init__ ./luci/cbi.lua /^function Compound.__init__(self, ...)$/;" f +Compound.parse ./luci/cbi.lua /^function Compound.parse(self, ...)$/;" f +Compound.populate_delegator ./luci/cbi.lua /^function Compound.populate_delegator(self, delegator)$/;" f +Cursor._affected ./luci/model/uci.lua /^function Cursor._affected(self, configlist)$/;" f +Cursor.apply ./luci/model/uci.lua /^function Cursor.apply(self, configlist, command)$/;" f +Cursor.delete_all ./luci/model/uci.lua /^function Cursor.delete_all(self, config, stype, comparator)$/;" f +Cursor.get_bool ./luci/model/uci.lua /^function Cursor.get_bool(self, ...)$/;" f +Cursor.get_first ./luci/model/uci.lua /^function Cursor.get_first(self, conf, stype, opt, def)$/;" f +Cursor.get_list ./luci/model/uci.lua /^function Cursor.get_list(self, config, section, option)$/;" f +Cursor.load ./luci/model/uci.lua /^function Cursor.load(self, ...)$/;" f +Cursor.section ./luci/model/uci.lua /^function Cursor.section(self, config, type, name, values)$/;" f +Cursor.set_list ./luci/model/uci.lua /^function Cursor.set_list(self, config, section, option, value)$/;" f +Cursor.substate ./luci/model/uci.lua /^function Cursor.substate(self)$/;" f +Cursor.tset ./luci/model/uci.lua /^function Cursor.tset(self, config, section, values)$/;" f +Cursor.unload ./luci/model/uci.lua /^function Cursor.unload(self, ...)$/;" f +Decoder.__init__ ./luci/json.lua /^function Decoder.__init__(self, customnull)$/;" f +Decoder.dispatch ./luci/json.lua /^function Decoder.dispatch(self, chunk, src_err, strict)$/;" f +Decoder.fetch ./luci/json.lua /^function Decoder.fetch(self)$/;" f +Decoder.fetch_atleast ./luci/json.lua /^function Decoder.fetch_atleast(self, chunk, bytes)$/;" f +Decoder.fetch_until ./luci/json.lua /^function Decoder.fetch_until(self, chunk, pattern)$/;" f +Decoder.get ./luci/json.lua /^function Decoder.get(self)$/;" f +Decoder.parse_array ./luci/json.lua /^function Decoder.parse_array(self, chunk)$/;" f +Decoder.parse_delimiter ./luci/json.lua /^function Decoder.parse_delimiter(self, chunk, delimiter)$/;" f +Decoder.parse_escape ./luci/json.lua /^function Decoder.parse_escape(self, chunk)$/;" f +Decoder.parse_false ./luci/json.lua /^function Decoder.parse_false(self, chunk)$/;" f +Decoder.parse_literal ./luci/json.lua /^function Decoder.parse_literal(self, chunk, literal, value)$/;" f +Decoder.parse_null ./luci/json.lua /^function Decoder.parse_null(self, chunk)$/;" f +Decoder.parse_number ./luci/json.lua /^function Decoder.parse_number(self, chunk)$/;" f +Decoder.parse_object ./luci/json.lua /^function Decoder.parse_object(self, chunk)$/;" f +Decoder.parse_space ./luci/json.lua /^function Decoder.parse_space(self, chunk)$/;" f +Decoder.parse_string ./luci/json.lua /^function Decoder.parse_string(self, chunk)$/;" f +Decoder.parse_true ./luci/json.lua /^function Decoder.parse_true(self, chunk)$/;" f +Decoder.sink ./luci/json.lua /^function Decoder.sink(self)$/;" f +Delegator.__init__ ./luci/cbi.lua /^function Delegator.__init__(self, ...)$/;" f +Delegator.add ./luci/cbi.lua /^function Delegator.add(self, name, node)$/;" f +Delegator.get ./luci/cbi.lua /^function Delegator.get(self, name)$/;" f +Delegator.get_active ./luci/cbi.lua /^function Delegator.get_active(self)$/;" f +Delegator.get_chain ./luci/cbi.lua /^function Delegator.get_chain(self)$/;" f +Delegator.get_next ./luci/cbi.lua /^function Delegator.get_next(self, state)$/;" f +Delegator.get_prev ./luci/cbi.lua /^function Delegator.get_prev(self, state)$/;" f +Delegator.insert_after ./luci/cbi.lua /^function Delegator.insert_after(self, name, after)$/;" f +Delegator.parse ./luci/cbi.lua /^function Delegator.parse(self, ...)$/;" f +Delegator.set ./luci/cbi.lua /^function Delegator.set(self, name, node)$/;" f +Delegator.set_route ./luci/cbi.lua /^function Delegator.set_route(self, ...)$/;" f +DoExec ./xiaoqiang/util/XQMitvUtil.lua /^function DoExec(cmd)$/;" f +DummyValue.__init__ ./luci/cbi.lua /^function DummyValue.__init__(self, ...)$/;" f +DummyValue.cfgvalue ./luci/cbi.lua /^function DummyValue.cfgvalue(self, section)$/;" f +DummyValue.parse ./luci/cbi.lua /^function DummyValue.parse(self)$/;" f +DynamicList.__init__ ./luci/cbi.lua /^function DynamicList.__init__(self, ...)$/;" f +DynamicList.cfgvalue ./luci/cbi.lua /^function DynamicList.cfgvalue(self, section)$/;" f +DynamicList.formvalue ./luci/cbi.lua /^function DynamicList.formvalue(self, section)$/;" f +DynamicList.reset_values ./luci/cbi.lua /^function DynamicList.reset_values(self)$/;" f +DynamicList.value ./luci/cbi.lua /^function DynamicList.value(self, key, val)$/;" f +DynamicList.write ./luci/cbi.lua /^function DynamicList.write(self, section, value)$/;" f +Encoder.__init__ ./luci/json.lua /^function Encoder.__init__(self, data, buffersize, fastescape)$/;" f +Encoder.dispatch ./luci/json.lua /^function Encoder.dispatch(self, data, start)$/;" f +Encoder.parse_bool ./luci/json.lua /^function Encoder.parse_bool(self, obj)$/;" f +Encoder.parse_iter ./luci/json.lua /^function Encoder.parse_iter(self, obj)$/;" f +Encoder.parse_nil ./luci/json.lua /^function Encoder.parse_nil(self)$/;" f +Encoder.parse_number ./luci/json.lua /^function Encoder.parse_number(self, obj)$/;" f +Encoder.parse_string ./luci/json.lua /^function Encoder.parse_string(self, obj)$/;" f +Encoder.put ./luci/json.lua /^function Encoder.put(self, chunk)$/;" f +Encoder.source ./luci/json.lua /^function Encoder.source(self)$/;" f +FileBrowser.__init__ ./luci/cbi.lua /^function FileBrowser.__init__(self, ...)$/;" f +FileUpload.__init__ ./luci/cbi.lua /^function FileUpload.__init__(self, ...)$/;" f +FileUpload.cfgvalue ./luci/cbi.lua /^function FileUpload.cfgvalue(self, section)$/;" f +FileUpload.formcreated ./luci/cbi.lua /^function FileUpload.formcreated(self, section)$/;" f +FileUpload.formvalue ./luci/cbi.lua /^function FileUpload.formvalue(self, section)$/;" f +FileUpload.remove ./luci/cbi.lua /^function FileUpload.remove(self, section)$/;" f +Flag.__init__ ./luci/cbi.lua /^function Flag.__init__(self, ...)$/;" f +Flag.cfgvalue ./luci/cbi.lua /^function Flag.cfgvalue(self, section)$/;" f +Flag.parse ./luci/cbi.lua /^function Flag.parse(self, section)$/;" f +Form.__init__ ./luci/cbi.lua /^function Form.__init__(self, ...)$/;" f +Hex ./luci/ip.lua /^function Hex( hex, prefix, family, swap )$/;" f +IPv4 ./luci/ip.lua /^function IPv4(address, netmask)$/;" f +IPv6 ./luci/ip.lua /^function IPv6(address, netmask)$/;" f +IptParser.__init__ ./luci/sys/iptparser.lua /^function IptParser.__init__( self, family )$/;" f +IptParser._match_options ./luci/sys/iptparser.lua /^function IptParser._match_options( self, o1, o2 )$/;" f +IptParser._parse_addr ./luci/sys/iptparser.lua /^function IptParser._parse_addr( self, addr )$/;" f +IptParser._parse_rules ./luci/sys/iptparser.lua /^function IptParser._parse_rules( self )$/;" f +IptParser.chain ./luci/sys/iptparser.lua /^function IptParser.chain( self, table, chain )$/;" f +IptParser.chains ./luci/sys/iptparser.lua /^function IptParser.chains( self, table )$/;" f +IptParser.find ./luci/sys/iptparser.lua /^function IptParser.find( self, args )$/;" f +IptParser.is_custom_target ./luci/sys/iptparser.lua /^function IptParser.is_custom_target( self, target )$/;" f +IptParser.resync ./luci/sys/iptparser.lua /^function IptParser.resync( self )$/;" f +IptParser.tables ./luci/sys/iptparser.lua /^function IptParser.tables( self )$/;" f +KEY_FUNC_2G_CHANNEL ./xiaoqiang/XQLog.lua /^KEY_FUNC_2G_CHANNEL = "function_channel_2g"$/;" f +KEY_FUNC_2G_SIGNAL ./xiaoqiang/XQLog.lua /^KEY_FUNC_2G_SIGNAL = "function_channel_2g_signal"$/;" f +KEY_FUNC_5G_CHANNEL ./xiaoqiang/XQLog.lua /^KEY_FUNC_5G_CHANNEL = "function_channel_5g"$/;" f +KEY_FUNC_5G_SIGNAL ./xiaoqiang/XQLog.lua /^KEY_FUNC_5G_SIGNAL = "function_channel_5g_signal"$/;" f +KEY_FUNC_APPQOS ./xiaoqiang/XQLog.lua /^KEY_FUNC_APPQOS = "function_appqos"$/;" f +KEY_FUNC_DMZ ./xiaoqiang/XQLog.lua /^KEY_FUNC_DMZ = "function_dmz"$/;" f +KEY_FUNC_L2TP ./xiaoqiang/XQLog.lua /^KEY_FUNC_L2TP = "function_l2tp_web"$/;" f +KEY_FUNC_MACCLONE ./xiaoqiang/XQLog.lua /^KEY_FUNC_MACCLONE = "function_clone"$/;" f +KEY_FUNC_NOFLUSHED ./xiaoqiang/XQLog.lua /^KEY_FUNC_NOFLUSHED = "function_hdd_hibernation"$/;" f +KEY_FUNC_PLUGIN ./xiaoqiang/XQLog.lua /^KEY_FUNC_PLUGIN = "function_plugin"$/;" f +KEY_FUNC_PORTENABLE ./xiaoqiang/XQLog.lua /^KEY_FUNC_PORTENABLE = "function_port_forwarding_active"$/;" f +KEY_FUNC_PORTFADD ./xiaoqiang/XQLog.lua /^KEY_FUNC_PORTFADD = "function_port_forwarding_add"$/;" f +KEY_FUNC_PPTP ./xiaoqiang/XQLog.lua /^KEY_FUNC_PPTP = "function_pptp_web"$/;" f +KEY_FUNC_QOS ./xiaoqiang/XQLog.lua /^KEY_FUNC_QOS = "function_qos"$/;" f +KEY_FUNC_RANGEFADD ./xiaoqiang/XQLog.lua /^KEY_FUNC_RANGEFADD = "function_range_forwarding_add"$/;" f +KEY_FUNC_UPNP ./xiaoqiang/XQLog.lua /^KEY_FUNC_UPNP = "function_upnp"$/;" f +KEY_FUNC_WIRELESS_ACCESS ./xiaoqiang/XQLog.lua /^KEY_FUNC_WIRELESS_ACCESS = "function_wireless_access"$/;" f +KEY_FUNC_WIRELESS_BLACK ./xiaoqiang/XQLog.lua /^KEY_FUNC_WIRELESS_BLACK = "function_wireless_access_blacklist"$/;" f +KEY_FUNC_WIRELESS_WHITE ./xiaoqiang/XQLog.lua /^KEY_FUNC_WIRELESS_WHITE = "function_wireless_access_whitelist"$/;" f +LEVEL_FUNCS[i] ./logging.lua /^ LEVEL_FUNCS[i] = function(self, ...)$/;" f +LOG_MSG ./logging.lua /^local function LOG_MSG(self, level, fmt, ...)$/;" f +ListValue.__init__ ./luci/cbi.lua /^function ListValue.__init__(self, ...)$/;" f +ListValue.reset_values ./luci/cbi.lua /^function ListValue.reset_values(self)$/;" f +ListValue.validate ./luci/cbi.lua /^function ListValue.validate(self, val)$/;" f +ListValue.value ./luci/cbi.lua /^function ListValue.value(self, key, val, ...)$/;" f +M.strsplit ./Posix.lua /^function M.strsplit(str, delim, maxNb)$/;" f +M.timeradd ./Posix.lua /^function M.timeradd (x,y)$/;" f +M.timercmp ./Posix.lua /^function M.timercmp (x, y)$/;" f +M.timersub ./Posix.lua /^function M.timersub (x,y)$/;" f +M.timesleep ./Posix.lua /^function M.timesleep (x)$/;" f +M.var_dump ./Posix.lua /^function M.var_dump(data, max_level, prefix)$/;" f +Map.__init__ ./luci/cbi.lua /^function Map.__init__(self, config, ...)$/;" f +Map.add ./luci/cbi.lua /^function Map.add(self, sectiontype)$/;" f +Map.chain ./luci/cbi.lua /^function Map.chain(self, config)$/;" f +Map.del ./luci/cbi.lua /^function Map.del(self, section, option)$/;" f +Map.formvalue ./luci/cbi.lua /^function Map.formvalue(self, key)$/;" f +Map.formvaluetable ./luci/cbi.lua /^function Map.formvaluetable(self, key)$/;" f +Map.get ./luci/cbi.lua /^function Map.get(self, section, option)$/;" f +Map.get_scheme ./luci/cbi.lua /^function Map.get_scheme(self, sectiontype, option)$/;" f +Map.parse ./luci/cbi.lua /^function Map.parse(self, readinput, ...)$/;" f +Map.render ./luci/cbi.lua /^function Map.render(self, ...)$/;" f +Map.section ./luci/cbi.lua /^function Map.section(self, class, ...)$/;" f +Map.set ./luci/cbi.lua /^function Map.set(self, section, option, value)$/;" f +Map.state_handler ./luci/cbi.lua /^function Map.state_handler(self, state)$/;" f +Map.submitstate ./luci/cbi.lua /^function Map.submitstate(self)$/;" f +MultiValue.__init__ ./luci/cbi.lua /^function MultiValue.__init__(self, ...)$/;" f +MultiValue.render ./luci/cbi.lua /^function MultiValue.render(self, ...)$/;" f +MultiValue.reset_values ./luci/cbi.lua /^function MultiValue.reset_values(self)$/;" f +MultiValue.validate ./luci/cbi.lua /^function MultiValue.validate(self, val)$/;" f +MultiValue.value ./luci/cbi.lua /^function MultiValue.value(self, key, val)$/;" f +MultiValue.valuelist ./luci/cbi.lua /^function MultiValue.valuelist(self, section)$/;" f +NOT ./sha1.lua /^local function NOT(a)$/;" f +NamedSection.__init__ ./luci/cbi.lua /^function NamedSection.__init__(self, map, section, stype, ...)$/;" f +NamedSection.parse ./luci/cbi.lua /^function NamedSection.parse(self, novld)$/;" f +Node.__init__ ./luci/cbi.lua /^function Node.__init__(self, title, description)$/;" f +Node._run_hook ./luci/cbi.lua /^function Node._run_hook(self, hook)$/;" f +Node._run_hooks ./luci/cbi.lua /^function Node._run_hooks(self, ...)$/;" f +Node.append ./luci/cbi.lua /^function Node.append(self, obj)$/;" f +Node.parse ./luci/cbi.lua /^function Node.parse(self, ...)$/;" f +Node.prepare ./luci/cbi.lua /^function Node.prepare(self, ...)$/;" f +Node.render ./luci/cbi.lua /^function Node.render(self, scope)$/;" f +Node.render_children ./luci/cbi.lua /^function Node.render_children(self, ...)$/;" f +OR ./sha1.lua /^local function OR(a, b)$/;" f +OR3 ./sha1.lua /^local function OR3(a, b, c)$/;" f +Page.parse ./luci/cbi.lua /^Page.parse = function() end$/;" f +Pluginpanel ./luci/view/web/plugin.htm /^ function Pluginpanel(option){$/;" f +REMOVE_TAGS ./xssFilter.lua /^REMOVE_TAGS = function(self, tag, message, text)$/;" f +REPLACE_TAGS ./xssFilter.lua /^REPLACE_TAGS = function(self, tag, message, text)$/;" f +ROTATE ./sha1.lua /^local function ROTATE(bits, a)$/;" f +Request.__init__ ./luci/http.lua /^function Request.__init__(self, env, sourcein, sinkerr)$/;" f +Request._parse_input ./luci/http.lua /^function Request._parse_input(self)$/;" f +Request.content ./luci/http.lua /^function Request.content(self)$/;" f +Request.formvalue ./luci/http.lua /^function Request.formvalue(self, name, noparse)$/;" f +Request.formvaluetable ./luci/http.lua /^function Request.formvaluetable(self, prefix)$/;" f +Request.getcookie ./luci/http.lua /^function Request.getcookie(self, name)$/;" f +Request.getenv ./luci/http.lua /^function Request.getenv(self, name)$/;" f +Request.setfilehandler ./luci/http.lua /^function Request.setfilehandler(self, callback)$/;" f +SLAXML:dom ./slaxdom.lua /^function SLAXML:dom(xml,opts)$/;" f +SLAXML:parse ./slaxml.lua /^function SLAXML:parse(xml,options)$/;" f +SLAXML:parser ./slaxml.lua /^function SLAXML:parser(callbacks)$/;" f +ShowPanel ./luci/view/web/plugins/kuaipan.htm /^ function ShowPanel(panelId) {\/\/控制面板$/;" f +SimpleForm.__init__ ./luci/cbi.lua /^function SimpleForm.__init__(self, config, title, description, data)$/;" f +SimpleForm.del ./luci/cbi.lua /^function SimpleForm.del(self, section, option)$/;" f +SimpleForm.field ./luci/cbi.lua /^function SimpleForm.field(self, class, ...)$/;" f +SimpleForm.get ./luci/cbi.lua /^function SimpleForm.get(self, section, option)$/;" f +SimpleForm.get_scheme ./luci/cbi.lua /^function SimpleForm.get_scheme()$/;" f +SimpleForm.parse ./luci/cbi.lua /^function SimpleForm.parse(self, readinput, ...)$/;" f +SimpleForm.render ./luci/cbi.lua /^function SimpleForm.render(self, ...)$/;" f +SimpleForm.section ./luci/cbi.lua /^function SimpleForm.section(self, class, ...)$/;" f +SimpleForm.set ./luci/cbi.lua /^function SimpleForm.set(self, section, option, value)$/;" f +SimpleForm.submitstate ./luci/cbi.lua /^function SimpleForm.submitstate(self)$/;" f +SimpleSection.__init__ ./luci/cbi.lua /^function SimpleSection.__init__(self, form, ...)$/;" f +StaticList.__init__ ./luci/cbi.lua /^function StaticList.__init__(self, ...)$/;" f +StaticList.validate ./luci/cbi.lua /^function StaticList.validate(self, value)$/;" f +Table.__init__ ./luci/cbi.lua /^function Table.__init__(self, form, data, ...)$/;" f +Table.cfgsections ./luci/cbi.lua /^function Table.cfgsections(self)$/;" f +Table.parse ./luci/cbi.lua /^function Table.parse(self, readinput)$/;" f +Table.update ./luci/cbi.lua /^function Table.update(self, data)$/;" f +Template.__init__ ./luci/cbi.lua /^function Template.__init__(self, template)$/;" f +Template.__init__ ./luci/template.lua /^function Template.__init__(self, name) $/;" f +Template.parse ./luci/cbi.lua /^function Template.parse(self, readinput)$/;" f +Template.render ./luci/cbi.lua /^function Template.render(self)$/;" f +Template.render ./luci/template.lua /^function Template.render(self, scope)$/;" f +TextValue.__init__ ./luci/cbi.lua /^function TextValue.__init__(self, ...)$/;" f +TypedSection.__init__ ./luci/cbi.lua /^function TypedSection.__init__(self, map, type, ...)$/;" f +TypedSection.cfgsections ./luci/cbi.lua /^function TypedSection.cfgsections(self)$/;" f +TypedSection.checkscope ./luci/cbi.lua /^function TypedSection.checkscope(self, section)$/;" f +TypedSection.depends ./luci/cbi.lua /^function TypedSection.depends(self, option, value)$/;" f +TypedSection.parse ./luci/cbi.lua /^function TypedSection.parse(self, novld)$/;" f +TypedSection.validate ./luci/cbi.lua /^function TypedSection.validate(self, section)$/;" f +Value.__init__ ./luci/cbi.lua /^function Value.__init__(self, ...)$/;" f +Value.reset_values ./luci/cbi.lua /^function Value.reset_values(self)$/;" f +Value.value ./luci/cbi.lua /^function Value.value(self, key, val)$/;" f +XOR ./sha1.lua /^local function XOR(first, ...)$/;" f +XSSFilter:call_tags_handler ./xssFilter.lua /^function XSSFilter:call_tags_handler(tag, message, text)$/;" f +XSSFilter:filter ./xssFilter.lua /^function XSSFilter:filter(html)$/;" f +XSSFilter:init ./xssFilter.lua /^function XSSFilter:init(allowed_tags, generic_attrs)$/;" f +ZERO ./sha1.lua /^local function ZERO()$/;" f +['function'] ./luci/json.lua /^ ['function'] = Encoder.parse_iter$/;" f +_ ./luci/dispatcher.lua /^function _(text)$/;" f +_M['and'] ./luci/cbi/datatypes.lua /^_M['and'] = function(v, ...)$/;" f +_M['or'] ./luci/cbi/datatypes.lua /^_M['or'] = function(v, ...)$/;" f +__appendval ./luci/http/protocol.lua /^local function __appendval( tbl, key, chunk )$/;" f +__array16 ./luci/ip.lua /^local function __array16( x, family )$/;" f +__bless ./luci/ip.lua /^local function __bless(x)$/;" f +__call ./socket.lua /^ __call = function()$/;" f +__call ./socket.lua /^ __call = function(self, chunk, err)$/;" f +__call ./socket/http.lua /^ __call = function()$/;" f +__call ./socket/http.lua /^ __call = function(self, chunk, err)$/;" f +__chrdec ./luci/http/protocol.lua /^ local function __chrdec( hex )$/;" f +__chrenc ./luci/http/protocol.lua /^ local function __chrenc( chr )$/;" f +__finishval ./luci/http/protocol.lua /^local function __finishval( tbl, key, handler )$/;" f +__index ./luci/config.lua /^ __index = function(tbl, key)$/;" f +__index ./luci/sys.lua /^ __index = function(t, k)$/;" f +__index ./luci/sys/zoneinfo.lua /^ __index = function(t, k)$/;" f +__index ./luci/util.lua /^ __index = function(self, key)$/;" f +__initval ./luci/http/protocol.lua /^local function __initval( tbl, key )$/;" f +__mask16 ./luci/ip.lua /^local function __mask16(bits)$/;" f +__maxlen ./luci/ip.lua /^local function __maxlen(family)$/;" f +__newindex ./luci/util.lua /^ __newindex = function(self, key, value)$/;" f +__not16 ./luci/ip.lua /^local function __not16(bits)$/;" f +__sublen ./luci/ip.lua /^local function __sublen(family)$/;" f +_action ./luci/model/ipkg.lua /^local function _action(cmd, ...)$/;" f +_add ./luci/sys.lua /^ local function _add(i, ...)$/;" f +_appSpeedlimit ./xiaoqiang/util/XQQoSUtil.lua /^function _appSpeedlimit(app, maxdownload, maxupload)$/;" f +_append ./luci/model/network.lua /^function _append(c, s, o, a)$/;" f +_application ./xiaoqiang/util/XQQoSUtil.lua /^function _application()$/;" f +_apply ./xiaoqiang/util/XQQoSUtil.lua /^function _apply()$/;" f +_arcombine ./luci/dispatcher.lua /^local function _arcombine(self, ...)$/;" f +_bitFormat ./xiaoqiang/util/XQQoSUtil.lua /^function _bitFormat(bits)$/;" f +_bitTotal ./xiaoqiang/util/XQSecureUtil.lua /^function _bitTotal(num)$/;" f +_call ./luci/dispatcher.lua /^local function _call(self, ...)$/;" f +_cancelWgetDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _cancelWgetDownload(downloadId)$/;" f +_cancelXunleiDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _cancelXunleiDownload(downloadId)$/;" f +_channelFix ./xiaoqiang/util/XQWifiUtil.lua /^function _channelFix(channel)$/;" f +_charMode ./xiaoqiang/util/XQSecureUtil.lua /^function _charMode(char)$/;" f +_checkConnection ./luci/controller/api/xqsystem.lua /^function _checkConnection(mac, try)$/;" f +_checkGuestWifi ./xiaoqiang/module/XQGuestWifi.lua /^function _checkGuestWifi()$/;" f +_checkIP ./xiaoqiang/util/XQLanWanUtil.lua /^function _checkIP(ip)$/;" f +_checkMac ./xiaoqiang/util/XQLanWanUtil.lua /^function _checkMac(mac)$/;" f +_checkResource ./xiaoqiang/util/XQDownloadUtil.lua /^function _checkResource(downloadUrl)$/;" f +_checkid ./luci/sauth.lua /^local function _checkid(id)$/;" f +_create_node ./luci/dispatcher.lua /^function _create_node(path)$/;" f +_ddnsRestart ./xiaoqiang/module/XQDDNS.lua /^function _ddnsRestart()$/;" f +_ddnsServerSwitch ./xiaoqiang/module/XQDDNS.lua /^function _ddnsServerSwitch(server, enable)$/;" f +_deldhcp ./xiaoqiang/module/XQGuestWifi.lua /^function _deldhcp()$/;" f +_deleteDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _deleteDownload(ids)$/;" f +_delfirewall ./xiaoqiang/module/XQGuestWifi.lua /^function _delfirewall()$/;" f +_delnetwork ./xiaoqiang/module/XQGuestWifi.lua /^function _delnetwork()$/;" f +_doPush ./xiaoqiang/XQPushHelper.lua /^function _doPush(payload, title, description, ptype)$/;" f +_encode_filename ./luci/ccache.lua /^ local function _encode_filename(name)$/;" f +_filter ./luci/model/network.lua /^function _filter(c, s, o, r)$/;" f +_firstchild ./luci/dispatcher.lua /^function _firstchild()$/;" f +_formatMac ./xiaoqiang/util/XQSDKUtil.lua /^function _formatMac(mac)$/;" f +_formatStr ./xiaoqiang/XQPushHelper.lua /^function _formatStr(str)$/;" f +_get ./luci/model/firewall.lua /^function _get(c, s, o)$/;" f +_get ./luci/model/network.lua /^function _get(c, s, o)$/;" f +_hookADFilterEvent ./xiaoqiang/XQPushHelper.lua /^function _hookADFilterEvent(page, all)$/;" f +_hookAllDownloadFinished ./xiaoqiang/XQPushHelper.lua /^function _hookAllDownloadFinished()$/;" f +_hookCachecenterEvent ./xiaoqiang/XQPushHelper.lua /^function _hookCachecenterEvent(hitcount, timesaver)$/;" f +_hookDefault ./xiaoqiang/XQPushHelper.lua /^function _hookDefault(data)$/;" f +_hookDetectFinished ./xiaoqiang/XQPushHelper.lua /^function _hookDetectFinished(lan, wan)$/;" f +_hookDownloadEvent ./xiaoqiang/XQPushHelper.lua /^function _hookDownloadEvent(count)$/;" f +_hookIntelligentScene ./xiaoqiang/XQPushHelper.lua /^function _hookIntelligentScene(name,actions)$/;" f +_hookNewRomVersionDetected ./xiaoqiang/XQPushHelper.lua /^function _hookNewRomVersionDetected(version)$/;" f +_hookSysUpgraded ./xiaoqiang/XQPushHelper.lua /^function _hookSysUpgraded()$/;" f +_hookUploadEvent ./xiaoqiang/XQPushHelper.lua /^function _hookUploadEvent(count)$/;" f +_hookWifiConnect ./xiaoqiang/XQPushHelper.lua /^function _hookWifiConnect(mac)$/;" f +_hookWifiDisconnect ./xiaoqiang/XQPushHelper.lua /^function _hookWifiDisconnect(mac)$/;" f +_iface_ignore ./luci/model/network.lua /^function _iface_ignore(x)$/;" f +_iface_virtual ./luci/model/network.lua /^function _iface_virtual(x)$/;" f +_ifattr ./luci/dispatcher.lua /^ local function _ifattr(cond, key, val)$/;" f +_instantiate ./luci/util.lua /^local function _instantiate(class, ...)$/;" f +_keyWordsFilter ./xiaoqiang/util/XQSecureUtil.lua /^function _keyWordsFilter(value)$/;" f +_levelHelper ./xiaoqiang/util/XQQoSUtil.lua /^function _levelHelper(weight)$/;" f +_list ./luci/model/ipkg.lua /^function _list(action, pat, cb)$/;" f +_load_sane ./luci/ccache.lua /^ local function _load_sane(file)$/;" f +_lookup ./luci/model/ipkg.lua /^local function _lookup(act, pkg)$/;" f +_nethints ./luci/sys.lua /^local function _nethints(what, callback)$/;" f +_noauthAccessAllowed ./luci/dispatcher.lua /^function _noauthAccessAllowed(flag)$/;" f +_noinitAccessAllowed ./luci/dispatcher.lua /^function _noinitAccessAllowed(flag)$/;" f +_parse ./xiaoqiang/common/XQFunction.lua /^function _parse(hex, pre)$/;" f +_parseDhcpLeases ./xiaoqiang/util/XQLanWanUtil.lua /^function _parseDhcpLeases()$/;" f +_parseEncryption ./xiaoqiang/util/XQWifiUtil.lua /^function _parseEncryption(encryption)$/;" f +_parseMac ./xiaoqiang/util/XQLanWanUtil.lua /^function _parseMac(mac)$/;" f +_parse_mixed_record ./luci/sys.lua /^function _parse_mixed_record(cnt, delimiter)$/;" f +_parselist ./luci/model/ipkg.lua /^local function _parselist(rawdata)$/;" f +_parserFlag ./xiaoqiang/XQPushHelper.lua /^function _parserFlag(flag)$/;" f +_parserPushType ./xiaoqiang/XQPushHelper.lua /^function _parserPushType(ptype)$/;" f +_pauseChannel ./xiaoqiang/util/XQWifiUtil.lua /^function _pauseChannel(channel)$/;" f +_pauseDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _pauseDownload(ids)$/;" f +_permissionFilter ./xiaoqiang/util/XQSDKUtil.lua /^function _permissionFilter(mac)$/;" f +_portCheck ./xiaoqiang/module/XQPortForward.lua /^function _portCheck(port)$/;" f +_portConflictCheck ./xiaoqiang/module/XQPortForward.lua /^function _portConflictCheck(port)$/;" f +_portRangeOverlap ./xiaoqiang/module/XQPortForward.lua /^function _portRangeOverlap(port1, port2)$/;" f +_pppoeErrorCodeHelper ./xiaoqiang/util/XQLanWanUtil.lua /^function _pppoeErrorCodeHelper(code)$/;" f +_pppoeStatusCheck ./xiaoqiang/util/XQLanWanUtil.lua /^function _pppoeStatusCheck()$/;" f +_prepare ./luci/controller/api/xqsystem.lua /^function _prepare()$/;" f +_protoHelper ./xiaoqiang/module/XQPortForward.lua /^function _protoHelper(proto)$/;" f +_read ./luci/sauth.lua /^local function _read(id)$/;" f +_recurse ./nixio/fs.lua /^local function _recurse(cb, src, dest)$/;" f +_remoteAccessForbidden ./luci/dispatcher.lua /^function _remoteAccessForbidden(flag)$/;" f +_resolve_deps ./luci/model/uci.lua /^ local function _resolve_deps(name)$/;" f +_resumeDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _resumeDownload(ids)$/;" f +_sane ./luci/controller/api/xqsystem.lua /^function _sane()$/;" f +_saveConfig ./xiaoqiang/module/XQDDNS.lua /^function _saveConfig(server, enable, username, password, checkinterval, forceinterval, domain)$/;" f +_savePassword ./luci/controller/api/xqsystem.lua /^function _savePassword(nonce, oldpwd, newpwd)$/;" f +_sdkFilter ./luci/dispatcher.lua /^function _sdkFilter(flag)$/;" f +_serialize_data ./luci/util.lua /^function _serialize_data(val)$/;" f +_serialize_table ./luci/util.lua /^function _serialize_table(t)$/;" f +_serverId ./xiaoqiang/module/XQDDNS.lua /^function _serverId(server)$/;" f +_set ./luci/model/firewall.lua /^function _set(c, s, o, v)$/;" f +_set ./luci/model/network.lua /^function _set(c, s, o, v)$/;" f +_set ./xiaoqiang/util/XQQoSUtil.lua /^function _set(section, option, value)$/;" f +_setComplexDMZ ./xiaoqiang/module/XQDMZModule.lua /^function _setComplexDMZ(destip, destmac)$/;" f +_setSimpleDMZ ./xiaoqiang/module/XQDMZModule.lua /^function _setSimpleDMZ(destip, destmac)$/;" f +_setdhcp ./xiaoqiang/module/XQGuestWifi.lua /^function _setdhcp()$/;" f +_setfirewall ./xiaoqiang/module/XQGuestWifi.lua /^function _setfirewall()$/;" f +_setnetwork ./xiaoqiang/module/XQGuestWifi.lua /^function _setnetwork()$/;" f +_sortiter ./luci/util.lua /^function _sortiter( t, f )$/;" f +_stror ./luci/model/network.lua /^function _stror(s1, s2)$/;" f +_syslockAccessAllowed ./luci/dispatcher.lua /^function _syslockAccessAllowed(flag)$/;" f +_test ./xssFilter.lua /^ _test = function(tag)$/;" f +_valid_id ./luci/model/firewall.lua /^function _valid_id(x)$/;" f +_vpnErrorCodeHelper ./luci/controller/api/xqsystem.lua /^function _vpnErrorCodeHelper(code)$/;" f +_weightHelper ./xiaoqiang/util/XQQoSUtil.lua /^function _weightHelper(level)$/;" f +_wgetDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _wgetDownload(downloadUrl)$/;" f +_wgetDownloadPercent ./xiaoqiang/util/XQDownloadUtil.lua /^function _wgetDownloadPercent(downloadId)$/;" f +_wifiNameForIndex ./xiaoqiang/util/XQWifiUtil.lua /^function _wifiNameForIndex(index)$/;" f +_wifi_iface ./luci/model/network.lua /^function _wifi_iface(x)$/;" f +_wifi_lookup ./luci/model/network.lua /^function _wifi_lookup(ifn)$/;" f +_write ./luci/sauth.lua /^local function _write(id, data)$/;" f +_write_sane ./luci/ccache.lua /^ local function _write_sane(file, func)$/;" f +_xunleiDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function _xunleiDownload(downloadUrl, priority)$/;" f +_xunleiDownloadPercent ./xiaoqiang/util/XQDownloadUtil.lua /^function _xunleiDownloadPercent(downloadId)$/;" f +a, b) return tonumber ./luci/controller/api/xqsystem.lua /^ table.sort(statList, function(a, b) return tonumber(a.download) > tonumber(b.download) end)$/;" f +absolute ./socket/url.lua /^function absolute(base_url, relative_url)$/;" f +absolute_path ./socket/url.lua /^local function absolute_path(base_path, relative_path)$/;" f +actionLogin ./luci/controller/api/xqsystem.lua /^function actionLogin()$/;" f +action_logout ./luci/controller/mobile/index.lua /^function action_logout()$/;" f +action_logout ./luci/controller/web/index.lua /^function action_logout()$/;" f +action_safeurl ./luci/controller/web/index.lua /^function action_safeurl()$/;" f +addBind ./xiaoqiang/util/XQLanWanUtil.lua /^function addBind(mac, ip)$/;" f +addDdns ./luci/view/web/setting/ddns.htm /^ function addDdns(e){$/;" f +addEvent ./luci/view/web/setting/qos_pro.htm /^ function addEvent(){$/;" f +addRangeRedirect ./luci/controller/api/xqnetwork.lua /^function addRangeRedirect()$/;" f +addRedirect ./luci/controller/api/xqnetwork.lua /^function addRedirect()$/;" f +addServer ./luci/controller/api/xqnetwork.lua /^function addServer()$/;" f +add_network ./luci/model/network.lua /^function add_network(self, n, options)$/;" f +add_wifinet ./luci/model/network.lua /^function add_wifinet(self, net, options)$/;" f +add_zone ./luci/model/firewall.lua /^function add_zone(self, n)$/;" f +adjust_headers ./socket/smtp.lua /^local function adjust_headers(mesgt)$/;" f +adjustheaders ./socket/http.lua /^local function adjustheaders(reqt)$/;" f +adjustproxy ./socket/http.lua /^local function adjustproxy(reqt)$/;" f +adjustrequest ./socket/http.lua /^local function adjustrequest(reqt)$/;" f +adjusturi ./socket/http.lua /^local function adjusturi(reqt)$/;" f +alias ./luci/dispatcher.lua /^function alias(...)$/;" f +appInfo ./xiaoqiang/util/XQQoSUtil.lua /^function appInfo()$/;" f +appLimit ./luci/controller/api/xqsystem.lua /^function appLimit()$/;" f +appLimitSwitch ./luci/controller/api/xqsystem.lua /^function appLimitSwitch()$/;" f +appSpeedlimitSwitch ./xiaoqiang/util/XQQoSUtil.lua /^function appSpeedlimitSwitch(enable)$/;" f +append ./luci/util.lua /^function append(src, ...)$/;" f +append_yeelink_list ./xiaoqiang/util/XQZigbeeUtil.lua /^function append_yeelink_list(list)$/;" f +arcombine ./luci/dispatcher.lua /^function arcombine(trg1, trg2)$/;" f +areThingsMounted ./luci/controller/api/xqsystem.lua /^function areThingsMounted()$/;" f +areThingsMounted ./luci/view/web/setting/lamp.htm /^ function areThingsMounted(){$/;" f +asHEX ./sha1.lua /^function asHEX(a)$/;" f +ask ./luci/view/web/setting/net_wan.htm /^ function ask(){$/;" f +assert ./logging.lua /^local function assert(exp, ...)$/;" f +assert(type(func) ./luci/dispatcher.lua /^ assert(type(func) == "function",$/;" f +assert(type(idx) ./luci/dispatcher.lua /^ assert(type(idx) == "function",$/;" f +assign ./luci/dispatcher.lua /^function assign(path, clone, title, order, flag)$/;" f +attr ./luci/dispatcher.lua /^ attr = function(...) return _ifattr(true, ...) end;$/;" f +attribute ./slaxdom.lua /^ attribute = function(name,value,nsURI)$/;" f +attribute ./slaxml.lua /^ attribute = function(name,value,nsURI)$/;" f +authen ./luci/dispatcher.lua /^ authen = function() return eu end$/;" f +authenticator.htmlauth ./luci/dispatcher.lua /^function authenticator.htmlauth(validator, accs, default)$/;" f +authenticator.htmlauth_moblie ./luci/dispatcher.lua /^function authenticator.htmlauth_moblie(validator, accs, default)$/;" f +authenticator.jsonauth ./luci/dispatcher.lua /^function authenticator.jsonauth(validator, accs, default)$/;" f +available ./luci/sauth.lua /^function available()$/;" f +base64filter ./luci/controller/api/xqtunnel.lua /^local function base64filter(input)$/;" f +bigendian ./luci/util.lua /^function bigendian()$/;" f +binToHex ./xiaoqiang/util/XQCryptoUtil.lua /^function binToHex(s)$/;" f +binaryBase64Dec ./xiaoqiang/util/XQCryptoUtil.lua /^function binaryBase64Dec(data)$/;" f +binaryBase64Enc ./xiaoqiang/util/XQCryptoUtil.lua /^function binaryBase64Enc(data)$/;" f +bind ./socket.lua /^function bind(host, port, backlog)$/;" f +bool ./luci/cbi/datatypes.lua /^function bool(val)$/;" f +build ./socket/url.lua /^function build(parsed)$/;" f +buildUrl ./luci/view/mobile/init/hello.htm /^ function buildUrl(token, path){$/;" f +buildUrl ./luci/view/web/xmaccount.htm /^function buildUrl(token, path){$/;" f +build_path ./socket/url.lua /^function build_path(parsed, unsafe)$/;" f +build_querystring ./luci/http.lua /^function build_querystring(q)$/;" f +build_url ./luci/dispatcher.lua /^function build_url(...)$/;" f +byteFormat ./xiaoqiang/common/XQFunction.lua /^function byteFormat(byte)$/;" f +byte_format ./luci/tools/webadmin.lua /^function byte_format(byte)$/;" f +bytes2GB ./luci/view/web/plugins/kuaipan.htm /^ function bytes2GB(bytes) {$/;" f +c) return string.format ./luci/controller/service/datacenter.lua /^ function(c) return string.format ("%%%02X", string.byte(c)) end)$/;" f +cache_enable ./luci/ccache.lua /^function cache_enable(cachepath, mode)$/;" f +cache_ondemand ./luci/ccache.lua /^function cache_ondemand(...)$/;" f +call ./luci/dispatcher.lua /^function call(name, ...)$/;" f +call ./luci/sys.lua /^function call(...)$/;" f +cancelDownload ./xiaoqiang/util/XQDownloadUtil.lua /^function cancelDownload(downloadUrl)$/;" f +cancelUpgrade ./luci/controller/api/xqsystem.lua /^function cancelUpgrade()$/;" f +cancelUpgrade ./xiaoqiang/util/XQSysUtil.lua /^function cancelUpgrade()$/;" f +castMitvResult ./xiaoqiang/util/XQMitvUtil.lua /^function castMitvResult(str)$/;" f +cbi_add_knownips ./luci/tools/webadmin.lua /^function cbi_add_knownips(field)$/;" f +cbi_add_networks ./luci/tools/webadmin.lua /^function cbi_add_networks(field)$/;" f +channelFormat ./xiaoqiang/util/XQWifiUtil.lua /^function channelFormat(wifiIndex, channel, bandwidth)$/;" f +channelHelper ./xiaoqiang/util/XQWifiUtil.lua /^function channelHelper(channel)$/;" f +check ./xiaoqiang/XQLog.lua /^function check(ctype, key, value)$/;" f +checkBeenUpgraded ./xiaoqiang/util/XQSysUtil.lua /^function checkBeenUpgraded()$/;" f +checkDiskSpace ./xiaoqiang/util/XQSysUtil.lua /^function checkDiskSpace(byte)$/;" f +checkExecStatus ./xiaoqiang/util/XQSysUtil.lua /^function checkExecStatus(checkCmd)$/;" f +checkFileExist ./luci/controller/api/xqdatacenter.lua /^function checkFileExist()$/;" f +checkLanIp ./xiaoqiang/util/XQLanWanUtil.lua /^function checkLanIp(ip)$/;" f +checkMTU ./xiaoqiang/util/XQLanWanUtil.lua /^function checkMTU(value)$/;" f +checkMask ./xiaoqiang/common/XQFunction.lua /^function checkMask(mask)$/;" f +checkNonce ./xiaoqiang/util/XQSecureUtil.lua /^function checkNonce(nonce, mac)$/;" f +checkPermission ./xiaoqiang/util/XQSDKUtil.lua /^function checkPermission(mac)$/;" f +checkPlaintextPwd ./xiaoqiang/util/XQSecureUtil.lua /^function checkPlaintextPwd(user, plaintext)$/;" f +checkRedirectKey ./xiaoqiang/util/XQSecureUtil.lua /^function checkRedirectKey(key)$/;" f +checkRomUpdate ./luci/controller/api/xqsystem.lua /^function checkRomUpdate()$/;" f +checkRouterNamePending ./luci/controller/api/xqsystem.lua /^function checkRouterNamePending()$/;" f +checkSSID ./xiaoqiang/common/XQFunction.lua /^function checkSSID(ssid)$/;" f +checkSSID ./xiaoqiang/util/XQWifiUtil.lua /^function checkSSID(ssid,length)$/;" f +checkStrong ./xiaoqiang/util/XQSecureUtil.lua /^function checkStrong(pwd)$/;" f +checkSysPassword ./xiaoqiang/util/XQSysUtil.lua /^function checkSysPassword(oldPassword)$/;" f +checkSystemStatus ./xiaoqiang/util/XQSysUtil.lua /^function checkSystemStatus()$/;" f +checkTmpSpace ./xiaoqiang/util/XQSysUtil.lua /^function checkTmpSpace(byte)$/;" f +checkUpgrade ./xiaoqiang/util/XQNetUtil.lua /^function checkUpgrade()$/;" f +checkUpgradeStatus ./xiaoqiang/util/XQSysUtil.lua /^function checkUpgradeStatus()$/;" f +checkUser ./xiaoqiang/util/XQSecureUtil.lua /^function checkUser(user, nonce, encStr)$/;" f +checkWanIp ./xiaoqiang/util/XQLanWanUtil.lua /^function checkWanIp(ip)$/;" f +checkWifiPasswd ./xiaoqiang/util/XQWifiUtil.lua /^function checkWifiPasswd(passwd,encryption)$/;" f +check_show_syslock ./luci/dispatcher.lua /^function check_show_syslock(sysauth)$/;" f +checkid ./xiaoqiang/util/XQSecureUtil.lua /^function checkid(id)$/;" f +chmod777 ./xiaoqiang/util/XQCameraUtil.lua /^function chmod777()$/;" f +choose ./mime.lua /^local function choose(table)$/;" f +choose ./socket.lua /^function choose(table)$/;" f +cidr.add ./luci/ip.lua /^function cidr.add( self, amount, inplace )$/;" f +cidr.broadcast ./luci/ip.lua /^function cidr.broadcast( self )$/;" f +cidr.contains ./luci/ip.lua /^function cidr.contains( self, addr )$/;" f +cidr.equal ./luci/ip.lua /^function cidr.equal( self, addr )$/;" f +cidr.higher ./luci/ip.lua /^function cidr.higher( self, addr )$/;" f +cidr.host ./luci/ip.lua /^function cidr.host( self )$/;" f +cidr.is4 ./luci/ip.lua /^function cidr.is4( self )$/;" f +cidr.is4linklocal ./luci/ip.lua /^function cidr.is4linklocal( self )$/;" f +cidr.is4rfc1918 ./luci/ip.lua /^function cidr.is4rfc1918( self )$/;" f +cidr.is6 ./luci/ip.lua /^function cidr.is6( self )$/;" f +cidr.is6linklocal ./luci/ip.lua /^function cidr.is6linklocal( self )$/;" f +cidr.lower ./luci/ip.lua /^function cidr.lower( self, addr )$/;" f +cidr.mask ./luci/ip.lua /^function cidr.mask( self, bits )$/;" f +cidr.maxhost ./luci/ip.lua /^function cidr.maxhost( self )$/;" f +cidr.minhost ./luci/ip.lua /^function cidr.minhost( self )$/;" f +cidr.network ./luci/ip.lua /^function cidr.network( self, bits )$/;" f +cidr.prefix ./luci/ip.lua /^function cidr.prefix( self, mask )$/;" f +cidr.string ./luci/ip.lua /^function cidr.string( self )$/;" f +cidr.sub ./luci/ip.lua /^function cidr.sub( self, amount, inplace )$/;" f +cipher ./rc4.lua /^local function cipher(sMessage, state)$/;" f +ciphertextFormat ./xiaoqiang/util/XQSecureUtil.lua /^function ciphertextFormat(ciphertext)$/;" f +class ./luci/util.lua /^function class(base)$/;" f +clear ./luci/i18n.lua /^function clear()$/;" f +clearCookies ./luci/view/web/inc/reboot.js.htm /^ function clearCookies(){$/;" f +clearRouterNamePending ./luci/controller/api/xqsystem.lua /^function clearRouterNamePending()$/;" f +clone ./luci/util.lua /^function clone(object, deep)$/;" f +close ./luci/http.lua /^function close()$/;" f +closeDMZ ./luci/controller/api/xqnetwork.lua /^function closeDMZ()$/;" f +closeElement ./slaxml.lua /^ local function closeElement()$/;" f +closeElement ./slaxdom.lua /^ closeElement = function(name)$/;" f +closeElement ./slaxml.lua /^ closeElement = function(name,nsURI)$/;" f +closeWebInitRDR ./xiaoqiang/common/XQFunction.lua /^function closeWebInitRDR()$/;" f +cmatch ./luci/util.lua /^function cmatch(str, pat)$/;" f +cmd ./sysapi/miqos.lua /^function cmd(action)$/;" f +cmdSafeCheck ./xiaoqiang/util/XQSecureUtil.lua /^function cmdSafeCheck(url)$/;" f +code:sub ./luci/util.lua /^ return code:sub(1,12) .. strip_function(code:sub(13,-1))$/;" f +combine ./luci/util.lua /^function combine(...)$/;" f +command ./socket/ftp.lua /^command = socket.protect(function(cmdt)$/;" f +comment ./slaxdom.lua /^ comment = function(value)$/;" f +comment ./slaxml.lua /^ comment = function(content)$/;" f +commit ./luci/model/firewall.lua /^function commit(self, ...)$/;" f +commit ./luci/model/network.lua /^function commit(self, ...)$/;" f +comparator ./luci/model/uci.lua /^ comparator = function(section)$/;" f +compare ./luci/http/protocol/date.lua /^function compare(d1, d2)$/;" f +compile_datatype ./luci/cbi.lua /^function compile_datatype(code)$/;" f +configRecovery ./luci/controller/api/xqsystem.lua /^function configRecovery()$/;" f +conn:connect ./ssl/https.lua /^ function conn:connect(host, port)$/;" f +conn:settimeout ./ssl/https.lua /^ function conn:settimeout(...)$/;" f +conn[name] ./ssl/https.lua /^ conn[name] = function (self, ...)$/;" f +connect ./socket.lua /^function connect(address, port, laddress, lport)$/;" f +connect ./socket/tp.lua /^function connect(host, port, timeout, create)$/;" f +connectedDevice ./luci/controller/service/datacenter.lua /^function connectedDevice()$/;" f +consume ./nixio/util.lua /^function consume(iter, append)$/;" f +contains ./luci/util.lua /^function contains(table, value)$/;" f +content ./luci/http.lua /^function content()$/;" f +content ./luci/view/error404.htm /^

404 <%:Not Found%><\/a><\/h2>$/;" a +content ./luci/view/error500.htm /^

500 <%:Internal Server Error%><\/a><\/h2>$/;" a +control ./xiaoqiang/util/XQMitvUtil.lua /^function control(ip,keycode)$/;" f +controlPlugin ./luci/controller/service/datacenter.lua /^function controlPlugin()$/;" f +controlSync ./luci/view/web/plugins/kuaipan.htm /^ function controlSync(action) {$/;" f +copcall ./luci/util.lua /^function copcall(f, ...)$/;" f +copcall_id ./luci/util.lua /^local function copcall_id(trace, ...)$/;" f +copy ./nixio/fs.lua /^function copy(src, dest)$/;" f +copyr ./nixio/fs.lua /^function copyr(src, dest)$/;" f +coxpcall ./luci/util.lua /^function coxpcall(f, err, ...)$/;" f +createKeySchedule ./rc4.lua /^local function createKeySchedule(sKey)$/;" f +createSandbox ./luci/controller/api/xqsystem.lua /^function createSandbox()$/;" f +createSandbox ./luci/view/web/setting/lamp.htm /^ function createSandbox(){$/;" f +createindex ./luci/dispatcher.lua /^function createindex()$/;" f +createindex_fastindex ./luci/dispatcher.lua /^function createindex_fastindex(path, suffixes)$/;" f +createindex_plain ./luci/dispatcher.lua /^function createindex_plain(path, suffixes)$/;" f +createtree ./luci/dispatcher.lua /^function createtree()$/;" f +cryptUrl ./xiaoqiang/util/XQNetUtil.lua /^function cryptUrl(serverUrl, subUrl, params, salt)$/;" f +cursor_state ./luci/model/uci.lua /^function cursor_state()$/;" f +cutImage ./xiaoqiang/util/XQSysUtil.lua /^function cutImage(filePath)$/;" f +datacopy ./nixio/fs.lua /^function datacopy(src, dest, size)$/;" f +datasource.del ./luci/cbi.lua /^ function datasource.del(...)$/;" f +datasource.get ./luci/cbi.lua /^ function datasource.get(self, section, option)$/;" f +datasource.get_scheme ./luci/cbi.lua /^ function datasource.get_scheme()$/;" f +datasource.submitstate ./luci/cbi.lua /^ function datasource.submitstate(self)$/;" f +date_format ./luci/tools/webadmin.lua /^function date_format(secs)$/;" f +ddnsEdit ./luci/controller/api/xqnetwork.lua /^function ddnsEdit()$/;" f +ddnsInfo ./xiaoqiang/module/XQDDNS.lua /^function ddnsInfo()$/;" f +ddnsReload ./luci/controller/api/xqnetwork.lua /^function ddnsReload()$/;" f +ddnsServerSwitch ./xiaoqiang/module/XQDDNS.lua /^function ddnsServerSwitch(id, on)$/;" f +ddnsStatus ./luci/controller/api/xqnetwork.lua /^function ddnsStatus()$/;" f +ddnsSwitch ./luci/controller/api/xqnetwork.lua /^function ddnsSwitch()$/;" f +ddnsSwitch ./luci/view/web/setting/ddns.htm /^ function ddnsSwitch(){$/;" f +ddnsSwitch ./xiaoqiang/module/XQDDNS.lua /^function ddnsSwitch(on)$/;" f +decCiphertext ./xiaoqiang/util/XQSecureUtil.lua /^function decCiphertext(user, ciphertext)$/;" f +decode ./json.lua /^function decode(s, startPos)$/;" f +decode ./luci/json.lua /^function decode(json, ...)$/;" f +decode_scanArray ./json.lua /^function decode_scanArray(s,startPos)$/;" f +decode_scanComment ./json.lua /^function decode_scanComment(s, startPos)$/;" f +decode_scanConstant ./json.lua /^function decode_scanConstant(s, startPos)$/;" f +decode_scanNumber ./json.lua /^function decode_scanNumber(s,startPos)$/;" f +decode_scanObject ./json.lua /^function decode_scanObject(s,startPos)$/;" f +decode_scanString ./json.lua /^function decode_scanString(s,startPos)$/;" f +decode_scanWhitespace ./json.lua /^function decode_scanWhitespace(s,startPos)$/;" f +decodet['base64'] ./mime.lua /^decodet['base64'] = function()$/;" f +decodet['quoted-printable'] ./mime.lua /^decodet['quoted-printable'] = function()$/;" f +default_https_port ./ssl/https.lua /^local function default_https_port(u)$/;" f +defaults.__init__ ./luci/model/firewall.lua /^function defaults.__init__(self)$/;" f +defaults.drop_invalid ./luci/model/firewall.lua /^function defaults.drop_invalid(self)$/;" f +defaults.forward ./luci/model/firewall.lua /^function defaults.forward(self)$/;" f +defaults.get ./luci/model/firewall.lua /^function defaults.get(self, opt)$/;" f +defaults.input ./luci/model/firewall.lua /^function defaults.input(self)$/;" f +defaults.output ./luci/model/firewall.lua /^function defaults.output(self)$/;" f +defaults.set ./luci/model/firewall.lua /^function defaults.set(self, opt, val)$/;" f +defaults.syn_flood ./luci/model/firewall.lua /^function defaults.syn_flood(self)$/;" f +delGuestWifi ./xiaoqiang/module/XQGuestWifi.lua /^function delGuestWifi(wifiIndex)$/;" f +delGuestWifi ./xiaoqiang/util/XQWifiUtil.lua /^function delGuestWifi(wifiIndex)$/;" f +del_network ./luci/model/firewall.lua /^function del_network(self, net)$/;" f +del_network ./luci/model/network.lua /^function del_network(self, n)$/;" f +del_wifinet ./luci/model/network.lua /^function del_wifinet(self, net)$/;" f +del_zone ./luci/model/firewall.lua /^function del_zone(self, n)$/;" f +deleteAllPortForward ./xiaoqiang/module/XQPortForward.lua /^function deleteAllPortForward()$/;" f +deleteDdns ./xiaoqiang/module/XQDDNS.lua /^function deleteDdns(id)$/;" f +deleteDeviceInfo ./xiaoqiang/util/XQDBUtil.lua /^function deleteDeviceInfo(mac)$/;" f +deleteDownload ./luci/controller/service/datacenter.lua /^function deleteDownload()$/;" f +deletePassport ./xiaoqiang/util/XQDBUtil.lua /^function deletePassport(uuid)$/;" f +deletePortForward ./xiaoqiang/module/XQPortForward.lua /^function deletePortForward(port)$/;" f +deleteRedirect ./luci/controller/api/xqnetwork.lua /^function deleteRedirect()$/;" f +deleteServer ./luci/controller/api/xqnetwork.lua /^function deleteServer()$/;" f +deleteUserInfo ./xiaoqiang/util/XQDBUtil.lua /^function deleteUserInfo(uuid)$/;" f +dest.cfgvalue ./luci/model/cbi/firewall/forwards.lua /^function dest.cfgvalue(self, s)$/;" f +detecte ./luci/view/web/index.htm /^ function detecte(){$/;" f +developerInfo ./luci/view/web/setting/developer.htm /^ function developerInfo(){$/;" f +developerSet ./luci/view/web/setting/developer.htm /^ function developerSet(){$/;" f +developerSwitch ./luci/view/web/setting/developer.htm /^ function developerSwitch(){$/;" f +device ./luci/cbi/datatypes.lua /^function device( val, seen )$/;" f +dhcp6_leases ./luci/tools/status.lua /^function dhcp6_leases()$/;" f +dhcp_leases ./luci/tools/status.lua /^function dhcp_leases()$/;" f +dhcp_leases_common ./luci/tools/status.lua /^local function dhcp_leases_common(family)$/;" f +dir ./luci/fs.lua /^function dir(...)$/;" f +directory ./luci/cbi/datatypes.lua /^function directory( val, seen )$/;" f +dirty ./socket.lua /^ dirty = function() return sock:dirty() end$/;" f +dirty ./socket/http.lua /^ dirty = function() return sock:dirty() end$/;" f +disableLanAP ./xiaoqiang/module/XQAPModule.lua /^function disableLanAP()$/;" f +disablePlugin ./luci/controller/service/datacenter.lua /^function disablePlugin ()$/;" f +disable_level ./logging.lua /^local function disable_level() end$/;" f +dismissAccount ./xiaoqiang/util/XQNetUtil.lua /^function dismissAccount(uuid,account)$/;" f +dispatch ./luci/dispatcher.lua /^function dispatch(request)$/;" f +dmesg ./luci/sys.lua /^function dmesg()$/;" f +dmzReload ./xiaoqiang/module/XQDMZModule.lua /^function dmzReload(mode)$/;" f +dmzStatus ./luci/view/web/setting/dmz.htm /^ function dmzStatus(){$/;" f +dmzSwitch ./luci/view/web/setting/dmz.htm /^ function dmzSwitch(){$/;" f +dmzedit ./luci/view/web/setting/dmz.htm /^ function dmzedit() {$/;" f +dmzset ./luci/view/web/setting/dmz.htm /^ function dmzset(){$/;" f +dnsmsqRestart ./xiaoqiang/util/XQLanWanUtil.lua /^function dnsmsqRestart()$/;" f +doClose ./luci/view/web/setting/ddns.htm /^ function doClose(e){$/;" f +doDel ./luci/view/web/setting/ddns.htm /^ function doDel(e){$/;" f +doDelete ./xiaoqiang/util/XQCameraUtil.lua /^function doDelete(localfiles,afterDay)$/;" f +doDownload ./xiaoqiang/util/XQCameraUtil.lua /^function doDownload(f)$/;" f +doForceUpdate ./luci/view/web/setting/ddns.htm /^ function doForceUpdate(e){$/;" f +doNginx ./luci/view/web/setting/nginx.htm /^ function doNginx(){$/;" f +doOpen ./luci/view/web/setting/ddns.htm /^ function doOpen(e){$/;" f +doPrint ./xiaoqiang/common/XQFunction.lua /^function doPrint(content)$/;" f +doRequest ./xiaoqiang/util/XQNetUtil.lua /^function doRequest(method,url,param,uuid)$/;" f +done ./luci/view/web/setting/wifi_set_mini.htm /^ function done(){$/;" f +done ./luci/view/web/setting/wifi_set_pro.htm /^ function done(){$/;" f +download ./luci/controller/api/xqdatacenter.lua /^function download()$/;" f +downloadFile ./luci/controller/service/datacenter.lua /^function downloadFile()$/;" f +downloadPercent ./xiaoqiang/util/XQDownloadUtil.lua /^function downloadPercent(downloadId)$/;" f +downloadSpeedTest ./xiaoqiang/module/XQNetworkSpeedTest.lua /^function downloadSpeedTest()$/;" f +dtable ./luci/util.lua /^function dtable()$/;" f +dummy_test ./xssFilter.lua /^local function dummy_test()$/;" f +dumptable ./luci/util.lua /^function dumptable(t, maxdepth, i, seen)$/;" f +editDdns ./xiaoqiang/module/XQDDNS.lua /^function editDdns(id, enable, username, password, checkinterval, forceinterval, domain)$/;" f +editDevice ./luci/controller/api/xqnetwork.lua /^function editDevice()$/;" f +editWiFiMacfilterList ./xiaoqiang/util/XQWifiUtil.lua /^function editWiFiMacfilterList(model, mac, option)$/;" f +elseif base.type(mesgt.body) ./socket/smtp.lua /^ elseif base.type(mesgt.body) == "function" then send_source(mesgt)$/;" f +elseif f_type ./logging.lua /^ elseif f_type == 'function' then$/;" f +elseif type(datatypes[label]) ./luci/cbi.lua /^ elseif type(datatypes[label]) == "function" then$/;" f +elseif type(val) ./luci/util.lua /^ elseif type(val) == "function" then$/;" f +empower ./luci/dispatcher.lua /^function empower(lan,wan,admin)$/;" f +empty ./ltn12.lua /^local function empty()$/;" f +empty ./luci/ltn12.lua /^local function empty()$/;" f +enableLanAP ./xiaoqiang/module/XQAPModule.lua /^function enableLanAP()$/;" f +enablePlugin ./luci/controller/service/datacenter.lua /^function enablePlugin()$/;" f +encode ./luci/json.lua /^function encode(obj, ...)$/;" f +encode ./json.lua /^function encode (v)$/;" f +encodeString ./json.lua /^function encodeString(s)$/;" f +encodet['base64'] ./mime.lua /^encodet['base64'] = function()$/;" f +encodet['quoted-printable'] ./mime.lua /^encodet['quoted-printable'] = function(mode)$/;" f +entry ./luci/dispatcher.lua /^function entry(path, target, title, order, flag)$/;" f +error404 ./luci/dispatcher.lua /^function error404(message)$/;" f +error500 ./luci/dispatcher.lua /^function error500(message)$/;" f +escape ./luci/view/web/setting/wifi_set.htm /^function escape(str)$/;" f +escape ./socket/url.lua /^function escape(s)$/;" f +exec ./luci/util.lua /^function exec(command)$/;" f +execi ./luci/util.lua /^function execi(command)$/;" f +execl ./luci/util.lua /^function execl(command)$/;" f +execl ./xiaoqiang/module/XQNetworkSpeedTest.lua /^function execl(command, times)$/;" f +export ./luci/dispatcher.lua /^ export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end;$/;" f +f.try ./socket/ftp.lua /^ f.try = socket.newtry(function() f:close() end)$/;" f +facInfo ./xiaoqiang/util/XQSysUtil.lua /^function facInfo()$/;" f +fetchAllDeviceInfo ./xiaoqiang/util/XQDBUtil.lua /^function fetchAllDeviceInfo()$/;" f +fetchAllPassport ./xiaoqiang/util/XQDBUtil.lua /^function fetchAllPassport()$/;" f +fetchAllUserInfo ./xiaoqiang/util/XQDBUtil.lua /^function fetchAllUserInfo()$/;" f +fetchDeviceInfo ./xiaoqiang/util/XQDBUtil.lua /^function fetchDeviceInfo(mac)$/;" f +fetchPassport ./xiaoqiang/util/XQDBUtil.lua /^function fetchPassport(uuid)$/;" f +fetchUserInfo ./xiaoqiang/util/XQDBUtil.lua /^function fetchUserInfo(uuid)$/;" f +file ./luci/cbi/datatypes.lua /^function file( val, seen )$/;" f +filter.chain ./ltn12.lua /^function filter.chain(...)$/;" f +filter.chain ./luci/ltn12.lua /^function filter.chain(...)$/;" f +filter.cycle ./ltn12.lua /^function filter.cycle(low, ctx, extra)$/;" f +filter.cycle ./luci/ltn12.lua /^function filter.cycle(low, ctx, extra)$/;" f +find ./luci/model/ipkg.lua /^function find(pat, cb)$/;" f +findAttribute ./slaxml.lua /^ local function findAttribute()$/;" f +findCDATA ./slaxml.lua /^ local function findCDATA()$/;" f +findComment ./slaxml.lua /^ local function findComment()$/;" f +findElementClose ./slaxml.lua /^ local function findElementClose()$/;" f +findPI ./slaxml.lua /^ local function findPI()$/;" f +find_match ./xssFilter.lua /^local function find_match(value, patterns)$/;" f +finishText ./slaxml.lua /^ local function finishText()$/;" f +firewall_find_zone ./luci/tools/webadmin.lua /^function firewall_find_zone(name)$/;" f +firstchild ./luci/dispatcher.lua /^function firstchild()$/;" f +flashRom ./luci/controller/api/xqsystem.lua /^function flashRom()$/;" f +flashStatus ./luci/controller/api/xqsystem.lua /^function flashStatus()$/;" f +float ./luci/cbi/datatypes.lua /^function float(val)$/;" f +fmt_icmp_type ./luci/tools/firewall.lua /^function fmt_icmp_type(x)$/;" f +fmt_ip ./luci/tools/firewall.lua /^function fmt_ip(x, d)$/;" f +fmt_limit ./luci/tools/firewall.lua /^function fmt_limit(limit, burst)$/;" f +fmt_mac ./luci/tools/firewall.lua /^function fmt_mac(x)$/;" f +fmt_neg ./luci/tools/firewall.lua /^function fmt_neg(x)$/;" f +fmt_port ./luci/tools/firewall.lua /^function fmt_port(x, d)$/;" f +fmt_proto ./luci/tools/firewall.lua /^function fmt_proto(x, icmp_types)$/;" f +fmt_target ./luci/tools/firewall.lua /^function fmt_target(x, dest)$/;" f +fmt_zone ./luci/tools/firewall.lua /^function fmt_zone(x, d)$/;" f +forkExec ./xiaoqiang/common/XQFunction.lua /^function forkExec(command)$/;" f +forkFlashRomFile ./xiaoqiang/common/XQFunction.lua /^function forkFlashRomFile(filePath)$/;" f +forkReboot ./xiaoqiang/common/XQFunction.lua /^function forkReboot()$/;" f +forkResetAll ./xiaoqiang/common/XQFunction.lua /^function forkResetAll()$/;" f +forkRestartDnsmasq ./xiaoqiang/common/XQFunction.lua /^function forkRestartDnsmasq()$/;" f +forkRestartWifi ./xiaoqiang/common/XQFunction.lua /^function forkRestartWifi()$/;" f +forkShutdown ./xiaoqiang/common/XQFunction.lua /^function forkShutdown()$/;" f +forkShutdownAndRebootWithDelay ./xiaoqiang/common/XQFunction.lua /^function forkShutdownAndRebootWithDelay(m1, m2)$/;" f +format ./mime.lua /^local function format(chunk)$/;" f +formatTime ./luci/view/web/setting/ddns.htm /^ function formatTime(str){$/;" f +formvalue ./luci/http.lua /^function formvalue(name, noparse)$/;" f +formvaluetable ./luci/http.lua /^function formvaluetable(prefix)$/;" f +forward_proto_txt ./luci/model/cbi/firewall/forwards.lua /^local function forward_proto_txt(self, s)$/;" f +forward_src_txt ./luci/model/cbi/firewall/forwards.lua /^local function forward_src_txt(self, s)$/;" f +forward_via_txt ./luci/model/cbi/firewall/forwards.lua /^local function forward_via_txt(self, s)$/;" f +forwarding.__init__ ./luci/model/firewall.lua /^function forwarding.__init__(self, f)$/;" f +forwarding.dest ./luci/model/firewall.lua /^function forwarding.dest(self)$/;" f +forwarding.dest_zone ./luci/model/firewall.lua /^function forwarding.dest_zone(self)$/;" f +forwarding.src ./luci/model/firewall.lua /^function forwarding.src(self)$/;" f +forwarding.src_zone ./luci/model/firewall.lua /^function forwarding.src_zone(self)$/;" f +from_hex ./sha1.lua /^local function from_hex(hex)$/;" f +function(p) parsed.password ./socket/url.lua /^ function(p) parsed.password = p; return "" end)$/;" f +function(p) parsed.port ./socket/url.lua /^ function(p) parsed.port = p; return "" end)$/;" f +function(s) parsed.scheme ./socket/url.lua /^ function(s) parsed.scheme = s; return "" end)$/;" f +function(s) return (s.interface ./luci/model/network.lua /^ function(s) return (s.interface == n) end)$/;" f +function(s) wfd[#wfd+1] ./luci/model/network.lua /^ function(s) wfd[#wfd+1] = s['.name'] end)$/;" f +function(u) parsed.userinfo ./socket/url.lua /^ function(u) parsed.userinfo = u; return "" end)$/;" f +generateDns ./xiaoqiang/util/XQLanWanUtil.lua /^function generateDns(dns1, dns2, peerdns)$/;" f +generateMixed ./luci/view/web/setting/wifi_set.htm /^ function generateMixed(n) {$/;" f +generateOrigIconUrl ./xiaoqiang/util/XQNetUtil.lua /^function generateOrigIconUrl(iconUrl)$/;" f +generateRedirectKey ./xiaoqiang/util/XQSecureUtil.lua /^function generateRedirectKey(type)$/;" f +generateResponseFromCode ./luci/controller/service/datacenter.lua /^function generateResponseFromCode(code)$/;" f +generateSignature ./xiaoqiang/util/XQNetUtil.lua /^function generateSignature(method,url,params,security)$/;" f +generateUrlFromPath ./luci/controller/service/datacenter.lua /^function generateUrlFromPath(path)$/;" f +get ./luci/dispatcher.lua /^function get(...)$/;" f +get ./xiaoqiang/XQPreference.lua /^function get(key, defaultValue, config) $/;" f +get ./socket/ftp.lua /^get = socket.protect(function(gett)$/;" f +getAdminList ./xiaoqiang/util/XQNetUtil.lua /^function getAdminList(uuid)$/;" f +getAll ./xiaoqiang/util/XQCameraUtil.lua /^function getAll(did)$/;" f +getAllInfo ./luci/controller/api/xqsystem.lua /^function getAllInfo()$/;" f +getAllWifiConnetDeviceDict ./xiaoqiang/util/XQWifiUtil.lua /^function getAllWifiConnetDeviceDict()$/;" f +getAllWifiConnetDeviceList ./xiaoqiang/util/XQWifiUtil.lua /^function getAllWifiConnetDeviceList()$/;" f +getAllWifiInfo ./luci/controller/api/xqnetwork.lua /^function getAllWifiInfo()$/;" f +getAllWifiInfo ./xiaoqiang/util/XQWifiUtil.lua /^function getAllWifiInfo()$/;" f +getAntsCams ./xiaoqiang/util/XQCameraUtil.lua /^function getAntsCams()$/;" f +getAutoWanType ./luci/controller/api/xqnetwork.lua /^function getAutoWanType()$/;" f +getAutoWanType ./xiaoqiang/util/XQLanWanUtil.lua /^function getAutoWanType()$/;" f +getAvailableDisk ./xiaoqiang/util/XQSysUtil.lua /^function getAvailableDisk()$/;" f +getAvailableMemery ./xiaoqiang/util/XQSysUtil.lua /^function getAvailableMemery()$/;" f +getBandList ./xiaoqiang/util/XQWifiUtil.lua /^function getBandList(channel)$/;" f +getBandwidth ./luci/view/web/setting/qos_pro.htm /^ function getBandwidth( type ){$/;" f +getBatchDownloadInfo ./luci/controller/service/datacenter.lua /^function getBatchDownloadInfo()$/;" f +getBindInfo ./luci/controller/api/xqpassport.lua /^function getBindInfo()$/;" f +getBindUUID ./xiaoqiang/util/XQSysUtil.lua /^function getBindUUID()$/;" f +getBindUserInfo ./xiaoqiang/util/XQSysUtil.lua /^function getBindUserInfo()$/;" f +getCFEVersion ./xiaoqiang/util/XQSysUtil.lua /^function getCFEVersion()$/;" f +getCache ./xiaoqiang/util/XQCacheUtil.lua /^function getCache(key)$/;" f +getChangeLog ./xiaoqiang/util/XQSysUtil.lua /^function getChangeLog()$/;" f +getChannel ./xiaoqiang/util/XQSysUtil.lua /^function getChannel()$/;" f +getChannels ./luci/controller/api/xqnetwork.lua /^function getChannels()$/;" f +getChannels ./xiaoqiang/util/XQWifiUtil.lua /^function getChannels(wifiIndex)$/;" f +getConDevCount ./luci/controller/api/xqsystem.lua /^function getConDevCount()$/;" f +getConDevices ./xiaoqiang/util/XQDeviceUtil.lua /^function getConDevices(withbrlan)$/;" f +getConfig ./xiaoqiang/util/XQCameraUtil.lua /^function getConfig(did)$/;" f +getConfigFile ./xiaoqiang/util/XQNetUtil.lua /^function getConfigFile(configfile)$/;" f +getConfigInfo ./luci/controller/service/datacenter.lua /^function getConfigInfo()$/;" f +getConfigInfo ./xiaoqiang/util/XQSysUtil.lua /^function getConfigInfo()$/;" f +getConnectDeviceCount ./xiaoqiang/util/XQDeviceUtil.lua /^function getConnectDeviceCount()$/;" f +getConnectDeviceList ./xiaoqiang/util/XQDeviceUtil.lua /^function getConnectDeviceList()$/;" f +getCountryCodeList ./xiaoqiang/XQCountryCode.lua /^function getCountryCodeList()$/;" f +getCpuTemperature ./xiaoqiang/util/XQSysUtil.lua /^function getCpuTemperature()$/;" f +getCurrentCountryCode ./xiaoqiang/XQCountryCode.lua /^function getCurrentCountryCode()$/;" f +getCurrentDisk ./xiaoqiang/util/XQCameraUtil.lua /^function getCurrentDisk()$/;" f +getCurrentPID ./xiaoqiang/util/XQCameraUtil.lua /^function getCurrentPID()$/;" f +getDDNS ./luci/view/web/setting/ddns.htm /^ function getDDNS(){$/;" f +getDHCPDict ./xiaoqiang/util/XQDeviceUtil.lua /^function getDHCPDict()$/;" f +getDHCPIpDict ./xiaoqiang/util/XQDeviceUtil.lua /^function getDHCPIpDict()$/;" f +getDHCPList ./xiaoqiang/util/XQDeviceUtil.lua /^function getDHCPList()$/;" f +getDMZInfo ./luci/controller/api/xqnetwork.lua /^function getDMZInfo()$/;" f +getDMZInfo ./xiaoqiang/module/XQDMZModule.lua /^function getDMZInfo()$/;" f +getDay ./xiaoqiang/util/XQCameraUtil.lua /^function getDay(days)$/;" f +getDdns ./xiaoqiang/module/XQDDNS.lua /^function getDdns(id)$/;" f +getDefaultMacAddress ./xiaoqiang/util/XQLanWanUtil.lua /^function getDefaultMacAddress()$/;" f +getDefaultWifiChannels ./xiaoqiang/util/XQWifiUtil.lua /^function getDefaultWifiChannels(wifiIndex)$/;" f +getDetectionTimestamp ./luci/controller/api/xqsystem.lua /^function getDetectionTimestamp()$/;" f +getDetectionTimestamp ./xiaoqiang/util/XQSysUtil.lua /^function getDetectionTimestamp()$/;" f +getDevNetStatisticsDict ./xiaoqiang/util/XQDeviceUtil.lua /^function getDevNetStatisticsDict()$/;" f +getDevNetStatisticsList ./xiaoqiang/util/XQDeviceUtil.lua /^function getDevNetStatisticsList()$/;" f +getDevStatistics ./luci/controller/api/xqnetwork.lua /^function getDevStatistics()$/;" f +getDeviceCompany ./xiaoqiang/util/XQDeviceUtil.lua /^function getDeviceCompany(mac)$/;" f +getDeviceID ./luci/controller/service/datacenter.lua /^function getDeviceID()$/;" f +getDeviceId ./luci/controller/api/xqdatacenter.lua /^function getDeviceId()$/;" f +getDeviceId ./xiaoqiang/util/XQNetUtil.lua /^function getDeviceId()$/;" f +getDeviceInfoFromDB ./xiaoqiang/util/XQDeviceUtil.lua /^function getDeviceInfoFromDB()$/;" f +getDeviceList ./luci/controller/api/xqsystem.lua /^function getDeviceList()$/;" f +getDeviceListZigbee ./luci/controller/api/xqsystem.lua /^function getDeviceListZigbee()$/;" f +getDeviceMacaddr ./luci/controller/api/xqsystem.lua /^function getDeviceMacaddr()$/;" f +getDeviceWifiIndex ./xiaoqiang/util/XQWifiUtil.lua /^function getDeviceWifiIndex(mac)$/;" f +getDevsStatistics ./luci/controller/api/xqnetwork.lua /^function getDevsStatistics()$/;" f +getDiskSpace ./xiaoqiang/util/XQSysUtil.lua /^function getDiskSpace()$/;" f +getDownloadInfo ./luci/controller/service/datacenter.lua /^function getDownloadInfo()$/;" f +getErrorMessage ./service/util/ServiceErrorUtil.lua /^function getErrorMessage(errorCode)$/;" f +getErrorMessage ./xiaoqiang/util/XQErrorUtil.lua /^function getErrorMessage(errorCode)$/;" f +getFacInfo ./luci/controller/api/xqsystem.lua /^function getFacInfo()$/;" f +getFilesOnCam ./xiaoqiang/util/XQCameraUtil.lua /^function getFilesOnCam(item,afterDay)$/;" f +getFilesOnRouter ./xiaoqiang/util/XQCameraUtil.lua /^function getFilesOnRouter()$/;" f +getFlashStatus ./xiaoqiang/util/XQSysUtil.lua /^function getFlashStatus()$/;" f +getGpioValue ./xiaoqiang/common/XQFunction.lua /^function getGpioValue(digit)$/;" f +getGuestWifi ./xiaoqiang/util/XQWifiUtil.lua /^function getGuestWifi(wifiIndex)$/;" f +getHardware ./xiaoqiang/util/XQSysUtil.lua /^function getHardware()$/;" f +getHardwareGPIO ./xiaoqiang/util/XQSysUtil.lua /^function getHardwareGPIO()$/;" f +getHardwareVersion ./xiaoqiang/util/XQSysUtil.lua /^function getHardwareVersion()$/;" f +getIPv6Addrs ./xiaoqiang/util/XQLanWanUtil.lua /^function getIPv6Addrs()$/;" f +getInitInfo ./luci/controller/api/xqsystem.lua /^function getInitInfo()$/;" f +getInitInfo ./xiaoqiang/util/XQSysUtil.lua /^function getInitInfo()$/;" f +getKPLoginedUserInfo ./luci/view/web/plugins/kuaipan.htm /^ function getKPLoginedUserInfo() {$/;" f +getKPStatus ./luci/view/web/plugins/kuaipan.htm /^ function getKPStatus() {$/;" f +getKernelVersion ./xiaoqiang/util/XQSysUtil.lua /^function getKernelVersion()$/;" f +getLanDHCPService ./xiaoqiang/util/XQLanWanUtil.lua /^function getLanDHCPService()$/;" f +getLanDhcp ./luci/controller/api/xqnetwork.lua /^function getLanDhcp()$/;" f +getLanInfo ./luci/controller/api/xqnetwork.lua /^function getLanInfo()$/;" f +getLanIp ./xiaoqiang/util/XQLanWanUtil.lua /^function getLanIp()$/;" f +getLanLinkList ./xiaoqiang/util/XQLanWanUtil.lua /^function getLanLinkList()$/;" f +getLanWanInfo ./xiaoqiang/util/XQLanWanUtil.lua /^function getLanWanInfo(interface)$/;" f +getLanWanIp ./xiaoqiang/util/XQLanWanUtil.lua /^function getLanWanIp(interface)$/;" f +getLanWanSta ./luci/controller/api/xqsystem.lua /^function getLanWanSta()$/;" f +getLang ./xiaoqiang/util/XQSysUtil.lua /^function getLang()$/;" f +getLangList ./luci/controller/api/xqsystem.lua /^function getLangList()$/;" f +getLangList ./xiaoqiang/util/XQSysUtil.lua /^function getLangList()$/;" f +getMac ./luci/controller/service/datacenter.lua /^function getMac()$/;" f +getMacAddr ./xiaoqiang/util/XQNetUtil.lua /^function getMacAddr()$/;" f +getMacBindInfo ./luci/controller/api/xqnetwork.lua /^function getMacBindInfo()$/;" f +getMacfilterInfoDict ./xiaoqiang/util/XQDeviceUtil.lua /^function getMacfilterInfoDict()$/;" f +getMacfilterInfoList ./xiaoqiang/util/XQDeviceUtil.lua /^function getMacfilterInfoList()$/;" f +getMacfilterMode ./luci/controller/api/xqsystem.lua /^function getMacfilterMode()$/;" f +getMacfilterMode ./xiaoqiang/util/XQSysUtil.lua /^function getMacfilterMode(filter)$/;" f +getMainLang ./luci/controller/api/xqsystem.lua /^function getMainLang()$/;" f +getMiscHardwareInfo ./xiaoqiang/util/XQSysUtil.lua /^function getMiscHardwareInfo()$/;" f +getModel ./xiaoqiang/util/XQCameraUtil.lua /^function getModel()$/;" f +getModulesList ./xiaoqiang/util/XQSysUtil.lua /^function getModulesList()$/;" f +getNetMode ./xiaoqiang/common/XQFunction.lua /^function getNetMode()$/;" f +getNetworkDetectInfo ./xiaoqiang/util/XQSysUtil.lua /^function getNetworkDetectInfo(simple,target)$/;" f +getNextKpStatus ./luci/view/web/plugins/kuaipan.htm /^ function getNextKpStatus() {$/;" f +getNofStatus ./luci/controller/api/xqsystem.lua /^function getNofStatus()$/;" f +getNvramConfigs ./xiaoqiang/util/XQSysUtil.lua /^function getNvramConfigs()$/;" f +getOperateDeviceID ./luci/controller/service/datacenter.lua /^function getOperateDeviceID()$/;" f +getPPPoEStatus ./xiaoqiang/util/XQLanWanUtil.lua /^function getPPPoEStatus()$/;" f +getPassport ./xiaoqiang/util/XQNetUtil.lua /^function getPassport(uuid)$/;" f +getPassportBindInfo ./luci/controller/api/xqsystem.lua /^function getPassportBindInfo()$/;" f +getPassportBindInfo ./xiaoqiang/util/XQSysUtil.lua /^function getPassportBindInfo()$/;" f +getQosInfo ./luci/controller/api/xqnetwork.lua /^function getQosInfo()$/;" f +getRamFsVersion ./xiaoqiang/util/XQSysUtil.lua /^function getRamFsVersion()$/;" f +getRomVersion ./xiaoqiang/util/XQSysUtil.lua /^function getRomVersion()$/;" f +getRootFsVersion ./xiaoqiang/util/XQSysUtil.lua /^function getRootFsVersion()$/;" f +getRouterInfo ./luci/controller/service/datacenter.lua /^function getRouterInfo()$/;" f +getRouterName ./luci/controller/api/xqsystem.lua /^function getRouterName()$/;" f +getRouterName ./xiaoqiang/util/XQSysUtil.lua /^function getRouterName()$/;" f +getRouterNamePending ./xiaoqiang/util/XQSysUtil.lua /^function getRouterNamePending()$/;" f +getSN ./xiaoqiang/util/XQNetUtil.lua /^function getSN()$/;" f +getServer ./luci/controller/api/xqnetwork.lua /^function getServer()$/;" f +getSqaFsVersion ./xiaoqiang/util/XQSysUtil.lua /^function getSqaFsVersion()$/;" f +getStatus ./luci/view/web/plugin.htm /^ function getStatus(){$/;" f +getStatusInfo ./luci/controller/api/xqsystem.lua /^function getStatusInfo()$/;" f +getSysAvgLoad ./luci/controller/api/xqsystem.lua /^function getSysAvgLoad()$/;" f +getSysInfo ./luci/controller/api/xqnetdetect.lua /^function getSysInfo()$/;" f +getSysInfo ./luci/controller/api/xqsystem.lua /^function getSysInfo()$/;" f +getSysInfo ./xiaoqiang/util/XQSysUtil.lua /^function getSysInfo()$/;" f +getSysUptime ./xiaoqiang/util/XQSysUtil.lua /^function getSysUptime()$/;" f +getThumb ./luci/controller/api/xqdatacenter.lua /^function getThumb()$/;" f +getTime ./xiaoqiang/common/XQFunction.lua /^function getTime()$/;" f +getToken ./luci/controller/api/xqsystem.lua /^function getToken()$/;" f +getToken ./luci/view/mobile/init/hello.htm /^ function getToken( url ) {$/;" f +getToken ./xiaoqiang/util/XQNetUtil.lua /^function getToken()$/;" f +getUPnPList ./xiaoqiang/util/XQUPnPUtil.lua /^function getUPnPList()$/;" f +getUPnPStatus ./xiaoqiang/util/XQUPnPUtil.lua /^function getUPnPStatus()$/;" f +getUid ./xiaoqiang/util/XQCameraUtil.lua /^function getUid(did)$/;" f +getUpgradeStatus ./xiaoqiang/util/XQSysUtil.lua /^function getUpgradeStatus()$/;" f +getUserAgent ./xiaoqiang/util/XQNetUtil.lua /^function getUserAgent()$/;" f +getUserDeviceList ./xiaoqiang/util/XQNetUtil.lua /^function getUserDeviceList(uuid)$/;" f +getUserInfo ./luci/controller/api/xqpassport.lua /^function getUserInfo()$/;" f +getUserInfo ./xiaoqiang/util/XQNetUtil.lua /^function getUserInfo(uuid)$/;" f +getVPNInfo ./xiaoqiang/util/XQVPNUtil.lua /^function getVPNInfo(interface)$/;" f +getWanDetails ./xiaoqiang/util/XQLanWanUtil.lua /^function getWanDetails()$/;" f +getWanEth ./xiaoqiang/util/XQLanWanUtil.lua /^function getWanEth()$/;" f +getWanInfo ./luci/controller/api/xqnetwork.lua /^function getWanInfo()$/;" f +getWanLanNetworkStatistics ./xiaoqiang/util/XQDeviceUtil.lua /^function getWanLanNetworkStatistics(devName)$/;" f +getWanMac ./xiaoqiang/util/XQLanWanUtil.lua /^function getWanMac()$/;" f +getWanMonitorStat ./xiaoqiang/util/XQLanWanUtil.lua /^function getWanMonitorStat()$/;" f +getWanStatistics ./luci/controller/api/xqnetwork.lua /^function getWanStatistics()$/;" f +getWanStatus ./luci/controller/api/xqnetdetect.lua /^function getWanStatus()$/;" f +getWiFiMacfilterInfo ./xiaoqiang/util/XQWifiUtil.lua /^function getWiFiMacfilterInfo(model)$/;" f +getWiFiMacfilterList ./xiaoqiang/util/XQWifiUtil.lua /^function getWiFiMacfilterList(model)$/;" f +getWifiBridgedClient ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiBridgedClient(wifiIndex)$/;" f +getWifiChTx ./luci/controller/api/xqnetwork.lua /^function getWifiChTx()$/;" f +getWifiChannel ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiChannel(wifiIndex)$/;" f +getWifiChannelList ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiChannelList()$/;" f +getWifiChannelTxpwrList ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiChannelTxpwrList()$/;" f +getWifiConDev ./luci/controller/api/xqnetwork.lua /^function getWifiConDev()$/;" f +getWifiConnectDeviceDict ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiConnectDeviceDict(wifiIndex)$/;" f +getWifiConnectDeviceList ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiConnectDeviceList(wifiIndex)$/;" f +getWifiDeviceSignalDict ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiDeviceSignalDict(wifiIndex)$/;" f +getWifiInfo ./luci/controller/api/xqnetwork.lua /^function getWifiInfo()$/;" f +getWifiLog ./luci/controller/api/xqsystem.lua /^function getWifiLog()$/;" f +getWifiLog ./xiaoqiang/util/XQSysUtil.lua /^function getWifiLog()$/;" f +getWifiMacfilterInfo ./luci/controller/api/xqnetwork.lua /^function getWifiMacfilterInfo()$/;" f +getWifiNames ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiNames()$/;" f +getWifiScanList ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiScanList()$/;" f +getWifiStatus ./luci/controller/api/xqnetwork.lua /^function getWifiStatus()$/;" f +getWifiStatus ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiStatus(wifiIndex)$/;" f +getWifiTxpwr ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiTxpwr(wifiIndex)$/;" f +getWifiTxpwrList ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiTxpwrList()$/;" f +getWifiWorkChannel ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiWorkChannel(wifiIndex)$/;" f +getWifiWpsStatus ./xiaoqiang/util/XQWifiUtil.lua /^function getWifiWpsStatus()$/;" f +getWpsConDevMac ./xiaoqiang/util/XQWifiUtil.lua /^function getWpsConDevMac()$/;" f +getWpsStatus ./luci/controller/api/xqsystem.lua /^function getWpsStatus()$/;" f +get_bytecode ./luci/util.lua /^function get_bytecode(val)$/;" f +get_defaults ./luci/model/firewall.lua /^function get_defaults()$/;" f +get_hostname ./traffic.lua /^function get_hostname(mac)$/;" f +get_hostname_init ./traffic.lua /^function get_hostname_init()$/;" f +get_interface ./luci/model/network.lua /^function get_interface(self, i)$/;" f +get_interfaces ./luci/model/network.lua /^function get_interfaces(self)$/;" f +get_lan_dev_name ./traffic.lua /^function get_lan_dev_name()$/;" f +get_network ./luci/model/network.lua /^function get_network(self, n)$/;" f +get_networks ./luci/model/network.lua /^function get_networks(self)$/;" f +get_protocol ./luci/model/network.lua /^function get_protocol(self, protoname, netname)$/;" f +get_protocols ./luci/model/network.lua /^function get_protocols(self)$/;" f +get_reply ./socket/tp.lua /^local function get_reply(c)$/;" f +get_status_by_address ./luci/model/network.lua /^function get_status_by_address(self, addr)$/;" f +get_status_by_route ./luci/model/network.lua /^function get_status_by_route(self, addr, mask)$/;" f +get_wan6dev ./luci/model/network.lua /^function get_wan6dev(self)$/;" f +get_wan6net ./luci/model/network.lua /^function get_wan6net(self)$/;" f +get_wan_dev_name ./traffic.lua /^function get_wan_dev_name()$/;" f +get_wandev ./luci/model/network.lua /^function get_wandev(self)$/;" f +get_wannet ./luci/model/network.lua /^function get_wannet(self)$/;" f +get_wifidev ./luci/model/network.lua /^function get_wifidev(self, dev)$/;" f +get_wifidevs ./luci/model/network.lua /^function get_wifidevs(self)$/;" f +get_wifinet ./luci/model/network.lua /^function get_wifinet(self, net)$/;" f +get_zigbee_count ./xiaoqiang/util/XQZigbeeUtil.lua /^function get_zigbee_count()$/;" f +get_zone ./luci/model/firewall.lua /^function get_zone(self, n)$/;" f +get_zone_by_network ./luci/model/firewall.lua /^function get_zone_by_network(self, net)$/;" f +get_zones ./luci/model/firewall.lua /^function get_zones(self)$/;" f +getcookie ./luci/http.lua /^function getcookie(name)$/;" f +getenv ./luci/http.lua /^function getenv(name)$/;" f +getfd ./socket.lua /^ getfd = function() return sock:getfd() end,$/;" f +getfd ./socket/http.lua /^ getfd = function() return sock:getfd() end,$/;" f +getmetatable("").__mod ./luci/util.lua /^getmetatable("").__mod = function(a, b)$/;" f +getremotemac ./luci/dispatcher.lua /^function getremotemac()$/;" f +glob ./luci/fs.lua /^function glob(...)$/;" f +h.try ./socket/http.lua /^ h.try = socket.newtry(function() h:close() end)$/;" f +handleReturnValue ./luci/util.lua /^function handleReturnValue(err, co, status, ...)$/;" f +handle_request ./luci/sgi/uhttpd.lua /^function handle_request(env)$/;" f +hasFile ./xiaoqiang/util/XQCameraUtil.lua /^function hasFile(f,fileList)$/;" f +hasR ./luci/util.lua /^function hasR(t, seen)$/;" f +hasRecursion ./luci/util.lua /^function hasRecursion(t)$/;" f +has_ipv6 ./luci/model/network.lua /^function has_ipv6(self)$/;" f +hash4SHA1 ./xiaoqiang/util/XQCryptoUtil.lua /^function hash4SHA1(str)$/;" f +header ./luci/http.lua /^function header(key, value)$/;" f +header_source ./luci/http/protocol.lua /^function header_source( sock )$/;" f +helper ./luci/model/uci.lua /^ local function helper (section)$/;" f +hex_to_binary ./sha1.lua /^local function hex_to_binary(hex)$/;" f +hextobin ./xiaoqiang/util/XQCryptoUtil.lua /^function hextobin(s)$/;" f +hmac_sha1 ./sha1.lua /^function hmac_sha1(key, text)$/;" f +hmac_sha1_binary ./sha1.lua /^function hmac_sha1_binary(key, text)$/;" f +hookLanIPChangeEvent ./xiaoqiang/module/XQDMZModule.lua /^function hookLanIPChangeEvent(ip)$/;" f +hookLanIPChangeEvent ./xiaoqiang/module/XQPortForward.lua /^function hookLanIPChangeEvent(ip)$/;" f +hookLanIPChangeEvent ./xiaoqiang/util/XQLanWanUtil.lua /^function hookLanIPChangeEvent(ip)$/;" f +host ./luci/cbi/datatypes.lua /^function host(val)$/;" f +hostname ./luci/cbi/datatypes.lua /^function hostname(val)$/;" f +hostname ./luci/sys.lua /^function hostname(newname)$/;" f +htonl ./luci/ip.lua /^function htonl(x)$/;" f +htons ./luci/ip.lua /^function htons(x)$/;" f +httpGetRequest ./xiaoqiang/util/XQHttpUtil.lua /^function httpGetRequest(url, paramStr, cookies)$/;" f +httpPostRequest ./xiaoqiang/util/XQHttpUtil.lua /^function httpPostRequest(url, paramStr, cookies)$/;" f +http_request_log ./luci/dispatcher.lua /^function http_request_log(request, tag)$/;" f +httpdispatch ./luci/dispatcher.lua /^function httpdispatch(request, prefix)$/;" f +httpget ./luci/sys.lua /^function httpget(url, stream, target)$/;" f +hzFormat ./xiaoqiang/common/XQFunction.lua /^function hzFormat(hertz)$/;" f +i,v) table.insert ./xiaoqiang/util/XQDownloadUtil.lua /^ table.foreach(uncompletedList, function(i,v) table.insert(completedList, v) end)$/;" f +i,v) table.insert ./xiaoqiang/util/XQDownloadUtil.lua /^ table.foreach(uncompletedList, function(i,v) table.insert(completedList, v) end)$/;" f +identifyDevice ./luci/controller/api/xqdatacenter.lua /^function identifyDevice()$/;" f +identifyDevice ./xiaoqiang/XQEquipment.lua /^function identifyDevice(mac, dhcpname)$/;" f +if base.type(ok) ~ ./socket/tp.lua /^ if base.type(ok) ~= "function" then$/;" f +if c and (c.index or type(target) ./luci/dispatcher.lua /^ if c and (c.index or type(target) == "function") then$/;" f +if c and type(c[1]) ./luci/cbi.lua /^ if c and type(c[1]) == "function" then$/;" f +if params.connectionfactory ./logging/sql.lua /^ if params.connectionfactory == nil or type(params.connectionfactory) ~= "function" then$/;" f +if type(append) ~ ./logging.lua /^ if type(append) ~= "function" then$/;" f +if type(c.target) ./luci/dispatcher.lua /^ if type(c.target) == "function" then$/;" f +if type(f) ~ ./luci/cbi/datatypes.lua /^ if type(f) ~= "function" then$/;" f +if type(filecb) ./luci/http/protocol.lua /^ if type(filecb) == "function" then$/;" f +if type(method) ./ssl/https.lua /^ if type(method) == "function" then$/;" f +if type(modcons) ./luci/ccache.lua /^ if type(modcons) == "function" then$/;" f +if type(rawdata) ~ ./luci/model/ipkg.lua /^ if type(rawdata) ~= "function" then$/;" f +if type(self.active) ~ ./luci/cbi.lua /^ if type(self.active) ~= "function" then$/;" f +if type(self.active) ~ ./luci/cbi.lua /^ if type(self.active) ~= "function" then$/;" f +if type(self.commit_handler) ./luci/cbi.lua /^ if type(self.commit_handler) == "function" then$/;" f +if type(self.value) ./luci/cbi.lua /^ if type(self.value) == "function" then$/;" f +if type(self[f]) ./luci/cbi.lua /^ if type(self[f]) == "function" then$/;" f +if type(self[hook]) ./luci/cbi.lua /^ if type(self[hook]) == "function" then$/;" f +if type(stack[#stack-1]) ~ ./luci/cbi.lua /^ if type(stack[#stack-1]) ~= "function" then$/;" f +if type(subvalidator) ~ ./luci/cbi/datatypes.lua /^ if type(subvalidator) ~= "function" then$/;" f +if type(target) ./luci/dispatcher.lua /^ if type(target) == "function" then$/;" f +if type(val) ./luci/util.lua /^ if type(val) == "function" then$/;" f +if vtype ./json.lua /^ if vtype=='function' and v==null then$/;" f +if_match ./luci/http/protocol/conditionals.lua /^function if_match( req, stat )$/;" f +if_modified_since ./luci/http/protocol/conditionals.lua /^function if_modified_since( req, stat )$/;" f +if_none_match ./luci/http/protocol/conditionals.lua /^function if_none_match( req, stat )$/;" f +if_range ./luci/http/protocol/conditionals.lua /^function if_range( req, stat )$/;" f +if_unmodified_since ./luci/http/protocol/conditionals.lua /^function if_unmodified_since( req, stat )$/;" f +iface_get_network ./luci/tools/webadmin.lua /^function iface_get_network(iface)$/;" f +ifattr ./luci/dispatcher.lua /^ ifattr = function(...) return _ifattr(...) end;$/;" f +ifnameof ./luci/model/network.lua /^function ifnameof(self, x)$/;" f +ignore_interface ./luci/model/network.lua /^function ignore_interface(self, x)$/;" f +imatch ./luci/util.lua /^function imatch(v)$/;" f +include ./luci/dispatcher.lua /^ include = function(name) tpl.Template(name):render(getfenv(2)) end;$/;" f +index ./luci/controller/api/index.lua /^function index()$/;" f +index ./luci/controller/api/xqdatacenter.lua /^function index()$/;" f +index ./luci/controller/api/xqnetdetect.lua /^function index()$/;" f +index ./luci/controller/api/xqnetwork.lua /^function index()$/;" f +index ./luci/controller/api/xqpassport.lua /^function index()$/;" f +index ./luci/controller/api/xqsmarthome.lua /^function index()$/;" f +index ./luci/controller/api/xqsystem.lua /^function index()$/;" f +index ./luci/controller/api/xqtunnel.lua /^function index()$/;" f +index ./luci/controller/dispatch/index.lua /^function index()$/;" f +index ./luci/controller/firewall.lua /^function index()$/;" f +index ./luci/controller/mobile/index.lua /^function index()$/;" f +index ./luci/controller/service/datacenter.lua /^function index()$/;" f +index ./luci/controller/service/index.lua /^function index()$/;" f +index ./luci/controller/web/index.lua /^function index()$/;" f +info ./luci/model/ipkg.lua /^function info(pkg)$/;" f +init ./luci/model/firewall.lua /^function init(cursor)$/;" f +init ./luci/model/network.lua /^function init(cursor)$/;" f +init.disable ./luci/sys.lua /^function init.disable(name)$/;" f +init.enable ./luci/sys.lua /^function init.enable(name)$/;" f +init.enabled ./luci/sys.lua /^function init.enabled(name)$/;" f +init.index ./luci/sys.lua /^function init.index(name)$/;" f +init.names ./luci/sys.lua /^function init.names()$/;" f +init.start ./luci/sys.lua /^function init.start(name)$/;" f +init.stop ./luci/sys.lua /^function init.stop(name)$/;" f +init_action ./luci/sys.lua /^local function init_action(action, name)$/;" f +inp.cfgvalue ./luci/model/cbi/firewall/zone-details.lua /^function inp.cfgvalue(self, section)$/;" f +inp.formvalue ./luci/model/cbi/firewall/zone-details.lua /^function inp.formvalue(self, section)$/;" f +inp.write ./luci/model/cbi/firewall/zone-details.lua /^function inp.write(self, section, value)$/;" f +install ./luci/model/ipkg.lua /^function install(...)$/;" f +installed ./luci/model/ipkg.lua /^function installed(pkg)$/;" f +instanceof ./luci/util.lua /^function instanceof(object, class)$/;" f +integer ./luci/cbi/datatypes.lua /^function integer(val)$/;" f +interface.__init__ ./luci/model/network.lua /^function interface.__init__(self, ifname, network)$/;" f +interface._ubus ./luci/model/network.lua /^function interface._ubus(self, field)$/;" f +interface.adminlink ./luci/model/network.lua /^function interface.adminlink(self)$/;" f +interface.bridge_id ./luci/model/network.lua /^function interface.bridge_id(self)$/;" f +interface.bridge_stp ./luci/model/network.lua /^function interface.bridge_stp(self)$/;" f +interface.get_i18n ./luci/model/network.lua /^function interface.get_i18n(self)$/;" f +interface.get_network ./luci/model/network.lua /^function interface.get_network(self)$/;" f +interface.get_networks ./luci/model/network.lua /^function interface.get_networks(self)$/;" f +interface.get_type_i18n ./luci/model/network.lua /^function interface.get_type_i18n(self)$/;" f +interface.get_wifinet ./luci/model/network.lua /^function interface.get_wifinet(self)$/;" f +interface.ip6addrs ./luci/model/network.lua /^function interface.ip6addrs(self)$/;" f +interface.ipaddrs ./luci/model/network.lua /^function interface.ipaddrs(self)$/;" f +interface.is_bridge ./luci/model/network.lua /^function interface.is_bridge(self)$/;" f +interface.is_bridgeport ./luci/model/network.lua /^function interface.is_bridgeport(self)$/;" f +interface.is_up ./luci/model/network.lua /^function interface.is_up(self)$/;" f +interface.mac ./luci/model/network.lua /^function interface.mac(self)$/;" f +interface.name ./luci/model/network.lua /^function interface.name(self)$/;" f +interface.ports ./luci/model/network.lua /^function interface.ports(self)$/;" f +interface.rx_bytes ./luci/model/network.lua /^function interface.rx_bytes(self)$/;" f +interface.rx_packets ./luci/model/network.lua /^function interface.rx_packets(self)$/;" f +interface.shortname ./luci/model/network.lua /^function interface.shortname(self)$/;" f +interface.tx_bytes ./luci/model/network.lua /^function interface.tx_bytes(self)$/;" f +interface.tx_packets ./luci/model/network.lua /^function interface.tx_packets(self)$/;" f +interface.type ./luci/model/network.lua /^function interface.type(self)$/;" f +ip4addr ./luci/cbi/datatypes.lua /^function ip4addr(val)$/;" f +ip4prefix ./luci/cbi/datatypes.lua /^function ip4prefix(val)$/;" f +ip6addr ./luci/cbi/datatypes.lua /^function ip6addr(val)$/;" f +ip6prefix ./luci/cbi/datatypes.lua /^function ip6prefix(val)$/;" f +ipSplit ./luci/view/web/setting/net_lan.htm /^function ipSplit(ip){$/;" f +ipaddr ./luci/cbi/datatypes.lua /^function ipaddr(val)$/;" f +ipnot ./luci/ip.lua /^function ipnot ( ip )$/;" f +iptonl ./luci/ip.lua /^function iptonl( ip )$/;" f +isArray ./json.lua /^function isArray(t)$/;" f +isChange ./luci/view/web/setting/wifi_set_pro.htm /^ function isChange(name){$/;" f +isDeviceWifiConnect ./xiaoqiang/util/XQWifiUtil.lua /^function isDeviceWifiConnect(mac,wifiIndex)$/;" f +isDropbearStarted ./luci/controller/api/xqsystem.lua /^function isDropbearStarted()$/;" f +isDropbearStarted ./luci/view/web/setting/lamp.htm /^ function isDropbearStarted(){$/;" f +isEncodable ./json.lua /^function isEncodable(o)$/;" f +isInternetConnect ./luci/controller/api/xqsystem.lua /^function isInternetConnect()$/;" f +isRunning ./xiaoqiang/util/XQCameraUtil.lua /^function isRunning()$/;" f +isSandboxCreated ./luci/controller/api/xqsystem.lua /^function isSandboxCreated()$/;" f +isSandboxCreated ./luci/view/web/setting/lamp.htm /^ function isSandboxCreated(){$/;" f +isStrNil ./xiaoqiang/common/XQFunction.lua /^function isStrNil(str)$/;" f +isUpgrading ./xiaoqiang/util/XQSysUtil.lua /^function isUpgrading()$/;" f +isalive ./xiaoqiang/util/XQMitvUtil.lua /^function isalive(ip)$/;" f +isdirectory ./luci/fs.lua /^function isdirectory(dirname)$/;" f +isfile ./luci/fs.lua /^function isfile(filename)$/;" f +keepalive_failure.cfgvalue ./luci/model/cbi/admin_network/proto_ppp.lua /^function keepalive_failure.cfgvalue(self, section)$/;" f +keepalive_failure.cfgvalue ./luci/model/cbi/admin_network/proto_pppoa.lua /^function keepalive_failure.cfgvalue(self, section)$/;" f +keepalive_failure.cfgvalue ./luci/model/cbi/admin_network/proto_pppoe.lua /^function keepalive_failure.cfgvalue(self, section)$/;" f +keepalive_failure.cfgvalue ./luci/model/cbi/admin_network/proto_pptp.lua /^function keepalive_failure.cfgvalue(self, section)$/;" f +keepalive_failure.remove ./luci/model/cbi/admin_network/proto_ppp.lua /^function keepalive_failure.remove() end$/;" f +keepalive_failure.remove ./luci/model/cbi/admin_network/proto_pppoa.lua /^function keepalive_failure.remove() end$/;" f +keepalive_failure.remove ./luci/model/cbi/admin_network/proto_pppoe.lua /^function keepalive_failure.remove() end$/;" f +keepalive_failure.remove ./luci/model/cbi/admin_network/proto_pptp.lua /^function keepalive_failure.remove() end$/;" f +keepalive_failure.write ./luci/model/cbi/admin_network/proto_ppp.lua /^function keepalive_failure.write() end$/;" f +keepalive_failure.write ./luci/model/cbi/admin_network/proto_pppoa.lua /^function keepalive_failure.write() end$/;" f +keepalive_failure.write ./luci/model/cbi/admin_network/proto_pppoe.lua /^function keepalive_failure.write() end$/;" f +keepalive_failure.write ./luci/model/cbi/admin_network/proto_pptp.lua /^function keepalive_failure.write() end$/;" f +keepalive_interval.cfgvalue ./luci/model/cbi/admin_network/proto_ppp.lua /^function keepalive_interval.cfgvalue(self, section)$/;" f +keepalive_interval.cfgvalue ./luci/model/cbi/admin_network/proto_pppoa.lua /^function keepalive_interval.cfgvalue(self, section)$/;" f +keepalive_interval.cfgvalue ./luci/model/cbi/admin_network/proto_pppoe.lua /^function keepalive_interval.cfgvalue(self, section)$/;" f +keepalive_interval.cfgvalue ./luci/model/cbi/admin_network/proto_pptp.lua /^function keepalive_interval.cfgvalue(self, section)$/;" f +keepalive_interval.write ./luci/model/cbi/admin_network/proto_ppp.lua /^function keepalive_interval.write(self, section, value)$/;" f +keepalive_interval.write ./luci/model/cbi/admin_network/proto_pppoa.lua /^function keepalive_interval.write(self, section, value)$/;" f +keepalive_interval.write ./luci/model/cbi/admin_network/proto_pppoe.lua /^function keepalive_interval.write(self, section, value)$/;" f +keepalive_interval.write ./luci/model/cbi/admin_network/proto_pptp.lua /^function keepalive_interval.write(self, section, value)$/;" f +keyGeneration ./rc4.lua /^local function keyGeneration(state, nCount)$/;" f +keys ./luci/util.lua /^function keys(t)$/;" f +kill ./luci/sauth.lua /^function kill(id)$/;" f +kspairs ./luci/util.lua /^function kspairs(t)$/;" f +lanIPChange ./xiaoqiang/XQEvent.lua /^function lanIPChange(ip)$/;" f +ledFlashAlert ./xiaoqiang/common/XQFunction.lua /^function ledFlashAlert(enable)$/;" f +libpath ./luci/util.lua /^function libpath()$/;" f +limitsource ./luci/sgi/cgi.lua /^local function limitsource(handle, limit)$/;" f +link ./luci/fs.lua /^function link(src, dest, sym)$/;" f +list ./luci/cbi/datatypes.lua /^function list(v, subvalidator, subargs)$/;" f +list_all ./luci/model/ipkg.lua /^function list_all(pat, cb)$/;" f +list_installed ./luci/model/ipkg.lua /^function list_installed(pat, cb)$/;" f +listenStatus ./luci/view/web/setting/vpn.htm /^ function listenStatus(){$/;" f +listlocaldir ./xiaoqiang/util/XQCameraUtil.lua /^function listlocaldir(path)$/;" f +load ./luci/cbi.lua /^function load(cbimap, ...)$/;" f +load ./luci/i18n.lua /^function load(file, lang, force)$/;" f +loadavg ./luci/sys.lua /^function loadavg()$/;" f +loadc ./luci/i18n.lua /^function loadc(file, force)$/;" f +local _template ./luci/dispatcher.lua /^local _template = function(self, ...)$/;" f +local a ./luci/json.lua /^ local a = ActiveDecoder(function() return nil end, ...)$/;" f +local authen ./luci/dispatcher.lua /^ local authen = type(track.sysauth_authenticator) == "function"$/;" f +local checkstep ./socket/ftp.lua /^ local checkstep = function(src, snk)$/;" f +local co ./socket/smtp.lua /^ local co = coroutine.create(function() send_message(mesgt) end)$/;" f +local entitySwap ./slaxml.lua /^ local entitySwap = function(orig,n,s) return entityMap[s] or n=="#" and char(s) or orig end$/;" f +local f ./ltn12.lua /^ local f = function(chunk, err)$/;" f +local f ./luci/ltn12.lua /^ local f = function(chunk, err)$/;" f +local newf ./luci/util.lua /^ local newf = function() return f(unpack(params)) end$/;" f +local openFileLogger ./logging/file.lua /^local openFileLogger = function (filename, datePattern)$/;" f +local openRollingFileLogger ./logging/rolling_file.lua /^local openRollingFileLogger = function (self)$/;" f +local proto, off ./luci/util.lua /^ local proto, off = strip_function(code:sub(offset, -1))$/;" f +local rollOver ./logging/rolling_file.lua /^local rollOver = function (self)$/;" f +local stat, err ./luci/dispatcher.lua /^ local stat, err = util.coxpcall(function()$/;" f +log ./xiaoqiang/XQLog.lua /^function log(...)$/;" f +logCollection ./luci/view/web/setting/log.htm /^ function logCollection() {$/;" f +logger ./sysapi/miqos.lua /^function logger(loglevel,msg)$/;" f +logger.log ./logging.lua /^ logger.log = function (self, level, ...)$/;" f +logger.setLevel ./logging.lua /^ logger.setLevel = function (self, level)$/;" f +logging.console ./logging/console.lua /^function logging.console(logPattern)$/;" f +logging.email ./logging/email.lua /^function logging.email(params)$/;" f +logging.file ./logging/file.lua /^function logging.file(filename, datePattern, logPattern)$/;" f +logging.new ./logging.lua /^function logging.new(append)$/;" f +logging.prepareLogMsg ./logging.lua /^function logging.prepareLogMsg(pattern, dt, level, message)$/;" f +logging.rolling_file ./logging/rolling_file.lua /^function logging.rolling_file(filename, maxFileSize, maxBackupIndex, logPattern)$/;" f +logging.socket ./logging/socket.lua /^function logging.socket(address, port, logPattern)$/;" f +logging.sql ./logging/sql.lua /^function logging.sql(params)$/;" f +logout ./luci/view/web/plugins/kuaipan.htm /^ function logout() {$/;" f +lower_headers ./socket/smtp.lua /^local function lower_headers(headers)$/;" f +m.on_commit ./luci/model/cbi/firewall/zone-details.lua /^m.on_commit = function(map)$/;" f +macBind ./luci/controller/api/xqnetwork.lua /^function macBind()$/;" f +macBindInfo ./xiaoqiang/util/XQLanWanUtil.lua /^function macBindInfo()$/;" f +macFormat ./xiaoqiang/common/XQFunction.lua /^function macFormat(mac)$/;" f +macUnbind ./luci/controller/api/xqnetwork.lua /^function macUnbind()$/;" f +macaddr ./luci/cbi/datatypes.lua /^function macaddr(val)$/;" f +main ./sysapi/miqos.lua /^function main()$/;" f +mainStatusForApp ./luci/controller/api/xqsystem.lua /^function mainStatusForApp()$/;" f +make_set ./socket/url.lua /^local function make_set(t)$/;" f +match.cfgvalue ./luci/model/cbi/firewall/forwards.lua /^function match.cfgvalue(self, s)$/;" f +match.cfgvalue ./luci/model/cbi/firewall/rules.lua /^function match.cfgvalue(self, s)$/;" f +max ./luci/cbi/datatypes.lua /^function max(val, max)$/;" f +maxlength ./luci/cbi/datatypes.lua /^function maxlength(val, max)$/;" f +md5Base64Str ./xiaoqiang/util/XQCryptoUtil.lua /^function md5Base64Str(str)$/;" f +md5File ./xiaoqiang/util/XQCryptoUtil.lua /^function md5File(file)$/;" f +md5Str ./xiaoqiang/util/XQCryptoUtil.lua /^function md5Str(str)$/;" f +mergeFiles ./xiaoqiang/util/XQCameraUtil.lua /^function mergeFiles(remotefiles,localfiles)$/;" f +message ./socket/smtp.lua /^function message(mesgt)$/;" f +meta.blocksource ./nixio/util.lua /^function meta.blocksource(self, bs, limit)$/;" f +meta.copy ./nixio/util.lua /^function meta.copy(self, fdout, size)$/;" f +meta.copyz ./nixio/util.lua /^function meta.copyz(self, fd, size)$/;" f +meta.is_file ./nixio/util.lua /^function meta.is_file(self)$/;" f +meta.is_socket ./nixio/util.lua /^function meta.is_socket(self)$/;" f +meta.is_tls_socket ./nixio/util.lua /^function meta.is_tls_socket(self)$/;" f +meta.linesource ./nixio/util.lua /^function meta.linesource(self, limit)$/;" f +meta.readall ./nixio/util.lua /^function meta.readall(self, len)$/;" f +meta.sink ./nixio/util.lua /^function meta.sink(self, close)$/;" f +meta.writeall ./nixio/util.lua /^function meta.writeall(self, data)$/;" f +metat.__index:auth ./socket/smtp.lua /^function metat.__index:auth(user, password, ext)$/;" f +metat.__index:check ./socket/tp.lua /^function metat.__index:check(ok)$/;" f +metat.__index:close ./socket/ftp.lua /^function metat.__index:close()$/;" f +metat.__index:close ./socket/http.lua /^function metat.__index:close()$/;" f +metat.__index:close ./socket/smtp.lua /^function metat.__index:close()$/;" f +metat.__index:close ./socket/tp.lua /^function metat.__index:close()$/;" f +metat.__index:command ./socket/tp.lua /^function metat.__index:command(cmd, arg)$/;" f +metat.__index:cwd ./socket/ftp.lua /^function metat.__index:cwd(dir)$/;" f +metat.__index:data ./socket/smtp.lua /^function metat.__index:data(src, step)$/;" f +metat.__index:dirty ./socket/tp.lua /^function metat.__index:dirty()$/;" f +metat.__index:getcontrol ./socket/tp.lua /^function metat.__index:getcontrol()$/;" f +metat.__index:getfd ./socket/tp.lua /^function metat.__index:getfd()$/;" f +metat.__index:greet ./socket/ftp.lua /^function metat.__index:greet()$/;" f +metat.__index:greet ./socket/smtp.lua /^function metat.__index:greet(domain)$/;" f +metat.__index:login ./socket/ftp.lua /^function metat.__index:login(user, password)$/;" f +metat.__index:login ./socket/smtp.lua /^function metat.__index:login(user, password)$/;" f +metat.__index:mail ./socket/smtp.lua /^function metat.__index:mail(from)$/;" f +metat.__index:pasv ./socket/ftp.lua /^function metat.__index:pasv()$/;" f +metat.__index:pasvconnect ./socket/ftp.lua /^function metat.__index:pasvconnect()$/;" f +metat.__index:plain ./socket/smtp.lua /^function metat.__index:plain(user, password)$/;" f +metat.__index:port ./socket/ftp.lua /^function metat.__index:port(ip, port)$/;" f +metat.__index:portconnect ./socket/ftp.lua /^function metat.__index:portconnect()$/;" f +metat.__index:quit ./socket/ftp.lua /^function metat.__index:quit()$/;" f +metat.__index:quit ./socket/smtp.lua /^function metat.__index:quit()$/;" f +metat.__index:rcpt ./socket/smtp.lua /^function metat.__index:rcpt(to)$/;" f +metat.__index:receive ./socket/ftp.lua /^function metat.__index:receive(recvt)$/;" f +metat.__index:receive ./socket/tp.lua /^function metat.__index:receive(pat)$/;" f +metat.__index:receive09body ./socket/http.lua /^function metat.__index:receive09body(status, sink, step)$/;" f +metat.__index:receivebody ./socket/http.lua /^function metat.__index:receivebody(headers, sink, step)$/;" f +metat.__index:receiveheaders ./socket/http.lua /^function metat.__index:receiveheaders()$/;" f +metat.__index:receivestatusline ./socket/http.lua /^function metat.__index:receivestatusline()$/;" f +metat.__index:send ./socket/ftp.lua /^function metat.__index:send(sendt)$/;" f +metat.__index:send ./socket/smtp.lua /^function metat.__index:send(mailt)$/;" f +metat.__index:send ./socket/tp.lua /^function metat.__index:send(data)$/;" f +metat.__index:sendbody ./socket/http.lua /^function metat.__index:sendbody(headers, source, step)$/;" f +metat.__index:sendheaders ./socket/http.lua /^function metat.__index:sendheaders(headers)$/;" f +metat.__index:sendrequestline ./socket/http.lua /^function metat.__index:sendrequestline(method, uri)$/;" f +metat.__index:sink ./socket/tp.lua /^function metat.__index:sink(snk, pat)$/;" f +metat.__index:source ./socket/tp.lua /^function metat.__index:source(source, step)$/;" f +metat.__index:type ./socket/ftp.lua /^function metat.__index:type(type)$/;" f +mimedecode_message_body ./luci/http/protocol.lua /^function mimedecode_message_body( src, msg, filecb )$/;" f +min ./luci/cbi/datatypes.lua /^function min(val, min)$/;" f +minlength ./luci/cbi/datatypes.lua /^function minlength(val, min)$/;" f +mk_etag ./luci/http/protocol/conditionals.lua /^function mk_etag( stat )$/;" f +mkdir ./luci/fs.lua /^function mkdir(path, recursive)$/;" f +mkdirr ./nixio/fs.lua /^function mkdirr(dest, mode)$/;" f +modifier ./luci/dispatcher.lua /^function modifier(func, order)$/;" f +modify ./luci/view/web/setting/wifi_set_mini.htm /^ function modify (){$/;" f +modify ./luci/view/web/setting/wifi_set_pro.htm /^ function modify (){$/;" f +modisort ./luci/dispatcher.lua /^ local function modisort(a,b)$/;" f +module ("nixio.fs", function(m) setmetatable(m, {__index ./nixio/fs.lua /^module ("nixio.fs", function(m) setmetatable(m, {__index = nixio.fs}) end)$/;" f +moduleOn ./xiaoqiang/module/XQDMZModule.lua /^function moduleOn()$/;" f +moduleOn ./xiaoqiang/module/XQPortForward.lua /^function moduleOn()$/;" f +mountThings ./luci/controller/api/xqsystem.lua /^function mountThings()$/;" f +mountThings ./luci/view/web/setting/lamp.htm /^ function mountThings(){$/;" f +mounts ./luci/sys.lua /^function mounts()$/;" f +move ./nixio/fs.lua /^function move(src, dest)$/;" f +mover ./nixio/fs.lua /^function mover(src, dest)$/;" f +mtime ./luci/fs.lua /^function mtime(path)$/;" f +name.write ./luci/model/cbi/firewall/zone-details.lua /^function name.write(self, section, value)$/;" f +navigation ./luci/view/themes/openwrt.org/header.htm /^