mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-03-09 15:40:03 +00:00
Update luci and theme
This commit is contained in:
parent
fe03553aae
commit
4d7962337f
165 changed files with 74180 additions and 13802 deletions
|
@ -14,13 +14,17 @@ LUCI_BASENAME:=base
|
|||
LUCI_TITLE:=LuCI core libraries
|
||||
LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua
|
||||
|
||||
LUCI_LUASRCDIET_VERSION:=1.0.0
|
||||
|
||||
PKG_SOURCE:=v1.0.0.tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/jirutka/luasrcdiet/archive/
|
||||
PKG_HASH:=48162e63e77d009f5848f18a5cabffbdfc867d0e5e73c6d407f6af5d6880151b
|
||||
PKG_SOURCE_URL:=https://github.com/jirutka/luasrcdiet.git
|
||||
PKG_SOURCE_VERSION:=f138fc9359821d9201cd6b57cfa2fcbed5b9af97
|
||||
PKG_SOURCE_SUBDIR:=luasrcdiet-$(LUCI_LUASRCDIET_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
|
||||
PKG_MIRROR_HASH:=a5c9d098549fbef618e6022b701e66c8c6fb16c910e63219adad3a4e71341f72
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/luasrcdiet-1.0.0
|
||||
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_SOURCE_SUBDIR)
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
|
||||
|
@ -36,13 +40,14 @@ define Host/Configure
|
|||
endef
|
||||
|
||||
define Host/Compile
|
||||
$(MAKE) -C src/ clean po2lmo
|
||||
$(MAKE) -C src/ clean po2lmo jsmin
|
||||
endef
|
||||
|
||||
define Host/Install
|
||||
$(INSTALL_DIR) $(1)/bin
|
||||
$(INSTALL_DIR) $(1)/lib/lua/5.1
|
||||
$(INSTALL_BIN) src/po2lmo $(1)/bin/po2lmo
|
||||
$(INSTALL_BIN) src/jsmin $(1)/bin/jsmin
|
||||
$(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/luasrcdiet $(1)/bin/luasrcdiet
|
||||
$(CP) $(HOST_BUILD_DIR)/luasrcdiet $(1)/lib/lua/5.1/
|
||||
endef
|
||||
|
|
File diff suppressed because it is too large
Load diff
511
luci-base/htdocs/luci-static/resources/luci.js
Normal file
511
luci-base/htdocs/luci-static/resources/luci.js
Normal file
|
@ -0,0 +1,511 @@
|
|||
(function(window, document, undefined) {
|
||||
var modalDiv = null,
|
||||
tooltipDiv = null,
|
||||
tooltipTimeout = null,
|
||||
dummyElem = null,
|
||||
domParser = null;
|
||||
|
||||
LuCI.prototype = {
|
||||
/* URL construction helpers */
|
||||
path: function(prefix, parts) {
|
||||
var url = [ prefix || '' ];
|
||||
|
||||
for (var i = 0; i < parts.length; i++)
|
||||
if (/^(?:[a-zA-Z0-9_.%,;-]+\/)*[a-zA-Z0-9_.%,;-]+$/.test(parts[i]))
|
||||
url.push('/', parts[i]);
|
||||
|
||||
if (url.length === 1)
|
||||
url.push('/');
|
||||
|
||||
return url.join('');
|
||||
},
|
||||
|
||||
url: function() {
|
||||
return this.path(this.env.scriptname, arguments);
|
||||
},
|
||||
|
||||
resource: function() {
|
||||
return this.path(this.env.resource, arguments);
|
||||
},
|
||||
|
||||
location: function() {
|
||||
return this.path(this.env.scriptname, this.env.requestpath);
|
||||
},
|
||||
|
||||
|
||||
/* HTTP resource fetching */
|
||||
get: function(url, args, cb) {
|
||||
return this.poll(0, url, args, cb, false);
|
||||
},
|
||||
|
||||
post: function(url, args, cb) {
|
||||
return this.poll(0, url, args, cb, true);
|
||||
},
|
||||
|
||||
poll: function(interval, url, args, cb, post) {
|
||||
var data = post ? { token: this.env.token } : null;
|
||||
|
||||
if (!/^(?:\/|\S+:\/\/)/.test(url))
|
||||
url = this.url(url);
|
||||
|
||||
if (typeof(args) === 'object' && args !== null) {
|
||||
data = data || {};
|
||||
|
||||
for (var key in args)
|
||||
if (args.hasOwnProperty(key))
|
||||
switch (typeof(args[key])) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
data[key] = args[key];
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
data[key] = JSON.stringify(args[key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (interval > 0)
|
||||
return XHR.poll(interval, url, data, cb, post);
|
||||
else if (post)
|
||||
return XHR.post(url, data, cb);
|
||||
else
|
||||
return XHR.get(url, data, cb);
|
||||
},
|
||||
|
||||
stop: function(entry) { XHR.stop(entry) },
|
||||
halt: function() { XHR.halt() },
|
||||
run: function() { XHR.run() },
|
||||
|
||||
|
||||
/* Modal dialog */
|
||||
showModal: function(title, children) {
|
||||
var dlg = modalDiv.firstElementChild;
|
||||
|
||||
dlg.setAttribute('class', 'modal');
|
||||
|
||||
this.dom.content(dlg, this.dom.create('h4', {}, title));
|
||||
this.dom.append(dlg, children);
|
||||
|
||||
document.body.classList.add('modal-overlay-active');
|
||||
|
||||
return dlg;
|
||||
},
|
||||
|
||||
hideModal: function() {
|
||||
document.body.classList.remove('modal-overlay-active');
|
||||
},
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
showTooltip: function(ev) {
|
||||
var target = findParent(ev.target, '[data-tooltip]');
|
||||
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (tooltipTimeout !== null) {
|
||||
window.clearTimeout(tooltipTimeout);
|
||||
tooltipTimeout = null;
|
||||
}
|
||||
|
||||
var rect = target.getBoundingClientRect(),
|
||||
x = rect.left + window.pageXOffset,
|
||||
y = rect.top + rect.height + window.pageYOffset;
|
||||
|
||||
tooltipDiv.className = 'cbi-tooltip';
|
||||
tooltipDiv.innerHTML = '▲ ';
|
||||
tooltipDiv.firstChild.data += target.getAttribute('data-tooltip');
|
||||
|
||||
if (target.hasAttribute('data-tooltip-style'))
|
||||
tooltipDiv.classList.add(target.getAttribute('data-tooltip-style'));
|
||||
|
||||
if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) {
|
||||
y -= (tooltipDiv.offsetHeight + target.offsetHeight);
|
||||
tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(2);
|
||||
}
|
||||
|
||||
tooltipDiv.style.top = y + 'px';
|
||||
tooltipDiv.style.left = x + 'px';
|
||||
tooltipDiv.style.opacity = 1;
|
||||
|
||||
tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', {
|
||||
bubbles: true,
|
||||
detail: { target: target }
|
||||
}));
|
||||
},
|
||||
|
||||
hideTooltip: function(ev) {
|
||||
if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv ||
|
||||
tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget))
|
||||
return;
|
||||
|
||||
if (tooltipTimeout !== null) {
|
||||
window.clearTimeout(tooltipTimeout);
|
||||
tooltipTimeout = null;
|
||||
}
|
||||
|
||||
tooltipDiv.style.opacity = 0;
|
||||
tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
|
||||
|
||||
tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true }));
|
||||
},
|
||||
|
||||
|
||||
/* Widget helper */
|
||||
itemlist: function(node, items, separators) {
|
||||
var children = [];
|
||||
|
||||
if (!Array.isArray(separators))
|
||||
separators = [ separators || E('br') ];
|
||||
|
||||
for (var i = 0; i < items.length; i += 2) {
|
||||
if (items[i+1] !== null && items[i+1] !== undefined) {
|
||||
var sep = separators[(i/2) % separators.length],
|
||||
cld = [];
|
||||
|
||||
children.push(E('span', { class: 'nowrap' }, [
|
||||
items[i] ? E('strong', items[i] + ': ') : '',
|
||||
items[i+1]
|
||||
]));
|
||||
|
||||
if ((i+2) < items.length)
|
||||
children.push(this.dom.elem(sep) ? sep.cloneNode(true) : sep);
|
||||
}
|
||||
}
|
||||
|
||||
this.dom.content(node, children);
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
/* Tabs */
|
||||
LuCI.prototype.tabs = {
|
||||
init: function() {
|
||||
var groups = [], prevGroup = null, currGroup = null;
|
||||
|
||||
document.querySelectorAll('[data-tab]').forEach(function(tab) {
|
||||
var parent = tab.parentNode;
|
||||
|
||||
if (!parent.hasAttribute('data-tab-group'))
|
||||
parent.setAttribute('data-tab-group', groups.length);
|
||||
|
||||
currGroup = +parent.getAttribute('data-tab-group');
|
||||
|
||||
if (currGroup !== prevGroup) {
|
||||
prevGroup = currGroup;
|
||||
|
||||
if (!groups[currGroup])
|
||||
groups[currGroup] = [];
|
||||
}
|
||||
|
||||
groups[currGroup].push(tab);
|
||||
});
|
||||
|
||||
for (var i = 0; i < groups.length; i++)
|
||||
this.initTabGroup(groups[i]);
|
||||
|
||||
document.addEventListener('dependency-update', this.updateTabs.bind(this));
|
||||
|
||||
this.updateTabs();
|
||||
|
||||
if (!groups.length)
|
||||
this.setActiveTabId(-1, -1);
|
||||
},
|
||||
|
||||
initTabGroup: function(panes) {
|
||||
if (!Array.isArray(panes) || panes.length === 0)
|
||||
return;
|
||||
|
||||
var menu = E('ul', { 'class': 'cbi-tabmenu' }),
|
||||
group = panes[0].parentNode,
|
||||
groupId = +group.getAttribute('data-tab-group'),
|
||||
selected = null;
|
||||
|
||||
for (var i = 0, pane; pane = panes[i]; i++) {
|
||||
var name = pane.getAttribute('data-tab'),
|
||||
title = pane.getAttribute('data-tab-title'),
|
||||
active = pane.getAttribute('data-tab-active') === 'true';
|
||||
|
||||
menu.appendChild(E('li', {
|
||||
'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
|
||||
'data-tab': name
|
||||
}, E('a', {
|
||||
'href': '#',
|
||||
'click': this.switchTab.bind(this)
|
||||
}, title)));
|
||||
|
||||
if (active)
|
||||
selected = i;
|
||||
}
|
||||
|
||||
group.parentNode.insertBefore(menu, group);
|
||||
|
||||
if (selected === null) {
|
||||
selected = this.getActiveTabId(groupId);
|
||||
|
||||
if (selected < 0 || selected >= panes.length)
|
||||
selected = 0;
|
||||
|
||||
menu.childNodes[selected].classList.add('cbi-tab');
|
||||
menu.childNodes[selected].classList.remove('cbi-tab-disabled');
|
||||
panes[selected].setAttribute('data-tab-active', 'true');
|
||||
|
||||
this.setActiveTabId(groupId, selected);
|
||||
}
|
||||
},
|
||||
|
||||
getActiveTabState: function() {
|
||||
var page = document.body.getAttribute('data-page');
|
||||
|
||||
try {
|
||||
var val = JSON.parse(window.sessionStorage.getItem('tab'));
|
||||
if (val.page === page && Array.isArray(val.groups))
|
||||
return val;
|
||||
}
|
||||
catch(e) {}
|
||||
|
||||
window.sessionStorage.removeItem('tab');
|
||||
return { page: page, groups: [] };
|
||||
},
|
||||
|
||||
getActiveTabId: function(groupId) {
|
||||
return +this.getActiveTabState().groups[groupId] || 0;
|
||||
},
|
||||
|
||||
setActiveTabId: function(groupId, tabIndex) {
|
||||
try {
|
||||
var state = this.getActiveTabState();
|
||||
state.groups[groupId] = tabIndex;
|
||||
|
||||
window.sessionStorage.setItem('tab', JSON.stringify(state));
|
||||
}
|
||||
catch (e) { return false; }
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
updateTabs: function(ev) {
|
||||
document.querySelectorAll('[data-tab-title]').forEach(function(pane) {
|
||||
var menu = pane.parentNode.previousElementSibling,
|
||||
tab = menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))),
|
||||
n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
|
||||
|
||||
if (!pane.firstElementChild) {
|
||||
tab.style.display = 'none';
|
||||
tab.classList.remove('flash');
|
||||
}
|
||||
else if (tab.style.display === 'none') {
|
||||
tab.style.display = '';
|
||||
requestAnimationFrame(function() { tab.classList.add('flash') });
|
||||
}
|
||||
|
||||
if (n_errors) {
|
||||
tab.setAttribute('data-errors', n_errors);
|
||||
tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors));
|
||||
tab.setAttribute('data-tooltip-style', 'error');
|
||||
}
|
||||
else {
|
||||
tab.removeAttribute('data-errors');
|
||||
tab.removeAttribute('data-tooltip');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
switchTab: function(ev) {
|
||||
var tab = ev.target.parentNode,
|
||||
name = tab.getAttribute('data-tab'),
|
||||
menu = tab.parentNode,
|
||||
group = menu.nextElementSibling,
|
||||
groupId = +group.getAttribute('data-tab-group'),
|
||||
index = 0;
|
||||
|
||||
ev.preventDefault();
|
||||
|
||||
if (!tab.classList.contains('cbi-tab-disabled'))
|
||||
return;
|
||||
|
||||
menu.querySelectorAll('[data-tab]').forEach(function(tab) {
|
||||
tab.classList.remove('cbi-tab');
|
||||
tab.classList.remove('cbi-tab-disabled');
|
||||
tab.classList.add(
|
||||
tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled');
|
||||
});
|
||||
|
||||
group.childNodes.forEach(function(pane) {
|
||||
if (L.dom.matches(pane, '[data-tab]')) {
|
||||
if (pane.getAttribute('data-tab') === name) {
|
||||
pane.setAttribute('data-tab-active', 'true');
|
||||
L.tabs.setActiveTabId(groupId, index);
|
||||
}
|
||||
else {
|
||||
pane.setAttribute('data-tab-active', 'false');
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/* DOM manipulation */
|
||||
LuCI.prototype.dom = {
|
||||
elem: function(e) {
|
||||
return (typeof(e) === 'object' && e !== null && 'nodeType' in e);
|
||||
},
|
||||
|
||||
parse: function(s) {
|
||||
var elem;
|
||||
|
||||
try {
|
||||
domParser = domParser || new DOMParser();
|
||||
elem = domParser.parseFromString(s, 'text/html').body.firstChild;
|
||||
}
|
||||
catch(e) {}
|
||||
|
||||
if (!elem) {
|
||||
try {
|
||||
dummyElem = dummyElem || document.createElement('div');
|
||||
dummyElem.innerHTML = s;
|
||||
elem = dummyElem.firstChild;
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
return elem || null;
|
||||
},
|
||||
|
||||
matches: function(node, selector) {
|
||||
var m = this.elem(node) ? node.matches || node.msMatchesSelector : null;
|
||||
return m ? m.call(node, selector) : false;
|
||||
},
|
||||
|
||||
parent: function(node, selector) {
|
||||
if (this.elem(node) && node.closest)
|
||||
return node.closest(selector);
|
||||
|
||||
while (this.elem(node))
|
||||
if (this.matches(node, selector))
|
||||
return node;
|
||||
else
|
||||
node = node.parentNode;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
append: function(node, children) {
|
||||
if (!this.elem(node))
|
||||
return null;
|
||||
|
||||
if (Array.isArray(children)) {
|
||||
for (var i = 0; i < children.length; i++)
|
||||
if (this.elem(children[i]))
|
||||
node.appendChild(children[i]);
|
||||
else if (children !== null && children !== undefined)
|
||||
node.appendChild(document.createTextNode('' + children[i]));
|
||||
|
||||
return node.lastChild;
|
||||
}
|
||||
else if (typeof(children) === 'function') {
|
||||
return this.append(node, children(node));
|
||||
}
|
||||
else if (this.elem(children)) {
|
||||
return node.appendChild(children);
|
||||
}
|
||||
else if (children !== null && children !== undefined) {
|
||||
node.innerHTML = '' + children;
|
||||
return node.lastChild;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
content: function(node, children) {
|
||||
if (!this.elem(node))
|
||||
return null;
|
||||
|
||||
while (node.firstChild)
|
||||
node.removeChild(node.firstChild);
|
||||
|
||||
return this.append(node, children);
|
||||
},
|
||||
|
||||
attr: function(node, key, val) {
|
||||
if (!this.elem(node))
|
||||
return null;
|
||||
|
||||
var attr = null;
|
||||
|
||||
if (typeof(key) === 'object' && key !== null)
|
||||
attr = key;
|
||||
else if (typeof(key) === 'string')
|
||||
attr = {}, attr[key] = val;
|
||||
|
||||
for (key in attr) {
|
||||
if (!attr.hasOwnProperty(key) || attr[key] === null || attr[key] === undefined)
|
||||
continue;
|
||||
|
||||
switch (typeof(attr[key])) {
|
||||
case 'function':
|
||||
node.addEventListener(key, attr[key]);
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
node.setAttribute(key, JSON.stringify(attr[key]));
|
||||
break;
|
||||
|
||||
default:
|
||||
node.setAttribute(key, attr[key]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
create: function() {
|
||||
var html = arguments[0],
|
||||
attr = (arguments[1] instanceof Object && !Array.isArray(arguments[1])) ? arguments[1] : null,
|
||||
data = attr ? arguments[2] : arguments[1],
|
||||
elem;
|
||||
|
||||
if (this.elem(html))
|
||||
elem = html;
|
||||
else if (html.charCodeAt(0) === 60)
|
||||
elem = this.parse(html);
|
||||
else
|
||||
elem = document.createElement(html);
|
||||
|
||||
if (!elem)
|
||||
return null;
|
||||
|
||||
this.attr(elem, attr);
|
||||
this.append(elem, data);
|
||||
|
||||
return elem;
|
||||
}
|
||||
};
|
||||
|
||||
/* Setup */
|
||||
LuCI.prototype.setupDOM = function(ev) {
|
||||
this.tabs.init();
|
||||
};
|
||||
|
||||
function LuCI(env) {
|
||||
this.env = env;
|
||||
|
||||
modalDiv = document.body.appendChild(
|
||||
this.dom.create('div', { id: 'modal_overlay' },
|
||||
this.dom.create('div', { class: 'modal', role: 'dialog', 'aria-modal': true })));
|
||||
|
||||
tooltipDiv = document.body.appendChild(this.dom.create('div', { class: 'cbi-tooltip' }));
|
||||
|
||||
document.addEventListener('mouseover', this.showTooltip.bind(this), true);
|
||||
document.addEventListener('mouseout', this.hideTooltip.bind(this), true);
|
||||
document.addEventListener('focus', this.showTooltip.bind(this), true);
|
||||
document.addEventListener('blur', this.hideTooltip.bind(this), true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', this.setupDOM.bind(this));
|
||||
}
|
||||
|
||||
window.LuCI = LuCI;
|
||||
})(window, document);
|
|
@ -1,24 +1,65 @@
|
|||
/*
|
||||
* xhr.js - XMLHttpRequest helper class
|
||||
* (c) 2008-2010 Jo-Philipp Wich
|
||||
* (c) 2008-2018 Jo-Philipp Wich <jo@mein.io>
|
||||
*/
|
||||
|
||||
XHR = function()
|
||||
{
|
||||
this.reinit = function()
|
||||
{
|
||||
if (window.XMLHttpRequest) {
|
||||
this._xmlHttp = new XMLHttpRequest();
|
||||
}
|
||||
else if (window.ActiveXObject) {
|
||||
this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
else {
|
||||
alert("xhr.js: XMLHttpRequest is not supported by this browser!");
|
||||
}
|
||||
}
|
||||
XHR.prototype = {
|
||||
_encode: function(obj) {
|
||||
obj = obj ? obj : { };
|
||||
obj['_'] = Math.random();
|
||||
|
||||
this.busy = function() {
|
||||
if (typeof obj == 'object') {
|
||||
var code = '';
|
||||
var self = this;
|
||||
|
||||
for (var k in obj)
|
||||
code += (code ? '&' : '') +
|
||||
k + '=' + encodeURIComponent(obj[k]);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
_response: function(callback, ts) {
|
||||
if (this._xmlHttp.readyState !== 4)
|
||||
return;
|
||||
|
||||
var status = this._xmlHttp.status,
|
||||
login = this._xmlHttp.getResponseHeader("X-LuCI-Login-Required"),
|
||||
type = this._xmlHttp.getResponseHeader("Content-Type"),
|
||||
json = null;
|
||||
|
||||
if (status === 403 && login === 'yes') {
|
||||
XHR.halt();
|
||||
|
||||
showModal(_('Session expired'), [
|
||||
E('div', { class: 'alert-message warning' },
|
||||
_('A new login is required since the authentication session expired.')),
|
||||
E('div', { class: 'right' },
|
||||
E('div', {
|
||||
class: 'btn primary',
|
||||
click: function() {
|
||||
var loc = window.location;
|
||||
window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search;
|
||||
}
|
||||
}, _('To login…')))
|
||||
]);
|
||||
}
|
||||
else if (type && type.toLowerCase().match(/^application\/json\b/)) {
|
||||
try {
|
||||
json = JSON.parse(this._xmlHttp.responseText);
|
||||
}
|
||||
catch(e) {
|
||||
json = null;
|
||||
}
|
||||
}
|
||||
|
||||
callback(this._xmlHttp, json, Date.now() - ts);
|
||||
},
|
||||
|
||||
busy: function() {
|
||||
if (!this._xmlHttp)
|
||||
return false;
|
||||
|
||||
|
@ -32,20 +73,18 @@ XHR = function()
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.abort = function() {
|
||||
abort: function() {
|
||||
if (this.busy())
|
||||
this._xmlHttp.abort();
|
||||
}
|
||||
},
|
||||
|
||||
this.get = function(url,data,callback,timeout)
|
||||
{
|
||||
this.reinit();
|
||||
get: function(url, data, callback, timeout) {
|
||||
this._xmlHttp = new XMLHttpRequest();
|
||||
|
||||
var ts = Date.now();
|
||||
var xhr = this._xmlHttp;
|
||||
var code = this._encode(data);
|
||||
var xhr = this._xmlHttp,
|
||||
code = this._encode(data);
|
||||
|
||||
url = location.protocol + '//' + location.host + url;
|
||||
|
||||
|
@ -60,83 +99,51 @@ XHR = function()
|
|||
if (!isNaN(timeout))
|
||||
xhr.timeout = timeout;
|
||||
|
||||
xhr.onreadystatechange = function()
|
||||
{
|
||||
if (xhr.readyState == 4) {
|
||||
var json = null;
|
||||
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
||||
try { json = JSON.parse(xhr.responseText); }
|
||||
catch(e) { json = null; }
|
||||
}
|
||||
|
||||
callback(xhr, json, Date.now() - ts);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = this._response.bind(this, callback, Date.now());
|
||||
xhr.send(null);
|
||||
}
|
||||
},
|
||||
|
||||
this.post = function(url,data,callback,timeout)
|
||||
{
|
||||
this.reinit();
|
||||
post: function(url, data, callback, timeout) {
|
||||
this._xmlHttp = new XMLHttpRequest();
|
||||
|
||||
var ts = Date.now();
|
||||
var xhr = this._xmlHttp;
|
||||
var code = this._encode(data);
|
||||
|
||||
xhr.onreadystatechange = function()
|
||||
{
|
||||
if (xhr.readyState == 4) {
|
||||
var json = null;
|
||||
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
||||
try { json = JSON.parse(xhr.responseText); }
|
||||
catch(e) { json = null; }
|
||||
}
|
||||
|
||||
callback(xhr, json, Date.now() - ts);
|
||||
}
|
||||
}
|
||||
var xhr = this._xmlHttp,
|
||||
code = this._encode(data);
|
||||
|
||||
xhr.open('POST', url, true);
|
||||
|
||||
if (!isNaN(timeout))
|
||||
xhr.timeout = timeout;
|
||||
|
||||
xhr.onreadystatechange = this._response.bind(this, callback, Date.now());
|
||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(code);
|
||||
}
|
||||
},
|
||||
|
||||
this.cancel = function()
|
||||
{
|
||||
this._xmlHttp.onreadystatechange = function(){};
|
||||
cancel: function() {
|
||||
this._xmlHttp.onreadystatechange = function() {};
|
||||
this._xmlHttp.abort();
|
||||
}
|
||||
},
|
||||
|
||||
this.send_form = function(form,callback,extra_values)
|
||||
{
|
||||
send_form: function(form, callback, extra_values) {
|
||||
var code = '';
|
||||
|
||||
for (var i = 0; i < form.elements.length; i++)
|
||||
{
|
||||
for (var i = 0; i < form.elements.length; i++) {
|
||||
var e = form.elements[i];
|
||||
|
||||
if (e.options)
|
||||
{
|
||||
if (e.options) {
|
||||
code += (code ? '&' : '') +
|
||||
form.elements[i].name + '=' + encodeURIComponent(
|
||||
e.options[e.selectedIndex].value
|
||||
);
|
||||
}
|
||||
else if (e.length)
|
||||
{
|
||||
else if (e.length) {
|
||||
for (var j = 0; j < e.length; j++)
|
||||
if (e[j].name) {
|
||||
code += (code ? '&' : '') +
|
||||
e[j].name + '=' + encodeURIComponent(e[j].value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
code += (code ? '&' : '') +
|
||||
e.name + '=' + encodeURIComponent(e.value);
|
||||
}
|
||||
|
@ -147,46 +154,25 @@ XHR = function()
|
|||
code += (code ? '&' : '') +
|
||||
key + '=' + encodeURIComponent(extra_values[key]);
|
||||
|
||||
return(
|
||||
(form.method == 'get')
|
||||
? this.get(form.getAttribute('action'), code, callback)
|
||||
: this.post(form.getAttribute('action'), code, callback)
|
||||
);
|
||||
}
|
||||
|
||||
this._encode = function(obj)
|
||||
{
|
||||
obj = obj ? obj : { };
|
||||
obj['_'] = Math.random();
|
||||
|
||||
if (typeof obj == 'object')
|
||||
{
|
||||
var code = '';
|
||||
var self = this;
|
||||
|
||||
for (var k in obj)
|
||||
code += (code ? '&' : '') +
|
||||
k + '=' + encodeURIComponent(obj[k]);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return obj;
|
||||
return (form.method == 'get'
|
||||
? this.get(form.getAttribute('action'), code, callback)
|
||||
: this.post(form.getAttribute('action'), code, callback));
|
||||
}
|
||||
}
|
||||
|
||||
XHR.get = function(url, data, callback)
|
||||
{
|
||||
XHR.get = function(url, data, callback) {
|
||||
(new XHR()).get(url, data, callback);
|
||||
}
|
||||
|
||||
XHR.poll = function(interval, url, data, callback, post)
|
||||
{
|
||||
if (isNaN(interval) || interval < 1)
|
||||
interval = 5;
|
||||
XHR.post = function(url, data, callback) {
|
||||
(new XHR()).post(url, data, callback);
|
||||
}
|
||||
|
||||
if (!XHR._q)
|
||||
{
|
||||
XHR.poll = function(interval, url, data, callback, post) {
|
||||
if (isNaN(interval) || interval <= 0)
|
||||
interval = L.env.pollinterval;
|
||||
|
||||
if (!XHR._q) {
|
||||
XHR._t = 0;
|
||||
XHR._q = [ ];
|
||||
XHR._r = function() {
|
||||
|
@ -213,8 +199,7 @@ XHR.poll = function(interval, url, data, callback, post)
|
|||
return e;
|
||||
}
|
||||
|
||||
XHR.stop = function(e)
|
||||
{
|
||||
XHR.stop = function(e) {
|
||||
for (var i = 0; XHR._q && XHR._q[i]; i++) {
|
||||
if (XHR._q[i] === e) {
|
||||
e.xhr.cancel();
|
||||
|
@ -226,10 +211,8 @@ XHR.stop = function(e)
|
|||
return false;
|
||||
}
|
||||
|
||||
XHR.halt = function()
|
||||
{
|
||||
if (XHR._i)
|
||||
{
|
||||
XHR.halt = function() {
|
||||
if (XHR._i) {
|
||||
/* show & set poll indicator */
|
||||
try {
|
||||
document.getElementById('xhr_poll_status').style.display = '';
|
||||
|
@ -242,10 +225,8 @@ XHR.halt = function()
|
|||
}
|
||||
}
|
||||
|
||||
XHR.run = function()
|
||||
{
|
||||
if (XHR._r && !XHR._i)
|
||||
{
|
||||
XHR.run = function() {
|
||||
if (XHR._r && !XHR._i) {
|
||||
/* show & set poll indicator */
|
||||
try {
|
||||
document.getElementById('xhr_poll_status').style.display = '';
|
||||
|
@ -260,9 +241,10 @@ XHR.run = function()
|
|||
}
|
||||
}
|
||||
|
||||
XHR.running = function()
|
||||
{
|
||||
XHR.running = function() {
|
||||
return !!(XHR._r && XHR._i);
|
||||
}
|
||||
|
||||
function XHR() {}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', XHR.run);
|
||||
|
|
|
@ -1199,19 +1199,20 @@ function TypedSection.parse(self, novld)
|
|||
if name then
|
||||
-- Ignore if it already exists
|
||||
if self:cfgvalue(name) then
|
||||
name = nil;
|
||||
end
|
||||
|
||||
name = self:checkscope(name)
|
||||
|
||||
if not name then
|
||||
name = nil
|
||||
self.err_invalid = true
|
||||
end
|
||||
else
|
||||
name = self:checkscope(name)
|
||||
|
||||
if name and #name > 0 then
|
||||
created = self:create(name, origin) and name
|
||||
if not created then
|
||||
self.invalid_cts = true
|
||||
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
|
||||
|
|
|
@ -132,6 +132,10 @@ function ip6prefix(val)
|
|||
return ( val and val >= 0 and val <= 128 )
|
||||
end
|
||||
|
||||
function cidr(val)
|
||||
return cidr4(val) or cidr6(val)
|
||||
end
|
||||
|
||||
function cidr4(val)
|
||||
local ip, mask = val:match("^([^/]+)/([^/]+)$")
|
||||
|
||||
|
@ -460,3 +464,7 @@ function dateyyyymmdd(val)
|
|||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function unique(val)
|
||||
return true
|
||||
end
|
||||
|
|
164
luci-base/luasrc/controller/admin/index.lua
Normal file
164
luci-base/luasrc/controller/admin/index.lua
Normal file
|
@ -0,0 +1,164 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.controller.admin.index", package.seeall)
|
||||
|
||||
function index()
|
||||
function toplevel_page(page, preflookup, preftarget)
|
||||
if preflookup and preftarget then
|
||||
if lookup(preflookup) then
|
||||
page.target = preftarget
|
||||
end
|
||||
end
|
||||
|
||||
if not page.target then
|
||||
page.target = firstchild()
|
||||
end
|
||||
end
|
||||
|
||||
local uci = require("luci.model.uci").cursor()
|
||||
|
||||
local root = node()
|
||||
if not root.target then
|
||||
root.target = alias("admin")
|
||||
root.index = true
|
||||
end
|
||||
|
||||
local page = node("admin")
|
||||
|
||||
page.title = _("Administration")
|
||||
page.order = 10
|
||||
page.sysauth = "root"
|
||||
page.sysauth_authenticator = "htmlauth"
|
||||
page.ucidata = true
|
||||
page.index = true
|
||||
page.target = firstnode()
|
||||
|
||||
-- Empty menu tree to be populated by addons and modules
|
||||
|
||||
page = node("admin", "status")
|
||||
page.title = _("Status")
|
||||
page.order = 10
|
||||
page.index = true
|
||||
-- overview is from mod-admin-full
|
||||
toplevel_page(page, "admin/status/overview", alias("admin", "status", "overview"))
|
||||
|
||||
page = node("admin", "system")
|
||||
page.title = _("System")
|
||||
page.order = 20
|
||||
page.index = true
|
||||
-- system/system is from mod-admin-full
|
||||
toplevel_page(page, "admin/system/system", alias("admin", "system", "system"))
|
||||
|
||||
-- Only used if applications add items
|
||||
page = node("admin", "services")
|
||||
page.title = _("Services")
|
||||
page.order = 40
|
||||
page.index = true
|
||||
toplevel_page(page, false, false)
|
||||
|
||||
-- Even for mod-admin-full network just uses first submenu item as landing
|
||||
page = node("admin", "network")
|
||||
page.title = _("Network")
|
||||
page.order = 50
|
||||
page.index = true
|
||||
toplevel_page(page, false, false)
|
||||
|
||||
if nixio.fs.access("/etc/config/dhcp") then
|
||||
page = entry({"admin", "dhcplease_status"}, call("lease_status"), nil)
|
||||
page.leaf = true
|
||||
end
|
||||
|
||||
local has_wifi = false
|
||||
|
||||
uci:foreach("wireless", "wifi-device",
|
||||
function(s)
|
||||
has_wifi = true
|
||||
return false
|
||||
end)
|
||||
|
||||
if has_wifi then
|
||||
page = entry({"admin", "wireless_assoclist"}, call("wifi_assoclist"), nil)
|
||||
page.leaf = true
|
||||
|
||||
page = entry({"admin", "wireless_deauth"}, post("wifi_deauth"), nil)
|
||||
page.leaf = true
|
||||
end
|
||||
|
||||
page = entry({"admin", "translations"}, call("action_translations"), nil)
|
||||
page.leaf = true
|
||||
|
||||
-- Logout is last
|
||||
entry({"admin", "logout"}, call("action_logout"), _("Logout"), 999)
|
||||
end
|
||||
|
||||
function action_logout()
|
||||
local dsp = require "luci.dispatcher"
|
||||
local utl = require "luci.util"
|
||||
local sid = dsp.context.authsession
|
||||
|
||||
if sid then
|
||||
utl.ubus("session", "destroy", { ubus_rpc_session = sid })
|
||||
|
||||
luci.http.header("Set-Cookie", "sysauth=%s; expires=%s; path=%s" %{
|
||||
'', 'Thu, 01 Jan 1970 01:00:00 GMT', dsp.build_url()
|
||||
})
|
||||
end
|
||||
|
||||
luci.http.redirect(dsp.build_url())
|
||||
end
|
||||
|
||||
function action_translations(lang)
|
||||
local i18n = require "luci.i18n"
|
||||
local http = require "luci.http"
|
||||
local fs = require "nixio".fs
|
||||
|
||||
if lang and #lang > 0 then
|
||||
lang = i18n.setlanguage(lang)
|
||||
if lang then
|
||||
local s = fs.stat("%s/base.%s.lmo" %{ i18n.i18ndir, lang })
|
||||
if s then
|
||||
http.header("Cache-Control", "public, max-age=31536000")
|
||||
http.header("ETag", "%x-%x-%x" %{ s["ino"], s["size"], s["mtime"] })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
http.prepare_content("application/javascript; charset=utf-8")
|
||||
http.write("window.TR=")
|
||||
http.write_json(i18n.dump())
|
||||
end
|
||||
|
||||
|
||||
function lease_status()
|
||||
local s = require "luci.tools.status"
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write('[')
|
||||
luci.http.write_json(s.dhcp_leases())
|
||||
luci.http.write(',')
|
||||
luci.http.write_json(s.dhcp6_leases())
|
||||
luci.http.write(']')
|
||||
end
|
||||
|
||||
function wifi_assoclist()
|
||||
local s = require "luci.tools.status"
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(s.wifi_assoclist())
|
||||
end
|
||||
|
||||
function wifi_deauth()
|
||||
local iface = luci.http.formvalue("iface")
|
||||
local bssid = luci.http.formvalue("bssid")
|
||||
|
||||
if iface and bssid then
|
||||
luci.util.ubus("hostapd.%s" % iface, "del_client", {
|
||||
addr = bssid,
|
||||
deauth = true,
|
||||
reason = 5,
|
||||
ban_time = 60000
|
||||
})
|
||||
end
|
||||
luci.http.status(200, "OK")
|
||||
end
|
|
@ -40,6 +40,28 @@ function build_url(...)
|
|||
return table.concat(url, "")
|
||||
end
|
||||
|
||||
function _ordered_children(node)
|
||||
local name, child, children = nil, nil, {}
|
||||
|
||||
for name, child in pairs(node.nodes) do
|
||||
children[#children+1] = {
|
||||
name = name,
|
||||
node = child,
|
||||
order = child.order or 100
|
||||
}
|
||||
end
|
||||
|
||||
table.sort(children, function(a, b)
|
||||
if a.order == b.order then
|
||||
return a.name < b.name
|
||||
else
|
||||
return a.order < b.order
|
||||
end
|
||||
end)
|
||||
|
||||
return children
|
||||
end
|
||||
|
||||
function node_visible(node)
|
||||
if node then
|
||||
return not (
|
||||
|
@ -55,15 +77,10 @@ end
|
|||
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
|
||||
local _, child
|
||||
for _, child in ipairs(_ordered_children(node)) do
|
||||
if node_visible(child.node) then
|
||||
rv[#rv+1] = child.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -296,10 +313,6 @@ function dispatch(request)
|
|||
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")
|
||||
|
@ -315,7 +328,7 @@ function dispatch(request)
|
|||
assert(media, "No valid theme found")
|
||||
end
|
||||
|
||||
local function _ifattr(cond, key, val)
|
||||
local function _ifattr(cond, key, val, noescape)
|
||||
if cond then
|
||||
local env = getfenv(3)
|
||||
local scope = (type(env.self) == "table") and env.self
|
||||
|
@ -326,13 +339,16 @@ function dispatch(request)
|
|||
val = util.serialize_json(val)
|
||||
end
|
||||
end
|
||||
return string.format(
|
||||
' %s="%s"', tostring(key),
|
||||
util.pcdata(tostring( val
|
||||
or (type(env[key]) ~= "function" and env[key])
|
||||
or (scope and type(scope[key]) ~= "function" and scope[key])
|
||||
or "" ))
|
||||
)
|
||||
|
||||
val = tostring(val or
|
||||
(type(env[key]) ~= "function" and env[key]) or
|
||||
(scope and type(scope[key]) ~= "function" and scope[key]) or "")
|
||||
|
||||
if noescape ~= true then
|
||||
val = util.pcdata(val)
|
||||
end
|
||||
|
||||
return string.format(' %s="%s"', tostring(key), val)
|
||||
else
|
||||
return ''
|
||||
end
|
||||
|
@ -421,6 +437,7 @@ function dispatch(request)
|
|||
context.path = {}
|
||||
|
||||
http.status(403, "Forbidden")
|
||||
http.header("X-LuCI-Login-Required", "yes")
|
||||
tmpl.render(track.sysauth_template or "sysauth", {
|
||||
duser = default_user,
|
||||
fuser = user
|
||||
|
@ -437,6 +454,7 @@ function dispatch(request)
|
|||
|
||||
if not sid or not sdat then
|
||||
http.status(403, "Forbidden")
|
||||
http.header("X-LuCI-Login-Required", "yes")
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -597,14 +615,9 @@ function createtree()
|
|||
|
||||
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})
|
||||
|
||||
|
@ -614,28 +627,9 @@ function createtree()
|
|||
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
|
||||
|
||||
function modifier(func, order)
|
||||
context.modifiers[#context.modifiers+1] = {
|
||||
func = func,
|
||||
order = order or 0,
|
||||
module
|
||||
= getfenv(2)._NAME
|
||||
}
|
||||
end
|
||||
|
||||
function assign(path, clone, title, order)
|
||||
local obj = node(unpack(path))
|
||||
obj.nodes = nil
|
||||
|
@ -724,32 +718,66 @@ end
|
|||
|
||||
-- Subdispatchers --
|
||||
|
||||
function _find_eligible_node(root, prefix, deep, types, descend)
|
||||
local children = _ordered_children(root)
|
||||
|
||||
if not root.leaf and deep ~= nil then
|
||||
local sub_path = { unpack(prefix) }
|
||||
|
||||
if deep == false then
|
||||
deep = nil
|
||||
end
|
||||
|
||||
local _, child
|
||||
for _, child in ipairs(children) do
|
||||
sub_path[#prefix+1] = child.name
|
||||
|
||||
local res_path = _find_eligible_node(child.node, sub_path,
|
||||
deep, types, true)
|
||||
|
||||
if res_path then
|
||||
return res_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if descend and
|
||||
(not types or
|
||||
(type(root.target) == "table" and
|
||||
util.contains(types, root.target.type)))
|
||||
then
|
||||
return prefix
|
||||
end
|
||||
end
|
||||
|
||||
function _find_node(recurse, types)
|
||||
local path = { unpack(context.path) }
|
||||
local name = table.concat(path, ".")
|
||||
local node = context.treecache[name]
|
||||
|
||||
path = _find_eligible_node(node, path, recurse, types)
|
||||
|
||||
if path then
|
||||
dispatch(path)
|
||||
else
|
||||
require "luci.template".render("empty_node_placeholder")
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
return _find_node(false, nil)
|
||||
end
|
||||
|
||||
function firstchild()
|
||||
return { type = "firstchild", target = _firstchild }
|
||||
return { type = "firstchild", target = _firstchild }
|
||||
end
|
||||
|
||||
function _firstnode()
|
||||
return _find_node(true, { "cbi", "form", "template", "arcombine" })
|
||||
end
|
||||
|
||||
function firstnode()
|
||||
return { type = "firstnode", target = _firstnode }
|
||||
end
|
||||
|
||||
function alias(...)
|
||||
|
|
|
@ -22,7 +22,7 @@ Check whether a dispatch node shall be visible
|
|||
]]
|
||||
|
||||
---[[
|
||||
Return a sorted table of visible childs within a given node
|
||||
Return a sorted table of visible children within a given node
|
||||
|
||||
@class function
|
||||
@name node_childs
|
||||
|
@ -81,15 +81,6 @@ Build the index before if it does not exist yet.
|
|||
@name createtree
|
||||
]]
|
||||
|
||||
---[[
|
||||
Register a tree modifier.
|
||||
|
||||
@class function
|
||||
@name modifier
|
||||
@param func Modifier function
|
||||
@param order Modifier order value (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
Clone a node of the dispatching tree to another position.
|
||||
|
||||
|
|
|
@ -335,13 +335,13 @@ end
|
|||
-- Content-Type. Stores all extracted data associated with its parameter name
|
||||
-- in the params table within the given message object. Multiple parameter
|
||||
-- values are stored as tables, ordinary ones as strings.
|
||||
-- If an optional file callback function is given then it is feeded with the
|
||||
-- If an optional file callback function is given then it is fed 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)
|
||||
-- o Boolean which indicates whether the current chunk is the last one (eof)
|
||||
function mimedecode_message_body(src, msg, file_cb)
|
||||
local parser, header, field
|
||||
local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
|
||||
|
|
|
@ -204,13 +204,13 @@ Stores all extracted data associated with its parameter name
|
|||
in the params table within the given message object. Multiple parameter
|
||||
values are stored as tables, ordinary ones as strings.
|
||||
|
||||
If an optional file callback function is given then it is feeded with the
|
||||
If an optional file callback function is given then it is fed 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)
|
||||
o Boolean which indicates whether the current chunk is the last one (eof)
|
||||
|
||||
@class function
|
||||
@name mimedecode_message_body
|
||||
|
|
|
@ -1,37 +1,43 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.i18n", package.seeall)
|
||||
require("luci.util")
|
||||
local tparser = require "luci.template.parser"
|
||||
local util = require "luci.util"
|
||||
local tostring = tostring
|
||||
|
||||
local tparser = require "luci.template.parser"
|
||||
module "luci.i18n"
|
||||
|
||||
table = {}
|
||||
i18ndir = luci.util.libpath() .. "/i18n/"
|
||||
loaded = {}
|
||||
context = luci.util.threadlocal()
|
||||
i18ndir = util.libpath() .. "/i18n/"
|
||||
context = util.threadlocal()
|
||||
default = "en"
|
||||
|
||||
function clear()
|
||||
end
|
||||
|
||||
function load(file, lang, force)
|
||||
end
|
||||
|
||||
-- Alternatively load the translation of the fallback language.
|
||||
function loadc(file, force)
|
||||
end
|
||||
|
||||
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)
|
||||
local code, subcode = lang:match("^([A-Za-z][A-Za-z])[%-_]([A-Za-z][A-Za-z])$")
|
||||
if not (code and subcode) then
|
||||
subcode = lang:match("^([A-Za-z][A-Za-z])$")
|
||||
if not subcode then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
context.parent = code and code:lower()
|
||||
context.lang = context.parent and context.parent.."-"..subcode:lower() or subcode:lower()
|
||||
|
||||
if tparser.load_catalog(context.lang, i18ndir) and
|
||||
tparser.change_catalog(context.lang)
|
||||
then
|
||||
return context.lang
|
||||
|
||||
elseif context.parent then
|
||||
if tparser.load_catalog(context.parent, i18ndir) and
|
||||
tparser.change_catalog(context.parent)
|
||||
then
|
||||
return context.parent
|
||||
end
|
||||
end
|
||||
return context.lang
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function translate(key)
|
||||
|
@ -42,14 +48,8 @@ function translatef(key, ...)
|
|||
return tostring(translate(key)):format(...)
|
||||
end
|
||||
|
||||
-- and ensure that the returned value is a Lua string value.
|
||||
-- This is the same as calling <code>tostring(translate(...))</code>
|
||||
function string(key)
|
||||
return tostring(translate(key))
|
||||
end
|
||||
|
||||
-- Ensure that the returned value is a Lua string value.
|
||||
-- This is the same as calling <code>tostring(translatef(...))</code>
|
||||
function stringf(key, ...)
|
||||
return tostring(translate(key)):format(...)
|
||||
function dump()
|
||||
local rv = {}
|
||||
tparser.get_translations(function(k, v) rv[k] = v end)
|
||||
return rv
|
||||
end
|
||||
|
|
|
@ -3,41 +3,13 @@ LuCI translation library.
|
|||
]]
|
||||
module "luci.i18n"
|
||||
|
||||
---[[
|
||||
Clear the translation table.
|
||||
|
||||
|
||||
@class function
|
||||
@name clear
|
||||
]]
|
||||
|
||||
---[[
|
||||
Load a translation and copy its data into the translation table.
|
||||
|
||||
@class function
|
||||
@name load
|
||||
@param file Language file
|
||||
@param lang Two-letter language code
|
||||
@param force Force reload even if already loaded (optional)
|
||||
@return Success status
|
||||
]]
|
||||
|
||||
---[[
|
||||
Load a translation file using the default translation language.
|
||||
|
||||
Alternatively load the translation of the fallback language.
|
||||
@class function
|
||||
@name loadc
|
||||
@param file Language file
|
||||
@param force Force reload even if already loaded (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the context default translation language.
|
||||
|
||||
@class function
|
||||
@name setlanguage
|
||||
@param lang Two-letter language code
|
||||
@param lang An IETF/BCP 47 language tag or ISO3166 country code, e.g. "en-US" or "de"
|
||||
@return The effective loaded language, e.g. "en" for "en-US" - or nil on failure
|
||||
]]
|
||||
|
||||
---[[
|
||||
|
@ -60,25 +32,11 @@ Return the translated value for a specific translation key and use it as sprintf
|
|||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key
|
||||
Return all currently loaded translation strings as a key-value table. The key is the
|
||||
hexadecimal representation of the translation key while the value is the translated
|
||||
text content.
|
||||
|
||||
and ensure that the returned value is a Lua string value.
|
||||
This is the same as calling <code>tostring(translate(...))</code>
|
||||
@class function
|
||||
@name string
|
||||
@param key Default translation text
|
||||
@return Translated string
|
||||
@name dump
|
||||
@return Key-value translation string table.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key and use it as sprintf pattern.
|
||||
|
||||
Ensure that the returned value is a Lua string value.
|
||||
This is the same as calling <code>tostring(translatef(...))</code>
|
||||
@class function
|
||||
@name stringf
|
||||
@param key Default translation text
|
||||
@param ... Format parameters
|
||||
@return Translated and formatted string
|
||||
]]
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ metric.datatype = "uinteger"
|
|||
|
||||
clientid = section:taboption("advanced", Value, "clientid",
|
||||
translate("Client ID to send when requesting DHCP"))
|
||||
clientid.datatype = "hexstring"
|
||||
|
||||
|
||||
vendorclass = section:taboption("advanced", Value, "vendorid",
|
||||
|
|
|
@ -4,17 +4,93 @@
|
|||
local map, section, net = ...
|
||||
local ifc = net:get_interface()
|
||||
|
||||
local ipaddr, netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw
|
||||
local mtu, metric
|
||||
local netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw
|
||||
local mtu, metric, usecidr, ipaddr_single, ipaddr_multi
|
||||
|
||||
|
||||
ipaddr = section:taboption("general", Value, "ipaddr", translate("IPv4 address"))
|
||||
ipaddr.datatype = "ip4addr"
|
||||
local function is_cidr(s)
|
||||
return (type(s) == "string" and luci.ip.IPv4(s) and s:find("/"))
|
||||
end
|
||||
|
||||
usecidr = section:taboption("general", Value, "ipaddr_usecidr")
|
||||
usecidr.forcewrite = true
|
||||
|
||||
usecidr.cfgvalue = function(self, section)
|
||||
local cfgvalue = self.map:get(section, "ipaddr")
|
||||
return (type(cfgvalue) == "table" or is_cidr(cfgvalue)) and "1" or "0"
|
||||
end
|
||||
|
||||
usecidr.render = function(self, section, scope)
|
||||
luci.template.Template(nil, [[
|
||||
<input type="hidden"<%= attr("id", cbid) .. attr("name", cbid) .. attr("value", value) %> />
|
||||
]]):render({
|
||||
cbid = self:cbid(section),
|
||||
value = self:cfgvalue(section)
|
||||
})
|
||||
end
|
||||
|
||||
usecidr.write = function(self, section)
|
||||
local cfgvalue = self.map:get(section, "ipaddr")
|
||||
local formvalue = (self:formvalue(section) == "1") and ipaddr_multi:formvalue(section) or ipaddr_single:formvalue(section)
|
||||
local equal = (cfgvalue == formvalue)
|
||||
|
||||
if not equal and type(cfgvalue) == "table" and type(formvalue) == "table" and #cfgvalue == #formvalue then
|
||||
equal = true
|
||||
|
||||
local _, v
|
||||
for _, v in ipairs(cfgvalue) do
|
||||
if v ~= formvalue[_] then
|
||||
equal = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not equal then
|
||||
self.map:set(section, "ipaddr", formvalue or "")
|
||||
end
|
||||
|
||||
return not equal
|
||||
end
|
||||
|
||||
|
||||
netmask = section:taboption("general", Value, "netmask",
|
||||
translate("IPv4 netmask"))
|
||||
ipaddr_multi = section:taboption("general", DynamicList, "ipaddrs", translate("IPv4 address"))
|
||||
ipaddr_multi:depends("ipaddr_usecidr", "1")
|
||||
ipaddr_multi.datatype = "or(cidr4,ipnet4)"
|
||||
ipaddr_multi.placeholder = translate("Add IPv4 address…")
|
||||
|
||||
ipaddr_multi.alias = "ipaddr"
|
||||
ipaddr_multi.write = function() end
|
||||
ipaddr_multi.remove = function() end
|
||||
ipaddr_multi.cfgvalue = function(self, section)
|
||||
local addr = self.map:get(section, "ipaddr")
|
||||
local mask = self.map:get(section, "netmask")
|
||||
|
||||
if is_cidr(addr) then
|
||||
return { addr }
|
||||
elseif type(addr) == "string" and
|
||||
type(mask) == "string" and
|
||||
#addr > 0 and #mask > 0
|
||||
then
|
||||
return { "%s/%s" %{ addr, mask } }
|
||||
elseif type(addr) == "table" then
|
||||
return addr
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ipaddr_single = section:taboption("general", Value, "ipaddr", translate("IPv4 address"))
|
||||
ipaddr_single:depends("ipaddr_usecidr", "0")
|
||||
ipaddr_single.datatype = "ip4addr"
|
||||
ipaddr_single.template = "cbi/ipaddr"
|
||||
ipaddr_single.write = function() end
|
||||
ipaddr_single.remove = function() end
|
||||
|
||||
|
||||
netmask = section:taboption("general", Value, "netmask", translate("IPv4 netmask"))
|
||||
netmask:depends("ipaddr_usecidr", "0")
|
||||
netmask.datatype = "ip4addr"
|
||||
netmask:value("255.255.255.0")
|
||||
netmask:value("255.255.0.0")
|
||||
|
@ -48,8 +124,9 @@ if luci.model.network:has_ipv6() then
|
|||
translate("Assign prefix parts using this hexadecimal subprefix ID for this interface."))
|
||||
for i=33,64 do ip6hint:depends("ip6assign", i) end
|
||||
|
||||
ip6addr = section:taboption("general", Value, "ip6addr", translate("IPv6 address"))
|
||||
ip6addr = section:taboption("general", DynamicList, "ip6addr", translate("IPv6 address"))
|
||||
ip6addr.datatype = "ip6addr"
|
||||
ip6addr.placeholder = translate("Add IPv6 address…")
|
||||
ip6addr:depends("ip6assign", "")
|
||||
|
||||
|
||||
|
@ -83,14 +160,8 @@ mtu.placeholder = "1500"
|
|||
mtu.datatype = "max(9200)"
|
||||
|
||||
|
||||
--metric = section:taboption("advanced", Value, "metric",
|
||||
-- translate("Use gateway metric"))
|
||||
--metric.default = "1"
|
||||
--metric.datatype = "uinteger"
|
||||
metric = section:taboption("advanced", Value, "metric",
|
||||
translate("Use gateway metric"))
|
||||
|
||||
--local nw = require "luci.model.network".init()
|
||||
--for _, network in ipairs(nw:get_networks()) do
|
||||
-- if network:proto() == "static" and network:type() == "macvlan" and tonumber(network:metric()) >= tonumber(metric.default) then
|
||||
-- metric.default = network:metric() + 1
|
||||
-- end
|
||||
--end
|
||||
metric.placeholder = "0"
|
||||
metric.datatype = "uinteger"
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache 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"
|
||||
|
||||
module "luci.model.ipkg"
|
||||
|
||||
|
||||
-- Internal action function
|
||||
local function _action(cmd, ...)
|
||||
local cmdline = { ipkg, cmd }
|
||||
|
||||
local k, v
|
||||
for k, v in pairs({...}) do
|
||||
cmdline[#cmdline+1] = util.shellquote(v)
|
||||
end
|
||||
|
||||
local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
|
||||
local r = os.execute(c)
|
||||
local e = fs.readfile("/tmp/opkg.stderr")
|
||||
local o = fs.readfile("/tmp/opkg.stdout")
|
||||
|
||||
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(cmd, pkg)
|
||||
local cmdline = { ipkg, cmd }
|
||||
if pkg then
|
||||
cmdline[#cmdline+1] = util.shellquote(pkg)
|
||||
end
|
||||
|
||||
-- OPKG sometimes kills the whole machine because it sucks
|
||||
-- Therefore we have to use a sucky approach too and use
|
||||
-- tmpfiles instead of directly reading the output
|
||||
local tmpfile = os.tmpname()
|
||||
os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
|
||||
|
||||
local data = _parselist(io.lines(tmpfile))
|
||||
os.remove(tmpfile)
|
||||
return data
|
||||
end
|
||||
|
||||
|
||||
function info(pkg)
|
||||
return _lookup("info", pkg)
|
||||
end
|
||||
|
||||
function status(pkg)
|
||||
return _lookup("status", pkg)
|
||||
end
|
||||
|
||||
function install(...)
|
||||
return _action("install", ...)
|
||||
end
|
||||
|
||||
function installed(pkg)
|
||||
local p = status(pkg)[pkg]
|
||||
return (p and p.Status and p.Status.installed)
|
||||
end
|
||||
|
||||
function remove(...)
|
||||
return _action("remove", ...)
|
||||
end
|
||||
|
||||
function update()
|
||||
return _action("update")
|
||||
end
|
||||
|
||||
function upgrade()
|
||||
return _action("upgrade")
|
||||
end
|
||||
|
||||
-- List helper
|
||||
local function _list(action, pat, cb)
|
||||
local cmdline = { ipkg, action }
|
||||
if pat then
|
||||
cmdline[#cmdline+1] = util.shellquote(pat)
|
||||
end
|
||||
|
||||
local fd = io.popen(table.concat(cmdline, " "))
|
||||
if fd then
|
||||
local name, version, sz, desc
|
||||
while true do
|
||||
local line = fd:read("*l")
|
||||
if not line then break end
|
||||
|
||||
name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
|
||||
|
||||
if not name then
|
||||
name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
|
||||
desc = ""
|
||||
end
|
||||
|
||||
if name and version then
|
||||
if #version > 26 then
|
||||
version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
|
||||
end
|
||||
|
||||
cb(name, version, sz, desc)
|
||||
end
|
||||
|
||||
name = nil
|
||||
version = nil
|
||||
sz = nil
|
||||
desc = nil
|
||||
end
|
||||
|
||||
fd:close()
|
||||
end
|
||||
end
|
||||
|
||||
function list_all(pat, cb)
|
||||
_list("list --size", pat, cb)
|
||||
end
|
||||
|
||||
function list_installed(pat, cb)
|
||||
_list("list_installed --size", pat, cb)
|
||||
end
|
||||
|
||||
function find(pat, cb)
|
||||
_list("find --size", pat, cb)
|
||||
end
|
||||
|
||||
|
||||
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
|
||||
|
||||
function compare_versions(ver1, comp, ver2)
|
||||
if not ver1 or not ver2
|
||||
or not comp or not (#comp > 0) then
|
||||
error("Invalid parameters")
|
||||
return nil
|
||||
end
|
||||
-- correct compare string
|
||||
if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
|
||||
elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
|
||||
elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
|
||||
elseif comp == "=" or comp == "==" then comp = "=="
|
||||
elseif comp == "<<" then comp = "<"
|
||||
elseif comp == ">>" then comp = ">"
|
||||
else
|
||||
error("Invalid compare string")
|
||||
return nil
|
||||
end
|
||||
|
||||
local av1 = util.split(ver1, "[%.%-]", nil, true)
|
||||
local av2 = util.split(ver2, "[%.%-]", nil, true)
|
||||
|
||||
local max = table.getn(av1)
|
||||
if (table.getn(av1) < table.getn(av2)) then
|
||||
max = table.getn(av2)
|
||||
end
|
||||
|
||||
for i = 1, max, 1 do
|
||||
local s1 = av1[i] or ""
|
||||
local s2 = av2[i] or ""
|
||||
|
||||
-- first "not equal" found return true
|
||||
if comp == "~=" and (s1 ~= s2) then return true end
|
||||
-- first "lower" found return true
|
||||
if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
|
||||
-- first "greater" found return true
|
||||
if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
|
||||
-- not equal then return false
|
||||
if (s1 ~= s2) then return false end
|
||||
end
|
||||
|
||||
-- all equal and not compare greater or lower then true
|
||||
return not (comp == "<" or comp == ">")
|
||||
end
|
|
@ -1,125 +0,0 @@
|
|||
---[[
|
||||
LuCI OPKG call abstraction library
|
||||
]]
|
||||
module "luci.model.ipkg"
|
||||
|
||||
---[[
|
||||
Return information about installed and available packages.
|
||||
|
||||
@class function
|
||||
@name info
|
||||
@param pkg Limit output to a (set of) packages
|
||||
@return Table containing package information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the package status of one or more packages.
|
||||
|
||||
@class function
|
||||
@name status
|
||||
@param pkg Limit output to a (set of) packages
|
||||
@return Table containing package status information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Install one or more packages.
|
||||
|
||||
@class function
|
||||
@name install
|
||||
@param ... List of packages to install
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Determine whether a given package is installed.
|
||||
|
||||
@class function
|
||||
@name installed
|
||||
@param pkg Package
|
||||
@return Boolean
|
||||
]]
|
||||
|
||||
---[[
|
||||
Remove one or more packages.
|
||||
|
||||
@class function
|
||||
@name remove
|
||||
@param ... List of packages to install
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Update package lists.
|
||||
|
||||
@class function
|
||||
@name update
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Upgrades all installed packages.
|
||||
|
||||
@class function
|
||||
@name upgrade
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
List all packages known to opkg.
|
||||
|
||||
@class function
|
||||
@name list_all
|
||||
@param pat Only find packages matching this pattern, nil lists all packages
|
||||
@param cb Callback function invoked for each package, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
List installed packages.
|
||||
|
||||
@class function
|
||||
@name list_installed
|
||||
@param pat Only find packages matching this pattern, nil lists all packages
|
||||
@param cb Callback function invoked for each package, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
Find packages that match the given pattern.
|
||||
|
||||
@class function
|
||||
@name find
|
||||
@param pat Find packages whose names or descriptions match this pattern, nil results in zero results
|
||||
@param cb Callback function invoked for each patckage, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
Determines the overlay root used by opkg.
|
||||
|
||||
@class function
|
||||
@name overlay_root
|
||||
@return String containing the directory path of the overlay root.
|
||||
]]
|
||||
|
||||
---[[
|
||||
lua version of opkg compare-versions
|
||||
|
||||
@class function
|
||||
@name compare_versions
|
||||
@param ver1 string version 1
|
||||
@param ver2 string version 2
|
||||
@param comp string compare versions using
|
||||
"<=" or "<" lower-equal
|
||||
">" or ">=" greater-equal
|
||||
"=" equal
|
||||
"<<" lower
|
||||
">>" greater
|
||||
"~=" not equal
|
||||
@return Boolean indicating the status of the compare
|
||||
]]
|
||||
|
|
@ -20,7 +20,7 @@ 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", "^gretap%d", "^ip6gre%d", "^ip6tnl%d", "^tunl%d", "^lo$" }
|
||||
IFACE_PATTERNS_IGNORE = { "^wmaster%d", "^wifi%d", "^hwsim%d", "^imq%d", "^ifb%d", "^mon%.wlan%d", "^sit%d", "^gre%d", "^gretap%d", "^ip6gre%d", "^ip6tnl%d", "^tunl%d", "^lo$", "^teql%d" }
|
||||
IFACE_PATTERNS_WIRELESS = { "^wlan%d", "^wl%d", "^ath%d", "^%w+%.network%d" }
|
||||
|
||||
IFACE_ERRORS = {
|
||||
|
@ -622,6 +622,12 @@ function del_network(self, n)
|
|||
_uci:delete("wireless", s['.name'], "network")
|
||||
end
|
||||
end)
|
||||
|
||||
local ok, fw = pcall(require, "luci.model.firewall")
|
||||
if ok then
|
||||
fw.init()
|
||||
fw:del_network(n)
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
@ -813,6 +819,7 @@ function del_wifinet(self, net)
|
|||
end
|
||||
|
||||
function get_status_by_route(self, addr, mask)
|
||||
local route_statuses = { }
|
||||
local _, object
|
||||
for _, object in ipairs(utl.ubus()) do
|
||||
local net = object:match("^network%.interface%.(.+)")
|
||||
|
@ -822,12 +829,14 @@ function get_status_by_route(self, addr, mask)
|
|||
local rt
|
||||
for _, rt in ipairs(s.route) do
|
||||
if not rt.table and rt.target == addr and rt.mask == mask then
|
||||
return net, s
|
||||
route_statuses[net] = s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return route_statuses
|
||||
end
|
||||
|
||||
function get_status_by_address(self, addr)
|
||||
|
@ -852,28 +861,40 @@ function get_status_by_address(self, addr)
|
|||
end
|
||||
end
|
||||
end
|
||||
if s and s['ipv6-prefix-assignment'] then
|
||||
local a
|
||||
for _, a in ipairs(s['ipv6-prefix-assignment']) do
|
||||
if a and a['local-address'] and a['local-address'].address == addr then
|
||||
return net, s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_wannet(self)
|
||||
local net, stat = self:get_status_by_route("0.0.0.0", 0)
|
||||
return net and network(net, stat.proto)
|
||||
function get_wan_networks(self)
|
||||
local k, v
|
||||
local wan_nets = { }
|
||||
local route_statuses = self:get_status_by_route("0.0.0.0", 0)
|
||||
|
||||
for k, v in pairs(route_statuses) do
|
||||
wan_nets[#wan_nets+1] = network(k, v.proto)
|
||||
end
|
||||
|
||||
return wan_nets
|
||||
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_wan6_networks(self)
|
||||
local k, v
|
||||
local wan6_nets = { }
|
||||
local route_statuses = self:get_status_by_route("::", 0)
|
||||
|
||||
function get_wan6net(self)
|
||||
local net, stat = self:get_status_by_route("::", 0)
|
||||
return net and network(net, stat.proto)
|
||||
end
|
||||
for k, v in pairs(route_statuses) do
|
||||
wan6_nets[#wan6_nets+1] = network(k, v.proto)
|
||||
end
|
||||
|
||||
function get_wan6dev(self)
|
||||
local _, stat = self:get_status_by_route("::", 0)
|
||||
return stat and interface(stat.l3_device or stat.device)
|
||||
return wan6_nets
|
||||
end
|
||||
|
||||
function get_switch_topologies(self)
|
||||
|
@ -1144,6 +1165,10 @@ function protocol.is_dynamic(self)
|
|||
return (self:_ubus("dynamic") == true)
|
||||
end
|
||||
|
||||
function protocol.is_auto(self)
|
||||
return (self:_get("auto") ~= "0")
|
||||
end
|
||||
|
||||
function protocol.is_alias(self)
|
||||
local ifn, parent = nil, nil
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
|
|||
-- 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
|
||||
-- LuCI then needs to Cursor.apply the changes so daemons etc. are
|
||||
-- reloaded.
|
||||
module "luci.model.uci"
|
||||
|
||||
|
@ -95,41 +95,15 @@ end
|
|||
|
||||
|
||||
function changes(self, config)
|
||||
local rv = call("changes", { config = config })
|
||||
local res = {}
|
||||
local rv, err = call("changes", { config = config })
|
||||
|
||||
if type(rv) == "table" and type(rv.changes) == "table" then
|
||||
local package, changes
|
||||
for package, changes in pairs(rv.changes) do
|
||||
res[package] = {}
|
||||
|
||||
local _, change
|
||||
for _, change in ipairs(changes) do
|
||||
local operation, section, option, value = unpack(change)
|
||||
if option and operation ~= "add" then
|
||||
res[package][section] = res[package][section] or { }
|
||||
|
||||
if operation == "list-add" then
|
||||
local v = res[package][section][option]
|
||||
if type(v) == "table" then
|
||||
v[#v+1] = value or ""
|
||||
elseif v ~= nil then
|
||||
res[package][section][option] = { v, value }
|
||||
else
|
||||
res[package][section][option] = { value }
|
||||
end
|
||||
else
|
||||
res[package][section][option] = value or ""
|
||||
end
|
||||
else
|
||||
res[package][section] = res[package][section] or {}
|
||||
res[package][section][".type"] = option or ""
|
||||
end
|
||||
end
|
||||
end
|
||||
return rv.changes
|
||||
elseif err then
|
||||
return nil, ERRSTR[err]
|
||||
else
|
||||
return { }
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ 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
|
||||
LuCI then needs to Cursor.apply the changes so daemons etc. are
|
||||
reloaded.
|
||||
@cstyle instance
|
||||
]]
|
||||
|
@ -172,7 +172,7 @@ has the same effect as deleting the option.
|
|||
---[[
|
||||
Create a sub-state of this cursor.
|
||||
|
||||
The sub-state is tied to the parent curser, means it the parent unloads or
|
||||
The sub-state is tied to the parent cursor, means it the parent unloads or
|
||||
loads configs, the sub state will do so as well.
|
||||
|
||||
@class function
|
||||
|
@ -339,7 +339,7 @@ Set the configuration directory.
|
|||
]]
|
||||
|
||||
---[[
|
||||
Set the directory for uncommited changes.
|
||||
Set the directory for uncommitted changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.set_savedir
|
||||
|
|
|
@ -13,8 +13,8 @@ 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
|
||||
local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack =
|
||||
tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack
|
||||
|
||||
|
||||
module "luci.sys"
|
||||
|
@ -70,6 +70,24 @@ function mounts()
|
|||
return data
|
||||
end
|
||||
|
||||
function mtds()
|
||||
local data = {}
|
||||
|
||||
if fs.access("/proc/mtd") then
|
||||
for l in io.lines("/proc/mtd") do
|
||||
local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
|
||||
if s and n then
|
||||
local d = {}
|
||||
d.size = tonumber(s, 16)
|
||||
d.name = n
|
||||
table.insert(data, d)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- 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.
|
||||
|
@ -87,9 +105,9 @@ end
|
|||
function httpget(url, stream, target)
|
||||
if not target then
|
||||
local source = stream and io.popen or luci.util.exec
|
||||
return source("wget -4 -T 20 -qO- %s" % luci.util.shellquote(url))
|
||||
return source("wget -qO- %s" % luci.util.shellquote(url))
|
||||
else
|
||||
return os.execute("wget -4 -T 20 -qO %s %s" %
|
||||
return os.execute("wget -qO %s %s" %
|
||||
{luci.util.shellquote(target), luci.util.shellquote(url)})
|
||||
end
|
||||
end
|
||||
|
@ -386,8 +404,8 @@ function process.list()
|
|||
end
|
||||
|
||||
for line in ps do
|
||||
local pid, ppid, user, stat, vsz, mem, cpun, cpu, cmd = line:match(
|
||||
"^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][W ][<N ]) +(%d+) +(%d+.%d) +(%d+) +(%d+.%d) +(.+)"
|
||||
local pid, ppid, user, stat, vsz, mem, cpu, cmd = line:match(
|
||||
"^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][W ][<N ]) +(%d+) +(%d+%%) +(%d+%%) +(.+)"
|
||||
)
|
||||
|
||||
local idx = tonumber(pid)
|
||||
|
@ -418,6 +436,96 @@ end
|
|||
|
||||
process.signal = nixio.kill
|
||||
|
||||
local function xclose(fd)
|
||||
if fd and fd:fileno() > 2 then
|
||||
fd:close()
|
||||
end
|
||||
end
|
||||
|
||||
function process.exec(command, stdout, stderr, nowait)
|
||||
local out_r, out_w, err_r, err_w
|
||||
if stdout then out_r, out_w = nixio.pipe() end
|
||||
if stderr then err_r, err_w = nixio.pipe() end
|
||||
|
||||
local pid = nixio.fork()
|
||||
if pid == 0 then
|
||||
nixio.chdir("/")
|
||||
|
||||
local null = nixio.open("/dev/null", "w+")
|
||||
if null then
|
||||
nixio.dup(out_w or null, nixio.stdout)
|
||||
nixio.dup(err_w or null, nixio.stderr)
|
||||
nixio.dup(null, nixio.stdin)
|
||||
xclose(out_w)
|
||||
xclose(out_r)
|
||||
xclose(err_w)
|
||||
xclose(err_r)
|
||||
xclose(null)
|
||||
end
|
||||
|
||||
nixio.exec(unpack(command))
|
||||
os.exit(-1)
|
||||
end
|
||||
|
||||
local _, pfds, rv = nil, {}, { code = -1, pid = pid }
|
||||
|
||||
xclose(out_w)
|
||||
xclose(err_w)
|
||||
|
||||
if out_r then
|
||||
pfds[#pfds+1] = {
|
||||
fd = out_r,
|
||||
cb = type(stdout) == "function" and stdout,
|
||||
name = "stdout",
|
||||
events = nixio.poll_flags("in", "err", "hup")
|
||||
}
|
||||
end
|
||||
|
||||
if err_r then
|
||||
pfds[#pfds+1] = {
|
||||
fd = err_r,
|
||||
cb = type(stderr) == "function" and stderr,
|
||||
name = "stderr",
|
||||
events = nixio.poll_flags("in", "err", "hup")
|
||||
}
|
||||
end
|
||||
|
||||
while #pfds > 0 do
|
||||
local nfds, err = nixio.poll(pfds, -1)
|
||||
if not nfds and err ~= nixio.const.EINTR then
|
||||
break
|
||||
end
|
||||
|
||||
local i
|
||||
for i = #pfds, 1, -1 do
|
||||
local rfd = pfds[i]
|
||||
if rfd.revents > 0 then
|
||||
local chunk, err = rfd.fd:read(4096)
|
||||
if chunk and #chunk > 0 then
|
||||
if rfd.cb then
|
||||
rfd.cb(chunk)
|
||||
else
|
||||
rfd.buf = rfd.buf or {}
|
||||
rfd.buf[#rfd.buf + 1] = chunk
|
||||
end
|
||||
else
|
||||
table.remove(pfds, i)
|
||||
if rfd.buf then
|
||||
rv[rfd.name] = table.concat(rfd.buf, "")
|
||||
end
|
||||
rfd.fd:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not nowait then
|
||||
_, _, rv.code = nixio.waitpid(pid)
|
||||
end
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
|
||||
user = {}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ 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
|
||||
@return String containing the return the output of the command
|
||||
]]
|
||||
|
||||
---[[
|
||||
|
@ -38,7 +38,7 @@ 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 String containing the value of the specified variable
|
||||
@return Table containing all variables if no variable name is given
|
||||
]]
|
||||
|
||||
|
@ -271,6 +271,42 @@ Send a signal to a process identified by given pid.
|
|||
@return Number containing the error code if failed
|
||||
]]
|
||||
|
||||
---[[
|
||||
Execute a process, optionally capturing stdio.
|
||||
|
||||
Executes the process specified by the given argv vector, e.g.
|
||||
`{ "/bin/sh", "-c", "echo 1" }` and waits for it to terminate unless a true
|
||||
value has been passed for the "nowait" parameter.
|
||||
|
||||
When a function value is passed for the stdout or stderr arguments, the passed
|
||||
function is repeatedly called for each chunk read from the corresponding stdio
|
||||
stream. The read data is passed as string containing at most 4096 bytes at a
|
||||
time.
|
||||
|
||||
When a true, non-function value is passed for the stdout or stderr arguments,
|
||||
the data of the corresponding stdio stream is read into an internal string
|
||||
buffer and returned as "stdout" or "stderr" field respectively in the result
|
||||
table.
|
||||
|
||||
When a true value is passed to the nowait parameter, the function does not
|
||||
await process termination but returns as soon as all captured stdio streams
|
||||
have been closed or - if no streams are captured - immediately after launching
|
||||
the process.
|
||||
|
||||
@class function
|
||||
@name process.exec
|
||||
@param commend Table containing the argv vector to execute
|
||||
@param stdout Callback function or boolean to indicate capturing (optional)
|
||||
@param stderr Callback function or boolean to indicate capturing (optional)
|
||||
@param nowait Don't wait for process termination when true (optional)
|
||||
@return Table containing at least the fields "code" which holds the exit
|
||||
status of the invoked process or "-1" on error and "pid", which
|
||||
contains the process id assigned to the spawned process. When
|
||||
stdout and/or stderr capturing has been requested, it additionally
|
||||
contains "stdout" and "stderr" fields respectively, holding the
|
||||
captured stdio data as string.
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / user related functions.
|
||||
|
||||
|
@ -279,7 +315,7 @@ LuCI system utilities / user related functions.
|
|||
]]
|
||||
|
||||
---[[
|
||||
Retrieve user informations for given uid.
|
||||
Retrieve user information for given uid.
|
||||
|
||||
@class function
|
||||
@name getuser
|
||||
|
@ -305,7 +341,7 @@ Test whether given string matches the password of a given system user.
|
|||
@name user.checkpasswd
|
||||
@param username String containing the Unix user name
|
||||
@param pass String containing the password to compare
|
||||
@return Boolean indicating wheather the passwords are equal
|
||||
@return Boolean indicating whether the passwords are equal
|
||||
]]
|
||||
|
||||
---[[
|
||||
|
|
|
@ -16,14 +16,12 @@ TZ = {
|
|||
{ 'Africa/Brazzaville', 'WAT-1' },
|
||||
{ 'Africa/Bujumbura', 'CAT-2' },
|
||||
{ 'Africa/Cairo', 'EET-2' },
|
||||
{ 'Africa/Casablanca', 'WET0WEST,M3.5.0,M10.5.0/3' },
|
||||
{ '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', 'WET0WEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Africa/Freetown', 'GMT0' },
|
||||
{ 'Africa/Gaborone', 'CAT-2' },
|
||||
{ 'Africa/Harare', 'CAT-2' },
|
||||
|
@ -51,7 +49,7 @@ TZ = {
|
|||
{ 'Africa/Nouakchott', 'GMT0' },
|
||||
{ 'Africa/Ouagadougou', 'GMT0' },
|
||||
{ 'Africa/Porto-Novo', 'WAT-1' },
|
||||
{ 'Africa/Sao Tome', 'WAT-1' },
|
||||
{ 'Africa/Sao Tome', 'GMT0' },
|
||||
{ 'Africa/Tripoli', 'EET-2' },
|
||||
{ 'Africa/Tunis', 'CET-1' },
|
||||
{ 'Africa/Windhoek', 'CAT-2' },
|
||||
|
@ -179,7 +177,7 @@ TZ = {
|
|||
{ 'America/Resolute', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Rio Branco', '<-05>5' },
|
||||
{ 'America/Santarem', '<-03>3' },
|
||||
{ 'America/Santiago', '<-04>4<-03>,M8.2.6/24,M5.2.6/24' },
|
||||
{ 'America/Santiago', '<-04>4<-03>,M9.1.6/24,M4.1.6/24' },
|
||||
{ 'America/Santo Domingo', 'AST4' },
|
||||
{ 'America/Sao Paulo', '<-03>3<-02>,M11.1.0/0,M2.3.0/0' },
|
||||
{ 'America/Scoresbysund', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' },
|
||||
|
@ -261,7 +259,7 @@ TZ = {
|
|||
{ 'Asia/Macau', 'CST-8' },
|
||||
{ 'Asia/Magadan', '<+11>-11' },
|
||||
{ 'Asia/Makassar', 'WITA-8' },
|
||||
{ 'Asia/Manila', '<+08>-8' },
|
||||
{ 'Asia/Manila', 'PST-8' },
|
||||
{ 'Asia/Muscat', '<+04>-4' },
|
||||
{ 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Asia/Novokuznetsk', '<+07>-7' },
|
||||
|
@ -270,9 +268,10 @@ TZ = {
|
|||
{ 'Asia/Oral', '<+05>-5' },
|
||||
{ 'Asia/Phnom Penh', '<+07>-7' },
|
||||
{ 'Asia/Pontianak', 'WIB-7' },
|
||||
{ 'Asia/Pyongyang', 'KST-8:30' },
|
||||
{ 'Asia/Pyongyang', 'KST-9' },
|
||||
{ 'Asia/Qatar', '<+03>-3' },
|
||||
{ 'Asia/Qyzylorda', '<+06>-6' },
|
||||
{ 'Asia/Qostanay', '<+06>-6' },
|
||||
{ 'Asia/Qyzylorda', '<+05>-5' },
|
||||
{ 'Asia/Riyadh', '<+03>-3' },
|
||||
{ 'Asia/Sakhalin', '<+11>-11' },
|
||||
{ 'Asia/Samarkand', '<+05>-5' },
|
||||
|
@ -283,7 +282,7 @@ TZ = {
|
|||
{ 'Asia/Taipei', 'CST-8' },
|
||||
{ 'Asia/Tashkent', '<+05>-5' },
|
||||
{ 'Asia/Tbilisi', '<+04>-4' },
|
||||
{ 'Asia/Tehran', '<+0330>-3:30<+0430>,J80/0,J264/0' },
|
||||
{ 'Asia/Tehran', '<+0330>-3:30<+0430>,J79/24,J263/24' },
|
||||
{ 'Asia/Thimphu', '<+06>-6' },
|
||||
{ 'Asia/Tokyo', 'JST-9' },
|
||||
{ 'Asia/Tomsk', '<+07>-7' },
|
||||
|
@ -358,7 +357,7 @@ TZ = {
|
|||
{ 'Europe/Busingen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Chisinau', 'EET-2EEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Dublin', 'GMT0IST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Dublin', 'IST-1GMT0,M10.5.0,M3.5.0/1' },
|
||||
{ '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' },
|
||||
|
@ -400,7 +399,7 @@ TZ = {
|
|||
{ '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', '<+03>-3' },
|
||||
{ 'Europe/Volgograd', '<+04>-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' },
|
||||
|
@ -421,11 +420,11 @@ TZ = {
|
|||
{ 'Pacific/Bougainville', '<+11>-11' },
|
||||
{ 'Pacific/Chatham', '<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45' },
|
||||
{ 'Pacific/Chuuk', '<+10>-10' },
|
||||
{ 'Pacific/Easter', '<-06>6<-05>,M8.2.6/22,M5.2.6/22' },
|
||||
{ 'Pacific/Easter', '<-06>6<-05>,M9.1.6/22,M4.1.6/22' },
|
||||
{ 'Pacific/Efate', '<+11>-11' },
|
||||
{ 'Pacific/Enderbury', '<+13>-13' },
|
||||
{ 'Pacific/Fakaofo', '<+13>-13' },
|
||||
{ 'Pacific/Fiji', '<+12>-12<+13>,M11.1.0,M1.2.1/147' },
|
||||
{ 'Pacific/Fiji', '<+12>-12<+13>,M11.1.0,M1.2.2/123' },
|
||||
{ 'Pacific/Funafuti', '<+12>-12' },
|
||||
{ 'Pacific/Galapagos', '<-06>6' },
|
||||
{ 'Pacific/Gambier', '<-09>9' },
|
||||
|
|
|
@ -9,7 +9,6 @@ OFFSET = {
|
|||
wat = 3600, -- WAT
|
||||
cat = 7200, -- CAT
|
||||
eet = 7200, -- EET
|
||||
wet = 0, -- WET
|
||||
sast = 7200, -- SAST
|
||||
hst = -36000, -- HST
|
||||
hdt = -32400, -- HDT
|
||||
|
@ -34,8 +33,9 @@ OFFSET = {
|
|||
idt = 10800, -- IDT
|
||||
pkt = 18000, -- PKT
|
||||
wita = 28800, -- WITA
|
||||
kst = 30600, -- KST
|
||||
kst = 32400, -- KST
|
||||
jst = 32400, -- JST
|
||||
wet = 0, -- WET
|
||||
acst = 34200, -- ACST
|
||||
acdt = 37800, -- ACDT
|
||||
aest = 36000, -- AEST
|
||||
|
|
|
@ -95,6 +95,6 @@ function Template.render(self, scope)
|
|||
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)"))
|
||||
"A runtime error occurred: " .. tostring(err or "(nil)"))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -262,7 +262,7 @@ end
|
|||
|
||||
-- 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.
|
||||
-- will result in a valid iterator which aborts with the first invocation.
|
||||
function imatch(v)
|
||||
if type(v) == "table" then
|
||||
local k = nil
|
||||
|
|
|
@ -158,7 +158,7 @@ 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.
|
||||
A nil value will result in a valid iterator which aborts with the first invocation.
|
||||
|
||||
@class function
|
||||
@name imatch
|
||||
|
@ -289,7 +289,7 @@ will be stripped before it is returned.
|
|||
]]
|
||||
|
||||
---[[
|
||||
Strips unnescessary lua bytecode from given string.
|
||||
Strips unnecessary 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)
|
||||
|
|
66
luci-base/luasrc/view/admin_uci/changelog.htm
Normal file
66
luci-base/luasrc/view/admin_uci/changelog.htm
Normal file
|
@ -0,0 +1,66 @@
|
|||
<%#
|
||||
Copyright 2010 Jo-Philipp Wich <jo@mein.io>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<% export("uci_changelog", function(changes) -%>
|
||||
<div class="cbi-section">
|
||||
<strong><%:Legend:%></strong>
|
||||
<div class="uci-change-legend">
|
||||
<div class="uci-change-legend-label"><ins> </ins> <%:Section added%></div>
|
||||
<div class="uci-change-legend-label"><del> </del> <%:Section removed%></div>
|
||||
<div class="uci-change-legend-label"><var><ins> </ins></var> <%:Option changed%></div>
|
||||
<div class="uci-change-legend-label"><var><del> </del></var> <%:Option removed%></div>
|
||||
<br style="clear:both" />
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div class="uci-change-list"><%
|
||||
local util = luci.util
|
||||
local tpl = {
|
||||
["add-3"] = "<ins>uci add %0 <strong>%3</strong> # =%2</ins>",
|
||||
["set-3"] = "<ins>uci set %0.<strong>%2</strong>=%3</ins>",
|
||||
["set-4"] = "<var><ins>uci set %0.%2.%3=<strong>%4</strong></ins></var>",
|
||||
["remove-2"] = "<del>uci del %0.<strong>%2</strong></del>",
|
||||
["remove-3"] = "<var><del>uci del %0.%2.<strong>%3</strong></del></var>",
|
||||
["order-3"] = "<var>uci reorder %0.%2=<strong>%3</strong></var>",
|
||||
["list-add-4"] = "<var><ins>uci add_list %0.%2.%3=<strong>%4</strong></ins></var>",
|
||||
["list-del-4"] = "<var><del>uci del_list %0.%2.%3=<strong>%4</strong></del></var>",
|
||||
["rename-3"] = "<var>uci rename %0.%2=<strong>%3</strong></var>",
|
||||
["rename-4"] = "<var>uci rename %0.%2.%3=<strong>%4</strong></var>"
|
||||
}
|
||||
|
||||
local conf, deltas
|
||||
for conf, deltas in util.kspairs(changes) do
|
||||
write("<h3># /etc/config/%s</h3>" % conf)
|
||||
|
||||
local _, delta, added
|
||||
for _, delta in pairs(deltas) do
|
||||
local t = tpl["%s-%d" %{ delta[1], #delta }]
|
||||
|
||||
write(t:gsub("%%(%d)", function(n)
|
||||
if n == "0" then
|
||||
return conf
|
||||
elseif n == "2" then
|
||||
if added and delta[2] == added[1] then
|
||||
return "@%s[-1]" % added[2]
|
||||
else
|
||||
return delta[2]
|
||||
end
|
||||
elseif n == "4" then
|
||||
return util.shellquote(delta[4])
|
||||
else
|
||||
return delta[tonumber(n)]
|
||||
end
|
||||
end))
|
||||
|
||||
if delta[1] == "add" then
|
||||
added = { delta[2], delta[3] }
|
||||
end
|
||||
end
|
||||
|
||||
write("<br />")
|
||||
end
|
||||
%></div>
|
||||
</div>
|
||||
<%- end) %>
|
|
@ -1,49 +1,4 @@
|
|||
<% export("cbi_apply_widget", function(redirect_ok, rollback_token) -%>
|
||||
<style type="text/css">
|
||||
#cbi_apply_overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message {
|
||||
position: relative;
|
||||
top: 10%;
|
||||
width: 60%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message > h4,
|
||||
#cbi_apply_overlay .alert-message > p,
|
||||
#cbi_apply_overlay .alert-message > div {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message > img {
|
||||
margin-right: 1em;
|
||||
flex-basis: 32px;
|
||||
}
|
||||
|
||||
body.apply-overlay-active {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body.apply-overlay-active #cbi_apply_overlay {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js?v=git-18.138.59467-72fe5dd"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var xhr = new XHR(),
|
||||
uci_apply_auth = { sid: '<%=luci.dispatcher.context.authsession%>', token: '<%=token%>' },
|
||||
|
@ -55,28 +10,22 @@
|
|||
was_xhr_poll_running = false;
|
||||
|
||||
function uci_status_message(type, content) {
|
||||
var overlay = document.getElementById('cbi_apply_overlay') || document.body.appendChild(E('<div id="cbi_apply_overlay"><div class="alert-message"></div></div>')),
|
||||
message = overlay.querySelector('.alert-message');
|
||||
if (type) {
|
||||
var message = showModal('', '');
|
||||
|
||||
if (message && type) {
|
||||
if (!message.classList.contains(type)) {
|
||||
message.classList.remove('notice');
|
||||
message.classList.remove('warning');
|
||||
message.classList.add(type);
|
||||
}
|
||||
message.classList.add('alert-message');
|
||||
DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
|
||||
|
||||
if (content)
|
||||
message.innerHTML = content;
|
||||
|
||||
document.body.classList.add('apply-overlay-active');
|
||||
|
||||
if (!was_xhr_poll_running) {
|
||||
was_xhr_poll_running = XHR.running();
|
||||
XHR.halt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
document.body.classList.remove('apply-overlay-active');
|
||||
hideModal();
|
||||
|
||||
if (was_xhr_poll_running)
|
||||
XHR.run();
|
||||
|
@ -85,19 +34,18 @@
|
|||
|
||||
function uci_rollback(checked) {
|
||||
if (checked) {
|
||||
uci_status_message('warning',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Failed to confirm apply within %ds, waiting for rollback…%>'.format(uci_apply_rollback));
|
||||
uci_status_message('warning spinning',
|
||||
'<p><%:Failed to confirm apply within %ds, waiting for rollback…%></p>'.format(uci_apply_rollback));
|
||||
|
||||
var call = function(r, data, duration) {
|
||||
if (r.status === 204) {
|
||||
uci_status_message('warning',
|
||||
'<h4><%:Configuration has been rolled back!%></h4>' +
|
||||
'<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, perform an unchecked configuration apply. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
|
||||
'<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, proceed by applying anyway. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
|
||||
'<div class="right">' +
|
||||
'<input type="button" class="btn" onclick="uci_status_message(false)" value="<%:Dismiss%>" /> ' +
|
||||
'<input type="button" class="btn cbi-button-action important" onclick="uci_revert()" value="<%:Revert changes%>" /> ' +
|
||||
'<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply unchecked%>" />' +
|
||||
'<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply anyway%>" />' +
|
||||
'</div>');
|
||||
|
||||
return;
|
||||
|
@ -126,6 +74,7 @@
|
|||
|
||||
var call = function(r, data, duration) {
|
||||
if (Date.now() >= deadline) {
|
||||
window.clearTimeout(tt);
|
||||
uci_rollback(checked);
|
||||
return;
|
||||
}
|
||||
|
@ -133,7 +82,7 @@
|
|||
var indicator = document.querySelector('.uci_change_indicator');
|
||||
if (indicator) indicator.style.display = 'none';
|
||||
|
||||
uci_status_message('notice', '<%:Configuration has been applied.%>');
|
||||
uci_status_message('notice', '<p><%:Configuration has been applied.%></p>');
|
||||
|
||||
window.clearTimeout(tt);
|
||||
window.setTimeout(function() {
|
||||
|
@ -156,9 +105,8 @@
|
|||
var tick = function() {
|
||||
var now = Date.now();
|
||||
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Waiting for configuration to get applied… %ds%>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
|
||||
uci_status_message('notice spinning',
|
||||
'<p><%:Waiting for configuration to be applied… %ds%></p>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
|
||||
|
||||
if (now >= deadline)
|
||||
return;
|
||||
|
@ -174,9 +122,7 @@
|
|||
}
|
||||
|
||||
function uci_apply(checked) {
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Starting configuration apply…%>');
|
||||
uci_status_message('notice spinning', '<p><%:Starting configuration apply…%></p>');
|
||||
|
||||
xhr.post('<%=url("admin/uci")%>/' + (checked ? 'apply_rollback' : 'apply_unchecked'), uci_apply_auth, function(r, tok) {
|
||||
if (r.status === (checked ? 200 : 204)) {
|
||||
|
@ -186,7 +132,7 @@
|
|||
uci_confirm(checked, Date.now() + uci_apply_rollback * 1000);
|
||||
}
|
||||
else if (checked && r.status === 204) {
|
||||
uci_status_message('notice', '<%:There are no changes to apply.%>');
|
||||
uci_status_message('notice', '<p><%:There are no changes to apply.%></p>');
|
||||
window.setTimeout(function() {
|
||||
<% if redirect_ok then -%>
|
||||
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
|
||||
|
@ -196,20 +142,18 @@
|
|||
}, uci_apply_display * 1000);
|
||||
}
|
||||
else {
|
||||
uci_status_message('warning', '<%_Apply request failed with status <code>%h</code>%>'.format(r.responseText || r.statusText || r.status));
|
||||
uci_status_message('warning', '<p><%_Apply request failed with status <code>%h</code>%></p>'.format(r.responseText || r.statusText || r.status));
|
||||
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uci_revert() {
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Reverting configuration…%>');
|
||||
uci_status_message('notice spinning', '<p><%:Reverting configuration…%></p>');
|
||||
|
||||
xhr.post('<%=url("admin/uci/revert")%>', uci_apply_auth, function(r) {
|
||||
if (r.status === 200) {
|
||||
uci_status_message('notice', '<%:Changes have been reverted.%>');
|
||||
uci_status_message('notice', '<p><%:Changes have been reverted.%></p>');
|
||||
window.setTimeout(function() {
|
||||
<% if redirect_ok then -%>
|
||||
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
|
||||
|
@ -219,7 +163,7 @@
|
|||
}, uci_apply_display * 1000);
|
||||
}
|
||||
else {
|
||||
uci_status_message('warning', '<%_Revert request failed with status <code>%h</code>%>'.format(r.statusText || r.status));
|
||||
uci_status_message('warning', '<p><%_Revert request failed with status <code>%h</code>%></p>'.format(r.statusText || r.status));
|
||||
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<% local v = self:cfgvalue(section) -%>
|
||||
<%+cbi/valueheader%>
|
||||
<input class="cbi-input-text" type="text"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
|
||||
<script type="text/javascript">
|
||||
cbi_init()
|
||||
cbi_browser_init('<%=cbid%>', '<%=resource%>', '<%=url('admin/filebrowser')%>'<%=self.default_path and ", '"..self.default_path.."'"%>);
|
||||
</script>
|
||||
|
||||
<input class="cbi-input-text" type="text"<%=
|
||||
attr("id", cbid) ..
|
||||
attr("name", cbid) ..
|
||||
attr("value", self:cfgvalue(section) or self.default) ..
|
||||
attr("data-browser", self.default_path or "")
|
||||
%> />
|
||||
|
||||
<%+cbi/valuefooter%>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<div class="td cbi-value-field<% if self.error and self.error[section] then %> cbi-value-error<% end %>"<%=
|
||||
attr("data-name", self.option) ..
|
||||
ifattr(ftype and #ftype > 0, "data-type", ftype) ..
|
||||
ifattr(title and #title > 0, "data-title", title) ..
|
||||
ifattr(descr and #descr > 0, "data-description", descr)
|
||||
ifattr(title and #title > 0, "data-title", title, true) ..
|
||||
ifattr(descr and #descr > 0, "data-description", descr, true)
|
||||
%>>
|
||||
<div id="cbi-<%=self.config.."-"..section.."-"..self.option%>" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>">
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<li<%=
|
||||
attr("data-index", i) ..
|
||||
attr("data-depends", self:deplist2json(section, self.deplist[i])) ..
|
||||
attr("value", key) ..
|
||||
attr("data-value", key) ..
|
||||
ifattr(selected[key], "selected", "selected")
|
||||
%>>
|
||||
<%=pcdata(self.vallist[i])%>
|
||||
|
|
|
@ -6,22 +6,8 @@
|
|||
self.keylist, self.vallist,
|
||||
self.datatype, self.optional or self.rmempty
|
||||
})) ..
|
||||
|
||||
attr("data-values", luci.util.serialize_json(self:cfgvalue(section))) ..
|
||||
ifattr(self.size, "data-size", self.size) ..
|
||||
ifattr(self.placeholder, "data-placeholder", self.placeholder)
|
||||
%>>
|
||||
<%
|
||||
local vals = self:cfgvalue(section) or {}
|
||||
for i=1, #vals + 1 do
|
||||
local val = vals[i]
|
||||
if (val and #val > 0) or (i == 1) then
|
||||
%>
|
||||
<input class="cbi-input-text" value="<%=pcdata(val)%>" data-update="change" type="text"<%=
|
||||
attr("id", cbid .. "." .. i) ..
|
||||
attr("name", cbid) ..
|
||||
ifattr(self.size, "size") ..
|
||||
ifattr(i == 1 and self.placeholder, "placeholder", self.placeholder)
|
||||
%> /><br />
|
||||
<% end end %>
|
||||
</div>
|
||||
%>></div>
|
||||
<%+cbi/valuefooter%>
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
if empty then
|
||||
%>
|
||||
<label class="zonebadge zonebadge-empty">
|
||||
<strong><%=zone:forward():upper()%></strong>
|
||||
<strong><%=def:forward():upper()%></strong>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
ifattr(self.rmempty or self.optional, "optional", "optional")
|
||||
%>>
|
||||
<script type="item-template"><!--
|
||||
<li value="{{value}}">
|
||||
<li data-value="{{value}}">
|
||||
<span class="zonebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">
|
||||
<strong>{{value}}:</strong><em>(<%:create%>)</em>
|
||||
</span>
|
||||
|
@ -38,7 +38,7 @@
|
|||
--></script>
|
||||
<ul>
|
||||
<% if self.allowlocal then %>
|
||||
<li value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<li data-value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
|
||||
<strong><%:Device%></strong>
|
||||
<% if self.allowany and self.allowlocal then -%>
|
||||
|
@ -48,14 +48,14 @@
|
|||
</span>
|
||||
</li>
|
||||
<% elseif self.widget ~= "checkbox" and (self.rmempty or self.optional) then %>
|
||||
<li value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<li data-value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<span class="zonebadge">
|
||||
<em><%:unspecified%></em>
|
||||
</span>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if self.allowany then %>
|
||||
<li value="*"<%=ifattr(checked["*"], "selected", "selected")%>>
|
||||
<li data-value="*"<%=ifattr(checked["*"], "selected", "selected")%>>
|
||||
<span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
|
||||
<strong><%:Any zone%></strong>
|
||||
<% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %>
|
||||
|
@ -67,7 +67,7 @@
|
|||
if zone:name() ~= self.exclude then
|
||||
selected = selected or (value == zone:name())
|
||||
%>
|
||||
<li<%=attr("value", zone:name()) .. ifattr(checked[zone:name()], "selected", "selected")%>>
|
||||
<li<%=attr("data-value", zone:name()) .. ifattr(checked[zone:name()], "selected", "selected")%>>
|
||||
<span style="background-color:<%=zone:get_color()%>" class="zonebadge">
|
||||
<strong><%=zone:name()%>:</strong>
|
||||
<%-
|
||||
|
@ -94,11 +94,11 @@
|
|||
<% end end %>
|
||||
|
||||
<% if self.widget ~= "checkbox" and not self.nocreate then %>
|
||||
<li value="-">
|
||||
<li data-value="-">
|
||||
<span class="zonebadge">
|
||||
<em><%:create%>:</em>
|
||||
<input type="password" style="display:none" />
|
||||
<input class="create-item-input" type="text" />
|
||||
<input class="create-item-input" type="text" data-type="and(uciname,maxlength(11))" data-optional="true" />
|
||||
</span>
|
||||
</li>
|
||||
<% end %>
|
||||
|
|
27
luci-base/luasrc/view/cbi/ipaddr.htm
Normal file
27
luci-base/luasrc/view/cbi/ipaddr.htm
Normal file
|
@ -0,0 +1,27 @@
|
|||
<%+cbi/valueheader%>
|
||||
<script type="text/javascript">
|
||||
function switchToCIDRList(ev) {
|
||||
var input = ev.target.previousElementSibling,
|
||||
usecidr = document.getElementById(input.id + '_usecidr');
|
||||
|
||||
ev.preventDefault();
|
||||
|
||||
usecidr.value = '1';
|
||||
cbi_d_update();
|
||||
}
|
||||
</script>
|
||||
<input data-update="change"<%=
|
||||
attr("id", cbid) ..
|
||||
attr("name", cbid) ..
|
||||
attr("type", "text") ..
|
||||
attr("class", "cbi-input-text") ..
|
||||
attr("value", self:cfgvalue(section) or self.default) ..
|
||||
ifattr(self.size, "size") ..
|
||||
ifattr(self.placeholder, "placeholder") ..
|
||||
ifattr(self.datatype, "data-type", self.datatype) ..
|
||||
ifattr(self.datatype, "data-optional", self.optional or self.rmempty) ..
|
||||
ifattr(self.combobox_manual, "data-manual", self.combobox_manual) ..
|
||||
ifattr(#self.keylist > 0, "data-choices", { self.keylist, self.vallist })
|
||||
%> /><!--
|
||||
--><button class="cbi-button cbi-button-neutral" title="<%:Switch to CIDR list notation%>" aria-label="<%:Switch to CIDR list notation%>" onclick="switchToCIDRList(event)">…</button>
|
||||
<%+cbi/valuefooter%>
|
|
@ -3,25 +3,25 @@
|
|||
<%- end end -%>
|
||||
|
||||
<div class="cbi-map" id="cbi-<%=self.config%>">
|
||||
<% if self.title and #self.title > 0 then %><h2 name="content"><%=self.title%></h2><% end %>
|
||||
<% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
|
||||
<% if self.title and #self.title > 0 then %>
|
||||
<h2 name="content"><%=self.title%></h2>
|
||||
<% end %>
|
||||
<% if self.description and #self.description > 0 then %>
|
||||
<div class="cbi-map-descr"><%=self.description%></div>
|
||||
<% end %>
|
||||
<% if self.tabbed then %>
|
||||
<ul class="cbi-tabmenu map">
|
||||
<%- self.selected_tab = luci.http.formvalue("tab.m-" .. self.config) %>
|
||||
<% for i, section in ipairs(self.children) do %>
|
||||
<%- if not self.selected_tab then self.selected_tab = section.sectiontype end %>
|
||||
<li id="tab.m-<%=self.config%>.<%=section.section or section.sectiontype%>" class="cbi-tab<%=(section.sectiontype == self.selected_tab) and '' or '-disabled'%>">
|
||||
<a onclick="this.blur(); return cbi_t_switch('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')" href="<%=REQUEST_URI%>?tab.m-<%=self.config%>=<%=section.section or section.sectiontype%>"><%=section.title or section.section or section.sectiontype %></a>
|
||||
<% if section.sectiontype == self.selected_tab then %><input type="hidden" id="tab.m-<%=self.config%>" name="tab.m-<%=self.config%>" value="<%=section.section or section.sectiontype%>" /><% end %>
|
||||
</li>
|
||||
<div>
|
||||
<% for i, section in ipairs(self.children) do
|
||||
tab = section.section or section.sectiontype %>
|
||||
<div class="cbi-tabcontainer"<%=
|
||||
attr("id", "container.m-%s.%s" %{ self.config, tab }) ..
|
||||
attr("data-tab", tab) ..
|
||||
attr("data-tab-title", section.title or tab)
|
||||
%>>
|
||||
<% section:render() %>
|
||||
</div>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% for i, section in ipairs(self.children) do %>
|
||||
<div class="cbi-tabcontainer" id="container.m-<%=self.config%>.<%=section.section or section.sectiontype%>"<% if section.sectiontype ~= self.selected_tab then %> style="display:none"<% end %>>
|
||||
<% section:render() %>
|
||||
</div>
|
||||
<script type="text/javascript">cbi_t_add('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')</script>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if not self.save then -%>
|
||||
<div class="cbi-section-error">
|
||||
|
|
|
@ -41,13 +41,13 @@
|
|||
|
||||
<input type="hidden" name="<%=cbeid%>" value="1" />
|
||||
|
||||
<div class="cbi-dropdown" display-items="5" placeholder="<%:-- please select -- %>"<%=
|
||||
<div class="cbi-dropdown" display-items="10" placeholder="<%:-- please select -- %>"<%=
|
||||
attr("name", cbid) ..
|
||||
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
|
||||
ifattr(self.widget == "checkbox", "optional", "optional")
|
||||
%>>
|
||||
<script type="item-template"><!--
|
||||
<li value="{{value}}">
|
||||
<li data-value="{{value}}">
|
||||
<img title="<%:Custom Interface%>: "{{value}}"" src="<%=resource%>/icons/ethernet_disabled.png" />
|
||||
<span class="hide-open">{{value}}</span>
|
||||
<span class="hide-close"><%:Custom Interface%>: "{{value}}"</span>
|
||||
|
@ -61,7 +61,7 @@
|
|||
iface:name() ~= self.exclude
|
||||
then %>
|
||||
<li<%=
|
||||
attr("value", iface:name()) ..
|
||||
attr("data-value", iface:name()) ..
|
||||
ifattr(checked[iface:name()], "selected", "selected")
|
||||
%>>
|
||||
<img<%=attr("title", iface:get_i18n())%> src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
|
||||
|
@ -78,7 +78,7 @@
|
|||
</li>
|
||||
<% end end %>
|
||||
<% if not self.nocreate then %>
|
||||
<li value="">
|
||||
<li data-value="">
|
||||
<img title="<%:Custom Interface%>" src="<%=resource%>/icons/ethernet_disabled.png" />
|
||||
<span><%:Custom Interface%>:</span>
|
||||
<input type="password" style="display:none" />
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
end
|
||||
-%>
|
||||
|
||||
<div class="cbi-dropdown" display-items="5" placeholder="<%:-- please select -- %>"<%=
|
||||
<div class="cbi-dropdown" display-items="10" placeholder="<%:-- please select -- %>"<%=
|
||||
attr("name", cbid) ..
|
||||
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
|
||||
ifattr(self.widget == "checkbox", "optional", "optional")
|
||||
%>>
|
||||
<script type="item-template"><!--
|
||||
<li value="{{value}}">
|
||||
<li data-value="{{value}}">
|
||||
<span class="ifacebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">
|
||||
{{value}}: <em>(<%:create%>)</em>
|
||||
</span>
|
||||
|
@ -34,7 +34,7 @@
|
|||
--></script>
|
||||
<ul>
|
||||
<% if self.widget ~= "checkbox" then %>
|
||||
<li value=""<%= ifattr(not value, "selected", "selected") %>>
|
||||
<li data-value=""<%= ifattr(not value, "selected", "selected") %>>
|
||||
<em><%:unspecified%></em>
|
||||
</li>
|
||||
<% end %>
|
||||
|
@ -44,7 +44,7 @@
|
|||
(net:name() ~= self.exclude) and
|
||||
(not self.novirtual or not net:is_virtual())
|
||||
then %>
|
||||
<li<%= attr("value", net:name()) .. ifattr(checked[net:name()], "selected", "selected") %>>
|
||||
<li<%= attr("data-value", net:name()) .. ifattr(checked[net:name()], "selected", "selected") %>>
|
||||
<span class="ifacebadge"><%=net:name()%>:
|
||||
<%
|
||||
local empty = true
|
||||
|
@ -63,7 +63,7 @@
|
|||
<% end end %>
|
||||
|
||||
<% if not self.nocreate then %>
|
||||
<li value="-"<%= ifattr(not value and self.widget ~= "checkbox", "selected", "selected") %>>
|
||||
<li data-value="-"<%= ifattr(not value and self.widget ~= "checkbox", "selected", "selected") %>>
|
||||
<em>
|
||||
<%- if self.widget == "checkbox" then -%>
|
||||
<%:create:%>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
<input type="submit" class="cbi-button" name="cbi.rns.<%=self.config%>.<%=section%>" value="<%:Delete%>" />
|
||||
</div>
|
||||
<%- end %>
|
||||
<%+cbi/tabmenu%>
|
||||
<div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>">
|
||||
<%+cbi/ucisection%>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
<% for tab, data in pairs(self.tabs) do %>
|
||||
<div class="cbi-tabcontainer" id="container.<%=self.config%>.<%=section%>.<%=tab%>"<% if tab ~= self.selected_tab then %> style="display:none"<% end %>>
|
||||
<% if data.description then %><div class="cbi-tab-descr"><%=data.description%></div><% end %>
|
||||
<% for _, tab in ipairs(self.tab_names) do data = self.tabs[tab] %>
|
||||
<div class="cbi-tabcontainer"<%=
|
||||
attr("id", "container.%s.%s.%s" %{ self.config, section, tab }) ..
|
||||
attr("data-tab", tab) ..
|
||||
attr("data-tab-title", data.title) ..
|
||||
attr("data-tab-active", tostring(tab == self.selected_tab))
|
||||
%>>
|
||||
<% if data.description then %>
|
||||
<div class="cbi-tab-descr"><%=data.description%></div>
|
||||
<% end %>
|
||||
|
||||
<% self:render_tab(tab, section, scope or {}) %>
|
||||
</div>
|
||||
<script type="text/javascript">cbi_t_add('<%=self.config%>.<%=section%>', '<%=tab%>')</script>
|
||||
<% end %>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
<%- if self.tabs then %>
|
||||
<ul class="cbi-tabmenu">
|
||||
<%- self.selected_tab = luci.http.formvalue("tab." .. self.config .. "." .. section) %>
|
||||
<%- for _, tab in ipairs(self.tab_names) do if #self.tabs[tab].childs > 0 then %>
|
||||
<%- if not self.selected_tab then self.selected_tab = tab end %>
|
||||
<li id="tab.<%=self.config%>.<%=section%>.<%=tab%>" class="cbi-tab<%=(tab == self.selected_tab) and '' or '-disabled'%>">
|
||||
<a onclick="this.blur(); return cbi_t_switch('<%=self.config%>.<%=section%>', '<%=tab%>')" href="<%=REQUEST_URI%>?tab.<%=self.config%>.<%=section%>=<%=tab%>"><%=self.tabs[tab].title%></a>
|
||||
<% if tab == self.selected_tab then %><input type="hidden" id="tab.<%=self.config%>.<%=section%>" name="tab.<%=self.config%>.<%=section%>" value="<%=tab%>" /><% end %>
|
||||
</li>
|
||||
<% end end -%>
|
||||
</ul>
|
||||
<% end -%>
|
|
@ -127,7 +127,7 @@ end
|
|||
section = k
|
||||
|
||||
local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
|
||||
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname)
|
||||
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
|
||||
local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
|
||||
local scope = {
|
||||
valueheader = "cbi/cell_valueheader",
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
<% if self.title and #self.title > 0 then -%>
|
||||
<legend><%=self.title%></legend>
|
||||
<%- end %>
|
||||
<% if self.error_msg and #self.error_msg > 0 then -%>
|
||||
<div class="cbi-section-error">
|
||||
<%=self.error_msg%>
|
||||
</div>
|
||||
<%- end %>
|
||||
<% if self.description and #self.description > 0 then -%>
|
||||
<div class="cbi-section-descr"><%=self.description%></div>
|
||||
<%- end %>
|
||||
|
@ -18,8 +23,6 @@
|
|||
<h3><%=section:upper()%></h3>
|
||||
<%- end %>
|
||||
|
||||
<%+cbi/tabmenu%>
|
||||
|
||||
<div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>">
|
||||
<%+cbi/ucisection%>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<%+cbi/valueheader%>
|
||||
<%- if self.password then -%>
|
||||
<input type="password" style="position:absolute; left:-4000px"<%=
|
||||
<input type="password" style="position:absolute; left:-1000px" aria-hidden="true" tabindex="-1"<%=
|
||||
attr("name", "password." .. cbid)
|
||||
%> />
|
||||
<%- end -%>
|
||||
|
@ -21,6 +21,6 @@
|
|||
ifattr(#self.keylist > 0, "data-choices", { self.keylist, self.vallist })
|
||||
%> />
|
||||
<%- if self.password then -%>
|
||||
<div class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'">∗</div>
|
||||
<button class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" aria-label="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'; event.preventDefault()">∗</button>
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
||||
|
|
11
luci-base/luasrc/view/empty_node_placeholder.htm
Normal file
11
luci-base/luasrc/view/empty_node_placeholder.htm
Normal file
|
@ -0,0 +1,11 @@
|
|||
<%#
|
||||
Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
|
||||
Copyright 2018 Daniel F. Dickinson <cshored@thecshore.com>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<%+header%>
|
||||
|
||||
<p>Component not present.</p>
|
||||
|
||||
<%+footer%>
|
|
@ -10,3 +10,15 @@
|
|||
luci.dispatcher.context.template_header_sent = true
|
||||
end
|
||||
%>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/luci.js"></script>
|
||||
<script type="text/javascript">
|
||||
L = new LuCI(<%= luci.http.write_json({
|
||||
token = token,
|
||||
resource = resource,
|
||||
scriptname = luci.http.getenv("SCRIPT_NAME"),
|
||||
pathinfo = luci.http.getenv("PATH_INFO"),
|
||||
requestpath = luci.dispatcher.context.requestpath,
|
||||
pollinterval = luci.config.main.pollinterval or 5
|
||||
}) %>);
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script type="text/javascript">//<![CDATA[
|
||||
XHR.poll(5, '<%=url('admin/network/dhcplease_status')%>', null,
|
||||
XHR.poll(-1, '<%=url('admin/dhcplease_status')%>', null,
|
||||
function(x, st)
|
||||
{
|
||||
var tb = document.getElementById('lease_status_table');
|
|
@ -1,4 +1,21 @@
|
|||
<%
|
||||
local supports_deauth = {}
|
||||
|
||||
local _, v
|
||||
for _, v in ipairs(luci.util.ubus()) do
|
||||
local iface = v:match("^hostapd%.(.+)$")
|
||||
if iface then
|
||||
local funcs = luci.util.ubus(v)
|
||||
if type(funcs) == "table" and funcs.del_client then
|
||||
supports_deauth[iface] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var supports_deauth = <%= luci.http.write_json(supports_deauth) %>;
|
||||
|
||||
function wifirate(bss, rx) {
|
||||
var p = rx ? 'rx_' : 'tx_',
|
||||
s = '%.1f <%:Mbit/s%>, %d<%:MHz%>'
|
||||
|
@ -17,7 +34,17 @@
|
|||
return s;
|
||||
}
|
||||
|
||||
XHR.poll(5, '<%=url('admin/network/wireless_assoclist')%>', null,
|
||||
function handleDeauth(ev) {
|
||||
(new XHR()).post('<%=url('admin/wireless_deauth')%>', {
|
||||
token: '<%=token%>',
|
||||
iface: ev.target.getAttribute('data-iface'),
|
||||
bssid: ev.target.getAttribute('data-bssid')
|
||||
}, function() {
|
||||
ev.target.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
XHR.poll(-1, '<%=url('admin/wireless_assoclist')%>', null,
|
||||
function(x, st)
|
||||
{
|
||||
var tb = document.getElementById('wifi_assoclist_table');
|
||||
|
@ -58,7 +85,15 @@
|
|||
E('span', wifirate(bss, true)),
|
||||
E('br'),
|
||||
E('span', wifirate(bss, false))
|
||||
])
|
||||
]),
|
||||
supports_deauth[bss.ifname] ? E('input', {
|
||||
type: 'button',
|
||||
class: 'cbi-button cbi-button-remove',
|
||||
value: '<%:Disconnect%>',
|
||||
'data-bssid': bss.bssid,
|
||||
'data-iface': bss.ifname,
|
||||
click: handleDeauth
|
||||
}) : '-'
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -75,6 +110,9 @@
|
|||
<div class="th nowrap"><%:Host%></div>
|
||||
<div class="th nowrap"><%:Signal%> / <%:Noise%></div>
|
||||
<div class="th nowrap"><%:RX Rate%> / <%:TX Rate%></div>
|
||||
<% if next(supports_deauth) then %>
|
||||
<div class="th right"><%:Disconnect%></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="tr placeholder">
|
||||
<div class="td"><em><%:Collecting data...%></em></div>
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -3,9 +3,9 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||
<meta http-equiv="refresh" content="0; URL=/cgi-bin/luci" />
|
||||
<meta http-equiv="refresh" content="0; URL=/cgi-bin/luci/" />
|
||||
</head>
|
||||
<body style="background-color: white">
|
||||
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="/cgi-bin/luci">LuCI - Lua Configuration Interface</a>
|
||||
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="/cgi-bin/luci/">LuCI - Lua Configuration Interface</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
clean:
|
||||
rm -f po2lmo parser.so version.lua *.o
|
||||
|
||||
jsmin: jsmin.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
po2lmo: po2lmo.o template_lmo.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
|
|
292
luci-base/src/jsmin.c
Normal file
292
luci-base/src/jsmin.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
/* jsmin.c
|
||||
2011-09-30
|
||||
|
||||
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
|
||||
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 shall be used for Good, not Evil.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int theA;
|
||||
static int theB;
|
||||
static int theLookahead = EOF;
|
||||
|
||||
|
||||
/* isAlphanum -- return true if the character is a letter, digit, underscore,
|
||||
dollar sign, or non-ASCII character.
|
||||
*/
|
||||
|
||||
static int
|
||||
isAlphanum(int c)
|
||||
{
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
|
||||
c > 126);
|
||||
}
|
||||
|
||||
|
||||
/* get -- return the next character from stdin. Watch out for lookahead. If
|
||||
the character is a control character, translate it to a space or
|
||||
linefeed.
|
||||
*/
|
||||
|
||||
static int
|
||||
get()
|
||||
{
|
||||
int c = theLookahead;
|
||||
theLookahead = EOF;
|
||||
if (c == EOF) {
|
||||
c = getc(stdin);
|
||||
}
|
||||
if (c >= ' ' || c == '\n' || c == EOF) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\r') {
|
||||
return '\n';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
|
||||
/* peek -- get the next character without getting it.
|
||||
*/
|
||||
|
||||
static int
|
||||
peek()
|
||||
{
|
||||
theLookahead = get();
|
||||
return theLookahead;
|
||||
}
|
||||
|
||||
|
||||
/* next -- get the next character, excluding comments. peek() is used to see
|
||||
if a '/' is followed by a '/' or '*'.
|
||||
*/
|
||||
|
||||
static int
|
||||
next()
|
||||
{
|
||||
int c = get();
|
||||
if (c == '/') {
|
||||
switch (peek()) {
|
||||
case '/':
|
||||
for (;;) {
|
||||
c = get();
|
||||
if (c <= '\n') {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
case '*':
|
||||
get();
|
||||
for (;;) {
|
||||
switch (get()) {
|
||||
case '*':
|
||||
if (peek() == '/') {
|
||||
get();
|
||||
return ' ';
|
||||
}
|
||||
break;
|
||||
case EOF:
|
||||
fprintf(stderr, "Error: JSMIN Unterminated comment.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* action -- do something! What you do is determined by the argument:
|
||||
1 Output A. Copy B to A. Get the next B.
|
||||
2 Copy B to A. Get the next B. (Delete A).
|
||||
3 Get the next B. (Delete B).
|
||||
action treats a string as a single character. Wow!
|
||||
action recognizes a regular expression if it is preceded by ( or , or =.
|
||||
*/
|
||||
|
||||
static void
|
||||
action(int d)
|
||||
{
|
||||
switch (d) {
|
||||
case 1:
|
||||
putc(theA, stdout);
|
||||
case 2:
|
||||
theA = theB;
|
||||
if (theA == '\'' || theA == '"' || theA == '`') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == theB) {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr, "Error: JSMIN unterminated string literal.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
theB = next();
|
||||
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
|
||||
theA == ':' || theA == '[' || theA == '!' ||
|
||||
theA == '&' || theA == '|' || theA == '?' ||
|
||||
theA == '{' || theA == '}' || theA == ';' ||
|
||||
theA == '\n')) {
|
||||
putc(theA, stdout);
|
||||
putc(theB, stdout);
|
||||
for (;;) {
|
||||
theA = get();
|
||||
if (theA == '[') {
|
||||
for (;;) {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
if (theA == ']') {
|
||||
break;
|
||||
}
|
||||
if (theA == '\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr,
|
||||
"Error: JSMIN unterminated set in Regular Expression literal.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (theA == '/') {
|
||||
break;
|
||||
} else if (theA =='\\') {
|
||||
putc(theA, stdout);
|
||||
theA = get();
|
||||
}
|
||||
if (theA == EOF) {
|
||||
fprintf(stderr,
|
||||
"Error: JSMIN unterminated Regular Expression literal.\n");
|
||||
exit(1);
|
||||
}
|
||||
putc(theA, stdout);
|
||||
}
|
||||
theB = next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* jsmin -- Copy the input to the output, deleting the characters which are
|
||||
insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
Most spaces and linefeeds will be removed.
|
||||
*/
|
||||
|
||||
static void
|
||||
jsmin()
|
||||
{
|
||||
theA = '\n';
|
||||
action(3);
|
||||
while (theA != EOF) {
|
||||
switch (theA) {
|
||||
case ' ':
|
||||
if (isAlphanum(theB)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(2);
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
switch (theB) {
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
case '+':
|
||||
case '-':
|
||||
action(1);
|
||||
break;
|
||||
case ' ':
|
||||
action(3);
|
||||
break;
|
||||
default:
|
||||
if (isAlphanum(theB)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (theB) {
|
||||
case ' ':
|
||||
if (isAlphanum(theA)) {
|
||||
action(1);
|
||||
break;
|
||||
}
|
||||
action(3);
|
||||
break;
|
||||
case '\n':
|
||||
switch (theA) {
|
||||
case '}':
|
||||
case ']':
|
||||
case ')':
|
||||
case '+':
|
||||
case '-':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '`':
|
||||
action(1);
|
||||
break;
|
||||
default:
|
||||
if (isAlphanum(theA)) {
|
||||
action(1);
|
||||
} else {
|
||||
action(3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
action(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* main -- Output any command line arguments as comments
|
||||
and then minify the input.
|
||||
*/
|
||||
extern int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i += 1) {
|
||||
fprintf(stdout, "// %s\n", argv[i]);
|
||||
}
|
||||
jsmin();
|
||||
return 0;
|
||||
}
|
|
@ -46,14 +46,14 @@ uint32_t sfh_hash(const char *data, int len)
|
|||
switch (rem) {
|
||||
case 3: hash += sfh_get16(data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= data[sizeof(uint16_t)] << 18;
|
||||
hash ^= (signed char)data[sizeof(uint16_t)] << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2: hash += sfh_get16(data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1: hash += *data;
|
||||
case 1: hash += (signed char)*data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ int lmo_load_catalog(const char *lang, const char *dir)
|
|||
if (!_lmo_active_catalog)
|
||||
_lmo_active_catalog = cat;
|
||||
|
||||
return 0;
|
||||
return cat->archives ? 0 : -1;
|
||||
|
||||
err:
|
||||
if (dh) closedir(dh);
|
||||
|
@ -301,6 +301,20 @@ int lmo_translate(const char *key, int keylen, char **out, int *outlen)
|
|||
return -1;
|
||||
}
|
||||
|
||||
void lmo_iterate(lmo_iterate_cb_t cb, void *priv)
|
||||
{
|
||||
unsigned int i;
|
||||
lmo_entry_t *e;
|
||||
lmo_archive_t *ar;
|
||||
|
||||
if (!_lmo_active_catalog)
|
||||
return;
|
||||
|
||||
for (ar = _lmo_active_catalog->archives; ar; ar = ar->next)
|
||||
for (i = 0, e = &ar->index[0]; i < ar->length; e = &ar->index[++i])
|
||||
cb(ntohl(e->key_id), ar->mmap + ntohl(e->offset), ntohl(e->length), priv);
|
||||
}
|
||||
|
||||
void lmo_close_catalog(const char *lang)
|
||||
{
|
||||
lmo_archive_t *ar, *next;
|
||||
|
|
|
@ -73,6 +73,7 @@ struct lmo_catalog {
|
|||
|
||||
typedef struct lmo_catalog lmo_catalog_t;
|
||||
|
||||
typedef void (*lmo_iterate_cb_t)(uint32_t, const char *, int, void *);
|
||||
|
||||
uint32_t sfh_hash(const char *data, int len);
|
||||
uint32_t lmo_canon_hash(const char *data, int len);
|
||||
|
@ -87,6 +88,7 @@ extern lmo_catalog_t *_lmo_active_catalog;
|
|||
int lmo_load_catalog(const char *lang, const char *dir);
|
||||
int lmo_change_catalog(const char *lang);
|
||||
int lmo_translate(const char *key, int keylen, char **out, int *outlen);
|
||||
void lmo_iterate(lmo_iterate_cb_t cb, void *priv);
|
||||
void lmo_close_catalog(const char *lang);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -129,6 +129,24 @@ static int template_L_change_catalog(lua_State *L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void template_L_get_translations_cb(uint32_t key, const char *val, int len, void *priv) {
|
||||
lua_State *L = priv;
|
||||
char hex[9];
|
||||
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
snprintf(hex, sizeof(hex), "%08x", key);
|
||||
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushstring(L, hex);
|
||||
lua_pushlstring(L, val, len);
|
||||
lua_call(L, 2, 0);
|
||||
}
|
||||
|
||||
static int template_L_get_translations(lua_State *L) {
|
||||
lmo_iterate(template_L_get_translations_cb, L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int template_L_translate(lua_State *L) {
|
||||
size_t len;
|
||||
char *tr;
|
||||
|
@ -168,6 +186,7 @@ static const luaL_reg R[] = {
|
|||
{ "load_catalog", template_L_load_catalog },
|
||||
{ "close_catalog", template_L_close_catalog },
|
||||
{ "change_catalog", template_L_change_catalog },
|
||||
{ "get_translations", template_L_get_translations },
|
||||
{ "translate", template_L_translate },
|
||||
{ "hash", template_L_hash },
|
||||
{ NULL, NULL }
|
||||
|
|
|
@ -258,7 +258,7 @@ static int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf)
|
|||
break;
|
||||
}
|
||||
|
||||
/* advance beyound the last found valid continuation char */
|
||||
/* advance beyond the last found valid continuation char */
|
||||
o = v;
|
||||
ptr += v;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#
|
||||
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
|
||||
# Copyright (C) 2017-2019 Ycarus (Yannick Chabanois) <ycarus@zugaina.org>
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
@ -8,9 +7,8 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI Administration - full-featured for full control
|
||||
LUCI_DEPENDS:=+luci-base +luci-app-firewall +luci-lib-iptparser
|
||||
LUCI_DEPENDS:=+luci-base +luci-mod-status +luci-mod-system +luci-mod-network
|
||||
|
||||
PKG_BUILD_DEPENDS:=iwinfo
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
include ../luci/luci.mk
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<polyline id="rx" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
|
||||
<polyline id="tx" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
|
||||
|
||||
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
</svg>
|
Before Width: | Height: | Size: 1 KiB |
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<polyline id="tcp" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
|
||||
<polyline id="udp" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
|
||||
<polyline id="other" points="" style="fill:red;fill-opacity:0.4;stroke:red;stroke-width:1" />
|
||||
|
||||
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<polyline id="load01" points="" style="fill:#ff0000;fill-opacity:0.4;stroke:#ff0000;stroke-width:1" />
|
||||
<polyline id="load05" points="" style="fill:#ff6600;fill-opacity:0.4;stroke:#ff6600;stroke-width:1" />
|
||||
<polyline id="load15" points="" style="fill:#ffaa00;fill-opacity:0.4;stroke:#ffaa00;stroke-width:1" />
|
||||
|
||||
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<polyline id="rate" points="" style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1" />
|
||||
|
||||
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
</svg>
|
Before Width: | Height: | Size: 973 B |
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<polyline id="rssi" points="" style="fill:blue;fill-opacity:0.4;stroke:blue;stroke-width:1" />
|
||||
<polyline id="noise" points="" style="fill:red;fill-opacity:0.4;stroke:red;stroke-width:1" />
|
||||
|
||||
<line x1="0" y1="25%" x2="100%" y2="25%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_75" x="20" y="24%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="50%" x2="100%" y2="50%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_50" x="20" y="49%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
|
||||
<line x1="0" y1="75%" x2="100%" y2="75%" style="stroke:black;stroke-width:0.1" />
|
||||
<text id="label_25" x="20" y="74%" style="fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000"> </text>
|
||||
</svg>
|
Before Width: | Height: | Size: 1 KiB |
|
@ -1,42 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.controller.admin.index", package.seeall)
|
||||
|
||||
function index()
|
||||
local root = node()
|
||||
if not root.target then
|
||||
root.target = alias("admin")
|
||||
root.index = true
|
||||
end
|
||||
|
||||
local page = node("admin")
|
||||
page.target = firstchild()
|
||||
page.title = _("Administration")
|
||||
page.order = 10
|
||||
page.sysauth = "root"
|
||||
page.sysauth_authenticator = "htmlauth"
|
||||
page.ucidata = true
|
||||
page.index = true
|
||||
|
||||
-- Empty services menu to be populated by addons
|
||||
entry({"admin", "services"}, firstchild(), _("Services"), 40).index = true
|
||||
|
||||
entry({"admin", "logout"}, call("action_logout"), _("Logout"), 90)
|
||||
end
|
||||
|
||||
function action_logout()
|
||||
local dsp = require "luci.dispatcher"
|
||||
local utl = require "luci.util"
|
||||
local sid = dsp.context.authsession
|
||||
|
||||
if sid then
|
||||
utl.ubus("session", "destroy", { ubus_rpc_session = sid })
|
||||
|
||||
luci.http.header("Set-Cookie", "sysauth=%s; expires=%s; path=%s/" %{
|
||||
sid, 'Thu, 01 Jan 1970 01:00:00 GMT', dsp.build_url()
|
||||
})
|
||||
end
|
||||
|
||||
luci.http.redirect(dsp.build_url())
|
||||
end
|
|
@ -1,154 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.controller.admin.status", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "status"}, alias("admin", "status", "overview"), _("Status"), 20).index = true
|
||||
entry({"admin", "status", "overview"}, template("admin_status/index"), _("Overview"), 1)
|
||||
|
||||
entry({"admin", "status", "iptables"}, template("admin_status/iptables"), _("Firewall"), 2).leaf = true
|
||||
entry({"admin", "status", "iptables_action"}, post("action_iptables")).leaf = true
|
||||
|
||||
entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3)
|
||||
entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4)
|
||||
entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5)
|
||||
entry({"admin", "status", "processes"}, form("admin_status/processes"), _("Processes"), 6)
|
||||
|
||||
entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7)
|
||||
|
||||
entry({"admin", "status", "realtime", "load"}, template("admin_status/load"), _("Load"), 1).leaf = true
|
||||
entry({"admin", "status", "realtime", "load_status"}, call("action_load")).leaf = true
|
||||
|
||||
entry({"admin", "status", "realtime", "bandwidth"}, template("admin_status/bandwidth"), _("Traffic"), 2).leaf = true
|
||||
entry({"admin", "status", "realtime", "bandwidth_status"}, call("action_bandwidth")).leaf = true
|
||||
|
||||
if nixio.fs.access("/etc/config/wireless") then
|
||||
entry({"admin", "status", "realtime", "wireless"}, template("admin_status/wireless"), _("Wireless"), 3).leaf = true
|
||||
entry({"admin", "status", "realtime", "wireless_status"}, call("action_wireless")).leaf = true
|
||||
end
|
||||
|
||||
entry({"admin", "status", "realtime", "connections"}, template("admin_status/connections"), _("Connections"), 4).leaf = true
|
||||
entry({"admin", "status", "realtime", "connections_status"}, call("action_connections")).leaf = true
|
||||
|
||||
entry({"admin", "status", "nameinfo"}, call("action_nameinfo")).leaf = true
|
||||
end
|
||||
|
||||
function action_syslog()
|
||||
local syslog = luci.sys.syslog()
|
||||
luci.template.render("admin_status/syslog", {syslog=syslog})
|
||||
end
|
||||
|
||||
function action_dmesg()
|
||||
local dmesg = luci.sys.dmesg()
|
||||
luci.template.render("admin_status/dmesg", {dmesg=dmesg})
|
||||
end
|
||||
|
||||
function action_iptables()
|
||||
if luci.http.formvalue("zero") then
|
||||
if luci.http.formvalue("family") == "6" then
|
||||
luci.util.exec("/usr/sbin/ip6tables -Z")
|
||||
else
|
||||
luci.util.exec("/usr/sbin/iptables -Z")
|
||||
end
|
||||
elseif luci.http.formvalue("restart") then
|
||||
luci.util.exec("/etc/init.d/firewall restart")
|
||||
end
|
||||
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin/status/iptables"))
|
||||
end
|
||||
|
||||
function action_bandwidth(iface)
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
local bwc = io.popen("luci-bwc -i %s 2>/dev/null"
|
||||
% luci.util.shellquote(iface))
|
||||
|
||||
if bwc then
|
||||
luci.http.write("[")
|
||||
|
||||
while true do
|
||||
local ln = bwc:read("*l")
|
||||
if not ln then break end
|
||||
luci.http.write(ln)
|
||||
end
|
||||
|
||||
luci.http.write("]")
|
||||
bwc:close()
|
||||
end
|
||||
end
|
||||
|
||||
function action_wireless(iface)
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
local bwc = io.popen("luci-bwc -r %s 2>/dev/null"
|
||||
% luci.util.shellquote(iface))
|
||||
|
||||
if bwc then
|
||||
luci.http.write("[")
|
||||
|
||||
while true do
|
||||
local ln = bwc:read("*l")
|
||||
if not ln then break end
|
||||
luci.http.write(ln)
|
||||
end
|
||||
|
||||
luci.http.write("]")
|
||||
bwc:close()
|
||||
end
|
||||
end
|
||||
|
||||
function action_load()
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
local bwc = io.popen("luci-bwc -l 2>/dev/null")
|
||||
if bwc then
|
||||
luci.http.write("[")
|
||||
|
||||
while true do
|
||||
local ln = bwc:read("*l")
|
||||
if not ln then break end
|
||||
luci.http.write(ln)
|
||||
end
|
||||
|
||||
luci.http.write("]")
|
||||
bwc:close()
|
||||
end
|
||||
end
|
||||
|
||||
function action_connections()
|
||||
local sys = require "luci.sys"
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
|
||||
luci.http.write('{ "connections": ')
|
||||
luci.http.write_json(sys.net.conntrack())
|
||||
|
||||
local bwc = io.popen("luci-bwc -c 2>/dev/null")
|
||||
if bwc then
|
||||
luci.http.write(', "statistics": [')
|
||||
|
||||
while true do
|
||||
local ln = bwc:read("*l")
|
||||
if not ln then break end
|
||||
luci.http.write(ln)
|
||||
end
|
||||
|
||||
luci.http.write("]")
|
||||
bwc:close()
|
||||
end
|
||||
|
||||
luci.http.write(" }")
|
||||
end
|
||||
|
||||
function action_nameinfo(...)
|
||||
local util = require "luci.util"
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(util.ubus("network.rrdns", "lookup", {
|
||||
addrs = { ... },
|
||||
timeout = 5000,
|
||||
limit = 1000
|
||||
}) or { })
|
||||
end
|
|
@ -1,448 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.controller.admin.system", package.seeall)
|
||||
|
||||
function index()
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
entry({"admin", "system"}, alias("admin", "system", "system"), _("System"), 30).index = true
|
||||
entry({"admin", "system", "system"}, cbi("admin_system/system"), _("System"), 1)
|
||||
entry({"admin", "system", "clock_status"}, post_on({ set = true }, "action_clock_status"))
|
||||
|
||||
entry({"admin", "system", "admin"}, cbi("admin_system/admin"), _("Administration"), 2)
|
||||
|
||||
if fs.access("/bin/opkg") then
|
||||
entry({"admin", "system", "packages"}, post_on({ exec = "1" }, "action_packages"), _("Software"), 10)
|
||||
entry({"admin", "system", "packages", "ipkg"}, form("admin_system/ipkg"))
|
||||
end
|
||||
|
||||
entry({"admin", "system", "startup"}, form("admin_system/startup"), _("Startup"), 45)
|
||||
entry({"admin", "system", "crontab"}, form("admin_system/crontab"), _("Scheduled Tasks"), 46)
|
||||
|
||||
if fs.access("/sbin/block") and fs.access("/etc/config/fstab") then
|
||||
entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), _("Mount Points"), 50)
|
||||
entry({"admin", "system", "fstab", "mount"}, cbi("admin_system/fstab/mount"), nil).leaf = true
|
||||
entry({"admin", "system", "fstab", "swap"}, cbi("admin_system/fstab/swap"), nil).leaf = true
|
||||
end
|
||||
|
||||
local nodes, number = fs.glob("/sys/class/leds/*")
|
||||
if number > 0 then
|
||||
entry({"admin", "system", "leds"}, cbi("admin_system/leds"), _("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), 60)
|
||||
end
|
||||
|
||||
entry({"admin", "system", "flashops"}, call("action_flashops"), _("Backup / Flash Firmware"), 70)
|
||||
entry({"admin", "system", "flashops", "reset"}, post("action_reset"))
|
||||
entry({"admin", "system", "flashops", "backup"}, post("action_backup"))
|
||||
entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles"))
|
||||
|
||||
-- call() instead of post() due to upload handling!
|
||||
entry({"admin", "system", "flashops", "restore"}, call("action_restore"))
|
||||
entry({"admin", "system", "flashops", "sysupgrade"}, call("action_sysupgrade"))
|
||||
|
||||
entry({"admin", "system", "reboot"}, template("admin_system/reboot"), _("Reboot"), 90)
|
||||
entry({"admin", "system", "reboot", "call"}, post("action_reboot"))
|
||||
end
|
||||
|
||||
function action_clock_status()
|
||||
local set = tonumber(luci.http.formvalue("set"))
|
||||
if set ~= nil and set > 0 then
|
||||
local date = os.date("*t", set)
|
||||
if date then
|
||||
luci.sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d'" %{
|
||||
date.year, date.month, date.day, date.hour, date.min, date.sec
|
||||
})
|
||||
luci.sys.call("/etc/init.d/sysfixtime restart")
|
||||
end
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ timestring = os.date("%c") })
|
||||
end
|
||||
|
||||
function action_packages()
|
||||
local fs = require "nixio.fs"
|
||||
local ipkg = require "luci.model.ipkg"
|
||||
local submit = (luci.http.formvalue("exec") == "1")
|
||||
local update, upgrade
|
||||
local changes = false
|
||||
local install = { }
|
||||
local remove = { }
|
||||
local stdout = { "" }
|
||||
local stderr = { "" }
|
||||
local out, err
|
||||
|
||||
-- Display
|
||||
local display = luci.http.formvalue("display") or "available"
|
||||
|
||||
-- Letter
|
||||
local letter = string.byte(luci.http.formvalue("letter") or "A", 1)
|
||||
letter = (letter == 35 or (letter >= 65 and letter <= 90)) and letter or 65
|
||||
|
||||
-- Search query
|
||||
local query = luci.http.formvalue("query")
|
||||
query = (query ~= '') and query or nil
|
||||
|
||||
|
||||
-- Modifying actions
|
||||
if submit then
|
||||
-- Packets to be installed
|
||||
local ninst = luci.http.formvalue("install")
|
||||
local uinst = nil
|
||||
|
||||
-- Install from URL
|
||||
local url = luci.http.formvalue("url")
|
||||
if url and url ~= '' then
|
||||
uinst = url
|
||||
end
|
||||
|
||||
-- Do install
|
||||
if ninst then
|
||||
install[ninst], out, err = ipkg.install(ninst)
|
||||
stdout[#stdout+1] = out
|
||||
stderr[#stderr+1] = err
|
||||
changes = true
|
||||
end
|
||||
|
||||
if uinst then
|
||||
local pkg
|
||||
for pkg in luci.util.imatch(uinst) do
|
||||
install[uinst], out, err = ipkg.install(pkg)
|
||||
stdout[#stdout+1] = out
|
||||
stderr[#stderr+1] = err
|
||||
changes = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove packets
|
||||
local rem = luci.http.formvalue("remove")
|
||||
if rem then
|
||||
remove[rem], out, err = ipkg.remove(rem)
|
||||
stdout[#stdout+1] = out
|
||||
stderr[#stderr+1] = err
|
||||
changes = true
|
||||
end
|
||||
|
||||
|
||||
-- Update all packets
|
||||
update = luci.http.formvalue("update")
|
||||
if update then
|
||||
update, out, err = ipkg.update()
|
||||
stdout[#stdout+1] = out
|
||||
stderr[#stderr+1] = err
|
||||
end
|
||||
|
||||
|
||||
-- Upgrade all packets
|
||||
upgrade = luci.http.formvalue("upgrade")
|
||||
if upgrade then
|
||||
upgrade, out, err = ipkg.upgrade()
|
||||
stdout[#stdout+1] = out
|
||||
stderr[#stderr+1] = err
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- List state
|
||||
local no_lists = true
|
||||
local old_lists = false
|
||||
if fs.access("/var/opkg-lists/") then
|
||||
local list
|
||||
for list in fs.dir("/var/opkg-lists/") do
|
||||
no_lists = false
|
||||
if (fs.stat("/var/opkg-lists/"..list, "mtime") or 0) < (os.time() - (24 * 60 * 60)) then
|
||||
old_lists = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
luci.template.render("admin_system/packages", {
|
||||
display = display,
|
||||
letter = letter,
|
||||
query = query,
|
||||
install = install,
|
||||
remove = remove,
|
||||
update = update,
|
||||
upgrade = upgrade,
|
||||
no_lists = no_lists,
|
||||
old_lists = old_lists,
|
||||
stdout = table.concat(stdout, ""),
|
||||
stderr = table.concat(stderr, "")
|
||||
})
|
||||
|
||||
-- Remove index cache
|
||||
if changes then
|
||||
fs.unlink("/tmp/luci-indexcache")
|
||||
end
|
||||
end
|
||||
|
||||
local function image_supported(image)
|
||||
return (os.execute("sysupgrade -T %q >/dev/null" % image) == 0)
|
||||
end
|
||||
|
||||
local function image_checksum(image)
|
||||
return (luci.sys.exec("md5sum %q" % image):match("^([^%s]+)"))
|
||||
end
|
||||
|
||||
local function image_sha256_checksum(image)
|
||||
return (luci.sys.exec("sha256sum %q" % image):match("^([^%s]+)"))
|
||||
end
|
||||
|
||||
local function supports_sysupgrade()
|
||||
return nixio.fs.access("/lib/upgrade/platform.sh")
|
||||
end
|
||||
|
||||
local function supports_reset()
|
||||
return (os.execute([[grep -sq "^overlayfs:/overlay / overlay " /proc/mounts]]) == 0)
|
||||
end
|
||||
|
||||
local function storage_size()
|
||||
local size = 0
|
||||
if nixio.fs.access("/proc/mtd") then
|
||||
for l in io.lines("/proc/mtd") do
|
||||
local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
|
||||
if n == "linux" or n == "firmware" then
|
||||
size = tonumber(s, 16)
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif nixio.fs.access("/proc/partitions") then
|
||||
for l in io.lines("/proc/partitions") do
|
||||
local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)')
|
||||
if b and n and not n:match('[0-9]') then
|
||||
size = tonumber(b) * 1024
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return size
|
||||
end
|
||||
|
||||
|
||||
function action_flashops()
|
||||
--
|
||||
-- Overview
|
||||
--
|
||||
luci.template.render("admin_system/flashops", {
|
||||
reset_avail = supports_reset(),
|
||||
upgrade_avail = supports_sysupgrade()
|
||||
})
|
||||
end
|
||||
|
||||
function action_sysupgrade()
|
||||
local fs = require "nixio.fs"
|
||||
local http = require "luci.http"
|
||||
local image_tmp = "/tmp/firmware.img"
|
||||
|
||||
local fp
|
||||
http.setfilehandler(
|
||||
function(meta, chunk, eof)
|
||||
if not fp and meta and meta.name == "image" then
|
||||
fp = io.open(image_tmp, "w")
|
||||
end
|
||||
if fp and chunk then
|
||||
fp:write(chunk)
|
||||
end
|
||||
if fp and eof then
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
if not luci.dispatcher.test_post_security() then
|
||||
fs.unlink(image_tmp)
|
||||
return
|
||||
end
|
||||
|
||||
--
|
||||
-- Cancel firmware flash
|
||||
--
|
||||
if http.formvalue("cancel") then
|
||||
fs.unlink(image_tmp)
|
||||
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
|
||||
return
|
||||
end
|
||||
|
||||
--
|
||||
-- Initiate firmware flash
|
||||
--
|
||||
local step = tonumber(http.formvalue("step") or 1)
|
||||
if step == 1 then
|
||||
if image_supported(image_tmp) then
|
||||
luci.template.render("admin_system/upgrade", {
|
||||
checksum = image_checksum(image_tmp),
|
||||
sha256ch = image_sha256_checksum(image_tmp),
|
||||
storage = storage_size(),
|
||||
size = (fs.stat(image_tmp, "size") or 0),
|
||||
keep = (not not http.formvalue("keep"))
|
||||
})
|
||||
else
|
||||
fs.unlink(image_tmp)
|
||||
luci.template.render("admin_system/flashops", {
|
||||
reset_avail = supports_reset(),
|
||||
upgrade_avail = supports_sysupgrade(),
|
||||
image_invalid = true
|
||||
})
|
||||
end
|
||||
--
|
||||
-- Start sysupgrade flash
|
||||
--
|
||||
elseif step == 2 then
|
||||
local keep = (http.formvalue("keep") == "1") and "" or "-n"
|
||||
luci.template.render("admin_system/applyreboot", {
|
||||
title = luci.i18n.translate("Flashing..."),
|
||||
msg = luci.i18n.translate("The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
|
||||
addr = (#keep > 0) and "192.168.1.1" or nil
|
||||
})
|
||||
fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %q" %{ keep, image_tmp })
|
||||
end
|
||||
end
|
||||
|
||||
function action_backup()
|
||||
local reader = ltn12_popen("sysupgrade --create-backup - 2>/dev/null")
|
||||
|
||||
luci.http.header(
|
||||
'Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' %{
|
||||
luci.sys.hostname(),
|
||||
os.date("%Y-%m-%d")
|
||||
})
|
||||
|
||||
luci.http.prepare_content("application/x-targz")
|
||||
luci.ltn12.pump.all(reader, luci.http.write)
|
||||
end
|
||||
|
||||
function action_restore()
|
||||
local fs = require "nixio.fs"
|
||||
local http = require "luci.http"
|
||||
local archive_tmp = "/tmp/restore.tar.gz"
|
||||
|
||||
local fp
|
||||
http.setfilehandler(
|
||||
function(meta, chunk, eof)
|
||||
if not fp and meta and meta.name == "archive" then
|
||||
fp = io.open(archive_tmp, "w")
|
||||
end
|
||||
if fp and chunk then
|
||||
fp:write(chunk)
|
||||
end
|
||||
if fp and eof then
|
||||
fp:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
if not luci.dispatcher.test_post_security() then
|
||||
fs.unlink(archive_tmp)
|
||||
return
|
||||
end
|
||||
|
||||
local upload = http.formvalue("archive")
|
||||
if upload and #upload > 0 then
|
||||
if os.execute("gunzip -t %q >/dev/null 2>&1" % archive_tmp) == 0 then
|
||||
luci.template.render("admin_system/applyreboot")
|
||||
os.execute("tar -C / -xzf %q >/dev/null 2>&1" % archive_tmp)
|
||||
luci.sys.reboot()
|
||||
else
|
||||
luci.template.render("admin_system/flashops", {
|
||||
reset_avail = supports_reset(),
|
||||
upgrade_avail = supports_sysupgrade(),
|
||||
backup_invalid = true
|
||||
})
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
|
||||
end
|
||||
|
||||
function action_reset()
|
||||
if supports_reset() then
|
||||
luci.template.render("admin_system/applyreboot", {
|
||||
title = luci.i18n.translate("Erasing..."),
|
||||
msg = luci.i18n.translate("The system is erasing the configuration partition now and will reboot itself when finished."),
|
||||
addr = "192.168.1.1"
|
||||
})
|
||||
|
||||
fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; jffs2reset -y && reboot")
|
||||
return
|
||||
end
|
||||
|
||||
http.redirect(luci.dispatcher.build_url('admin/system/flashops'))
|
||||
end
|
||||
|
||||
function action_passwd()
|
||||
local p1 = luci.http.formvalue("pwd1")
|
||||
local p2 = luci.http.formvalue("pwd2")
|
||||
local stat = nil
|
||||
|
||||
if p1 or p2 then
|
||||
if p1 == p2 then
|
||||
stat = luci.sys.user.setpasswd("root", p1)
|
||||
else
|
||||
stat = 10
|
||||
end
|
||||
end
|
||||
|
||||
luci.template.render("admin_system/passwd", {stat=stat})
|
||||
end
|
||||
|
||||
function action_reboot()
|
||||
luci.sys.reboot()
|
||||
end
|
||||
|
||||
function fork_exec(command)
|
||||
local pid = nixio.fork()
|
||||
if pid > 0 then
|
||||
return
|
||||
elseif pid == 0 then
|
||||
-- change to root dir
|
||||
nixio.chdir("/")
|
||||
|
||||
-- patch stdin, out, err to /dev/null
|
||||
local null = nixio.open("/dev/null", "w+")
|
||||
if null then
|
||||
nixio.dup(null, nixio.stderr)
|
||||
nixio.dup(null, nixio.stdout)
|
||||
nixio.dup(null, nixio.stdin)
|
||||
if null:fileno() > 2 then
|
||||
null:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- replace with target command
|
||||
nixio.exec("/bin/sh", "-c", command)
|
||||
end
|
||||
end
|
||||
|
||||
function ltn12_popen(command)
|
||||
|
||||
local fdi, fdo = nixio.pipe()
|
||||
local pid = nixio.fork()
|
||||
|
||||
if pid > 0 then
|
||||
fdo:close()
|
||||
local close
|
||||
return function()
|
||||
local buffer = fdi:read(2048)
|
||||
local wpid, stat = nixio.waitpid(pid, "nohang")
|
||||
if not close and wpid and stat == "exited" then
|
||||
close = true
|
||||
end
|
||||
|
||||
if buffer and #buffer > 0 then
|
||||
return buffer
|
||||
elseif close then
|
||||
fdi:close()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
elseif pid == 0 then
|
||||
nixio.dup(fdo, nixio.stdout)
|
||||
fdi:close()
|
||||
fdo:close()
|
||||
nixio.exec("/bin/sh", "-c", command)
|
||||
end
|
||||
end
|
|
@ -1,67 +0,0 @@
|
|||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local map, section, net = ...
|
||||
|
||||
local device, apn, service, pincode, username, password
|
||||
local ipv6, maxwait, defaultroute, metric, peerdns, dns,
|
||||
keepalive_failure, keepalive_interval, demand
|
||||
|
||||
|
||||
mca = s:taboption("ahcp", Value, "multicast_address", translate("Multicast address"))
|
||||
mca.optional = true
|
||||
mca.placeholder = "ff02::cca6:c0f9:e182:5359"
|
||||
mca.datatype = "ip6addr"
|
||||
mca:depends("proto", "ahcp")
|
||||
|
||||
port = s:taboption("ahcp", Value, "port", translate("Port"))
|
||||
port.optional = true
|
||||
port.placeholder = 5359
|
||||
port.datatype = "port"
|
||||
port:depends("proto", "ahcp")
|
||||
|
||||
fam = s:taboption("ahcp", ListValue, "_family", translate("Protocol family"))
|
||||
fam:value("", translate("IPv4 and IPv6"))
|
||||
fam:value("ipv4", translate("IPv4 only"))
|
||||
fam:value("ipv6", translate("IPv6 only"))
|
||||
fam:depends("proto", "ahcp")
|
||||
|
||||
function fam.cfgvalue(self, section)
|
||||
local v4 = m.uci:get_bool("network", section, "ipv4_only")
|
||||
local v6 = m.uci:get_bool("network", section, "ipv6_only")
|
||||
if v4 then
|
||||
return "ipv4"
|
||||
elseif v6 then
|
||||
return "ipv6"
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function fam.write(self, section, value)
|
||||
if value == "ipv4" then
|
||||
m.uci:set("network", section, "ipv4_only", "true")
|
||||
m.uci:delete("network", section, "ipv6_only")
|
||||
elseif value == "ipv6" then
|
||||
m.uci:set("network", section, "ipv6_only", "true")
|
||||
m.uci:delete("network", section, "ipv4_only")
|
||||
end
|
||||
end
|
||||
|
||||
function fam.remove(self, section)
|
||||
m.uci:delete("network", section, "ipv4_only")
|
||||
m.uci:delete("network", section, "ipv6_only")
|
||||
end
|
||||
|
||||
nodns = s:taboption("ahcp", Flag, "no_dns", translate("Disable DNS setup"))
|
||||
nodns.optional = true
|
||||
nodns.enabled = "true"
|
||||
nodns.disabled = "false"
|
||||
nodns.default = nodns.disabled
|
||||
nodns:depends("proto", "ahcp")
|
||||
|
||||
ltime = s:taboption("ahcp", Value, "lease_time", translate("Lease validity time"))
|
||||
ltime.optional = true
|
||||
ltime.placeholder = 3666
|
||||
ltime.datatype = "uinteger"
|
||||
ltime:depends("proto", "ahcp")
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
-- Copyright 2018 Jo-Philipp Wich <jo@mein.io>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local utl = require "luci.util"
|
||||
local tpl = require "luci.template"
|
||||
local ntm = require "luci.model.network"
|
||||
|
||||
local has_iwinfo = pcall(require, "iwinfo")
|
||||
|
||||
function guess_wifi_hw(dev)
|
||||
local bands = ""
|
||||
local ifname = dev:name()
|
||||
local name, idx = ifname:match("^([a-z]+)(%d+)")
|
||||
idx = tonumber(idx)
|
||||
|
||||
if has_iwinfo then
|
||||
local bl = dev.iwinfo.hwmodelist
|
||||
if bl and next(bl) then
|
||||
if bl.a then bands = bands .. "a" end
|
||||
if bl.b then bands = bands .. "b" end
|
||||
if bl.g then bands = bands .. "g" end
|
||||
if bl.n then bands = bands .. "n" end
|
||||
if bl.ac then bands = bands .. "ac" end
|
||||
end
|
||||
|
||||
local hw = dev.iwinfo.hardware_name
|
||||
if hw then
|
||||
return "%s 802.11%s" %{ hw, bands }
|
||||
end
|
||||
end
|
||||
|
||||
-- wl.o
|
||||
if name == "wl" then
|
||||
local name = translatef("Broadcom 802.11%s Wireless Controller", bands)
|
||||
local nm = 0
|
||||
|
||||
local fd = nixio.open("/proc/bus/pci/devices", "r")
|
||||
if fd then
|
||||
local ln
|
||||
for ln in fd:linesource() do
|
||||
if ln:match("wl$") then
|
||||
if nm == idx then
|
||||
local version = ln:match("^%S+%s+%S%S%S%S([0-9a-f]+)")
|
||||
name = translatef(
|
||||
"Broadcom BCM%04x 802.11 Wireless Controller",
|
||||
tonumber(version, 16)
|
||||
)
|
||||
|
||||
break
|
||||
else
|
||||
nm = nm + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
end
|
||||
|
||||
return name
|
||||
|
||||
-- dunno yet
|
||||
else
|
||||
return translatef("Generic 802.11%s Wireless Controller", bands)
|
||||
end
|
||||
end
|
||||
|
||||
local tpl_radio = tpl.Template(nil, [[
|
||||
<div class="cbi-section-node">
|
||||
<div class="table">
|
||||
<!-- physical device -->
|
||||
<div class="tr cbi-rowstyle-2">
|
||||
<div class="td col-2 center middle">
|
||||
<span class="ifacebadge"><img src="<%=resource%>/icons/wifi_disabled.png" id="<%=dev:name()%>-iw-upstate" /> <%=dev:name()%></span>
|
||||
</div>
|
||||
<div class="td col-7 left middle">
|
||||
<big><strong><%=hw%></strong></big><br />
|
||||
<span id="<%=dev:name()%>-iw-devinfo"></span>
|
||||
</div>
|
||||
<div class="td middle cbi-section-actions">
|
||||
<div>
|
||||
<input type="button" class="cbi-button cbi-button-neutral" title="<%:Restart radio interface%>" value="<%:Restart%>" data-radio="<%=dev:name()%>" onclick="wifi_restart(event)" />
|
||||
<input type="button" class="cbi-button cbi-button-action important" title="<%:Find and join network%>" value="<%:Scan%>" onclick="cbi_submit(this, 'device', '<%=dev:name()%>', '<%=url('admin/network/wireless_join')%>')" />
|
||||
<input type="button" class="cbi-button cbi-button-add" title="<%:Provide new network%>" value="<%:Add%>" onclick="cbi_submit(this, 'device', '<%=dev:name()%>', '<%=url('admin/network/wireless_add')%>')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /physical device -->
|
||||
|
||||
<!-- network list -->
|
||||
<% if #wnets > 0 then %>
|
||||
<% for i, net in ipairs(wnets) do local disabled = (dev:get("disabled") == "1" or net:get("disabled") == "1") %>
|
||||
<div class="tr cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
|
||||
<div class="td col-2 center middle" id="<%=net:id()%>-iw-signal">
|
||||
<span class="ifacebadge" title="<%:Not associated%>"><img src="<%=resource%>/icons/signal-<%= disabled and "none" or "0" %>.png" /> 0%</span>
|
||||
</div>
|
||||
<div class="td col-7 left middle" id="<%=net:id()%>-iw-status" data-network="<%=net:id()%>" data-disabled="<%= disabled and "true" or "false" %>">
|
||||
<em><%= disabled and translate("Wireless is disabled") or translate("Collecting data...") %></em>
|
||||
</div>
|
||||
<div class="td middle cbi-section-actions">
|
||||
<div>
|
||||
<% if disabled then %>
|
||||
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="1" />
|
||||
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Enable this network%>" value="<%:Enable%>" onclick="this.previousElementSibling.value='0'" />
|
||||
<% else %>
|
||||
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="0" />
|
||||
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Disable this network%>" value="<%:Disable%>" onclick="this.previousElementSibling.value='1'" />
|
||||
<% end %>
|
||||
|
||||
<input type="button" class="cbi-button cbi-button-action important" onclick="location.href='<%=net:adminlink()%>'" title="<%:Edit this network%>" value="<%:Edit%>" />
|
||||
|
||||
<input name="cbid.wireless.<%=net:name()%>.__delete__" type="hidden" value="" />
|
||||
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-negative" title="<%:Delete this network%>" value="<%:Remove%>" onclick="wifi_delete(event)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="tr placeholder">
|
||||
<div class="td">
|
||||
<em><%:No network configured on this device%></em>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<!-- /network list -->
|
||||
</div>
|
||||
</div>
|
||||
]])
|
||||
|
||||
|
||||
m = Map("wireless", translate("Wireless Overview"))
|
||||
m:chain("network")
|
||||
m.pageaction = false
|
||||
|
||||
if not has_iwinfo then
|
||||
s = m:section(NamedSection, "__warning__")
|
||||
|
||||
function s.render(self)
|
||||
tpl.render_string([[
|
||||
<div class="alert-message warning">
|
||||
<h4><%:Package libiwinfo required!%></h4>
|
||||
<p><%_The <em>libiwinfo-lua</em> package is not installed. You must install this component for working wireless configuration!%></p>
|
||||
</div>
|
||||
]])
|
||||
end
|
||||
end
|
||||
|
||||
local _, dev, net
|
||||
for _, dev in ipairs(ntm:get_wifidevs()) do
|
||||
s = m:section(TypedSection)
|
||||
s.wnets = dev:get_wifinets()
|
||||
|
||||
function s.render(self, sid)
|
||||
tpl_radio:render({
|
||||
hw = guess_wifi_hw(dev),
|
||||
dev = dev,
|
||||
wnets = self.wnets
|
||||
})
|
||||
end
|
||||
|
||||
function s.cfgsections(self)
|
||||
local _, net, sl = nil, nil, { }
|
||||
for _, net in ipairs(self.wnets) do
|
||||
sl[#sl+1] = net:name()
|
||||
self.wnets[net:name()] = net
|
||||
end
|
||||
return sl
|
||||
end
|
||||
|
||||
o = s:option(Value, "__disable__")
|
||||
|
||||
function o.cfgvalue(self, sid)
|
||||
local wnet = self.section.wnets[sid]
|
||||
local wdev = wnet:get_device()
|
||||
|
||||
return ((wnet and wnet:get("disabled") == "1") or
|
||||
(wdev and wdev:get("disabled") == "1")) and "1" or "0"
|
||||
end
|
||||
|
||||
function o.write(self, sid, value)
|
||||
local wnet = self.section.wnets[sid]
|
||||
local wdev = wnet:get_device()
|
||||
|
||||
if value ~= "1" then
|
||||
wnet:set("disabled", nil)
|
||||
wdev:set("disabled", nil)
|
||||
else
|
||||
wnet:set("disabled", "1")
|
||||
end
|
||||
end
|
||||
|
||||
o.remove = o.write
|
||||
|
||||
|
||||
o = s:option(Value, "__delete__")
|
||||
|
||||
function o.write(self, sid, value)
|
||||
local wnet = self.section.wnets[sid]
|
||||
local nets = wnet:get_networks()
|
||||
|
||||
ntm:del_wifinet(wnet:id())
|
||||
|
||||
local _, net
|
||||
for _, net in ipairs(nets) do
|
||||
if net:is_empty() then
|
||||
ntm:del_network(net:name())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
s = m:section(NamedSection, "__script__")
|
||||
s.template = "admin_network/wifi_overview_status"
|
||||
|
||||
s = m:section(NamedSection, "__assoclist__")
|
||||
|
||||
function s.render(self, sid)
|
||||
tpl.render_string([[
|
||||
<h2><%:Associated Stations%></h2>
|
||||
<%+admin_network/wifi_assoclist%>
|
||||
]])
|
||||
end
|
||||
|
||||
return m
|
|
@ -1,34 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
f = SimpleForm("processes", translate("Processes"), translate("This list gives an overview over currently running system processes and their status."))
|
||||
f.reset = false
|
||||
f.submit = false
|
||||
|
||||
t = f:section(Table, luci.sys.process.list())
|
||||
t:option(DummyValue, "PID", translate("PID"))
|
||||
t:option(DummyValue, "USER", translate("Owner"))
|
||||
t:option(DummyValue, "COMMAND", translate("Command"))
|
||||
t:option(DummyValue, "%CPU", translate("CPU usage (%)"))
|
||||
t:option(DummyValue, "%MEM", translate("Memory usage (%)"))
|
||||
|
||||
hup = t:option(Button, "_hup", translate("Hang Up"))
|
||||
hup.inputstyle = "reload"
|
||||
function hup.write(self, section)
|
||||
null, self.tag_error[section] = luci.sys.process.signal(section, 1)
|
||||
end
|
||||
|
||||
term = t:option(Button, "_term", translate("Terminate"))
|
||||
term.inputstyle = "remove"
|
||||
function term.write(self, section)
|
||||
null, self.tag_error[section] = luci.sys.process.signal(section, 15)
|
||||
end
|
||||
|
||||
kill = t:option(Button, "_kill", translate("Kill"))
|
||||
kill.inputstyle = "reset"
|
||||
function kill.write(self, section)
|
||||
null, self.tag_error[section] = luci.sys.process.signal(section, 9)
|
||||
end
|
||||
|
||||
return f
|
|
@ -1,122 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
m = Map("system", translate("Router Password"),
|
||||
translate("Changes the administrator password for accessing the device"))
|
||||
|
||||
s = m:section(TypedSection, "_dummy", "")
|
||||
s.addremove = false
|
||||
s.anonymous = true
|
||||
|
||||
pw1 = s:option(Value, "pw1", translate("Password"))
|
||||
pw1.password = true
|
||||
|
||||
pw2 = s:option(Value, "pw2", translate("Confirmation"))
|
||||
pw2.password = true
|
||||
|
||||
function s.cfgsections()
|
||||
return { "_pass" }
|
||||
end
|
||||
|
||||
function m.parse(map)
|
||||
local v1 = pw1:formvalue("_pass")
|
||||
local v2 = pw2:formvalue("_pass")
|
||||
|
||||
if v1 and v2 and #v1 > 0 and #v2 > 0 then
|
||||
if v1 == v2 then
|
||||
if luci.sys.user.setpasswd(luci.dispatcher.context.authuser, v1) == 0 then
|
||||
m.message = translate("Password successfully changed!")
|
||||
else
|
||||
m.message = translate("Unknown Error, password not changed!")
|
||||
end
|
||||
else
|
||||
m.message = translate("Given password confirmation did not match, password not changed!")
|
||||
end
|
||||
end
|
||||
|
||||
Map.parse(map)
|
||||
end
|
||||
|
||||
|
||||
if fs.access("/etc/config/dropbear") then
|
||||
|
||||
m2 = Map("dropbear", translate("SSH Access"),
|
||||
translate("Dropbear offers <abbr title=\"Secure Shell\">SSH</abbr> network shell access and an integrated <abbr title=\"Secure Copy\">SCP</abbr> server"))
|
||||
|
||||
s = m2:section(TypedSection, "dropbear", translate("Dropbear Instance"))
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
|
||||
|
||||
ni = s:option(Value, "Interface", translate("Interface"),
|
||||
translate("Listen only on the given interface or, if unspecified, on all"))
|
||||
|
||||
ni.template = "cbi/network_netlist"
|
||||
ni.nocreate = true
|
||||
ni.unspecified = true
|
||||
|
||||
|
||||
pt = s:option(Value, "Port", translate("Port"),
|
||||
translate("Specifies the listening port of this <em>Dropbear</em> instance"))
|
||||
|
||||
pt.datatype = "port"
|
||||
pt.default = 22
|
||||
|
||||
|
||||
pa = s:option(Flag, "PasswordAuth", translate("Password authentication"),
|
||||
translate("Allow <abbr title=\"Secure Shell\">SSH</abbr> password authentication"))
|
||||
|
||||
pa.enabled = "on"
|
||||
pa.disabled = "off"
|
||||
pa.default = pa.enabled
|
||||
pa.rmempty = false
|
||||
|
||||
|
||||
ra = s:option(Flag, "RootPasswordAuth", translate("Allow root logins with password"),
|
||||
translate("Allow the <em>root</em> user to login with password"))
|
||||
|
||||
ra.enabled = "on"
|
||||
ra.disabled = "off"
|
||||
ra.default = ra.enabled
|
||||
|
||||
|
||||
gp = s:option(Flag, "GatewayPorts", translate("Gateway ports"),
|
||||
translate("Allow remote hosts to connect to local SSH forwarded ports"))
|
||||
|
||||
gp.enabled = "on"
|
||||
gp.disabled = "off"
|
||||
gp.default = gp.disabled
|
||||
|
||||
|
||||
s2 = m2:section(TypedSection, "_dummy", translate("SSH-Keys"),
|
||||
translate("Here you can paste public SSH-Keys (one per line) for SSH public-key authentication."))
|
||||
s2.addremove = false
|
||||
s2.anonymous = true
|
||||
s2.template = "cbi/tblsection"
|
||||
|
||||
function s2.cfgsections()
|
||||
return { "_keys" }
|
||||
end
|
||||
|
||||
keys = s2:option(TextValue, "_data", "")
|
||||
keys.wrap = "off"
|
||||
keys.rows = 3
|
||||
|
||||
function keys.cfgvalue()
|
||||
return fs.readfile("/etc/dropbear/authorized_keys") or ""
|
||||
end
|
||||
|
||||
function keys.write(self, section, value)
|
||||
return fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n"))
|
||||
end
|
||||
|
||||
function keys.remove(self, section, value)
|
||||
return fs.writefile("/etc/dropbear/authorized_keys", "")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return m, m2
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue