From d5dff8f9a5ca85d197cbb6037f95053bc55941e5 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sun, 3 Nov 2019 20:49:31 +0100 Subject: treewide: move server side CBI support to luci-compat Signed-off-by: Jo-Philipp Wich --- applications/luci-app-aria2/Makefile | 2 +- applications/luci-app-bmx7/Makefile | 2 +- applications/luci-app-clamav/Makefile | 2 +- applications/luci-app-commands/Makefile | 2 +- applications/luci-app-coovachilli/Makefile | 2 +- applications/luci-app-cshark/Makefile | 2 +- applications/luci-app-ddns/Makefile | 2 +- applications/luci-app-dnscrypt-proxy/Makefile | 2 +- applications/luci-app-dump1090/Makefile | 2 +- applications/luci-app-dynapoint/Makefile | 2 +- applications/luci-app-e2guardian/Makefile | 2 +- applications/luci-app-fwknopd/Makefile | 2 +- applications/luci-app-hd-idle/Makefile | 2 +- applications/luci-app-https_dns_proxy/Makefile | 2 +- applications/luci-app-ltqtapi/Makefile | 2 +- applications/luci-app-lxc/Makefile | 2 +- applications/luci-app-mjpg-streamer/Makefile | 2 +- applications/luci-app-mosquitto/Makefile | 2 +- applications/luci-app-nft-qos/Makefile | 2 +- applications/luci-app-noddos/Makefile | 2 +- applications/luci-app-ntpc/Makefile | 2 +- applications/luci-app-nut/Makefile | 1 + applications/luci-app-openvpn/Makefile | 2 +- applications/luci-app-pagekitec/Makefile | 2 +- applications/luci-app-polipo/Makefile | 2 +- applications/luci-app-privoxy/Makefile | 2 +- applications/luci-app-qos/Makefile | 2 +- applications/luci-app-radicale/Makefile | 2 +- applications/luci-app-radicale2/Makefile | 2 +- applications/luci-app-rosy-file-server/Makefile | 2 +- applications/luci-app-samba/Makefile | 2 +- applications/luci-app-samba4/Makefile | 2 +- applications/luci-app-shairplay/Makefile | 2 +- applications/luci-app-siitwizard/Makefile | 2 +- applications/luci-app-simple-adblock/Makefile | 2 +- applications/luci-app-snmpd/Makefile | 2 +- applications/luci-app-splash/Makefile | 2 +- applications/luci-app-squid/Makefile | 2 +- applications/luci-app-tinyproxy/Makefile | 2 +- applications/luci-app-transmission/Makefile | 2 +- applications/luci-app-udpxy/Makefile | 2 +- applications/luci-app-uhttpd/Makefile | 2 +- applications/luci-app-upnp/Makefile | 2 +- applications/luci-app-vpnbypass/Makefile | 2 +- applications/luci-app-watchcat/Makefile | 2 +- applications/luci-app-wifischedule/Makefile | 4 +- applications/luci-app-wol/Makefile | 2 +- build/mkbasepot.sh | 2 +- modules/luci-base/luasrc/cbi.lua | 1977 -------------------- modules/luci-base/luasrc/cbi/datatypes.lua | 470 ----- modules/luci-base/luasrc/model/firewall.lua | 568 ------ modules/luci-base/luasrc/view/cbi/browser.htm | 10 - modules/luci-base/luasrc/view/cbi/button.htm | 7 - .../luci-base/luasrc/view/cbi/cell_valuefooter.htm | 2 - .../luci-base/luasrc/view/cbi/cell_valueheader.htm | 12 - modules/luci-base/luasrc/view/cbi/compound.htm | 1 - modules/luci-base/luasrc/view/cbi/delegator.htm | 24 - modules/luci-base/luasrc/view/cbi/dropdown.htm | 19 - modules/luci-base/luasrc/view/cbi/dvalue.htm | 13 - modules/luci-base/luasrc/view/cbi/dynlist.htm | 12 - modules/luci-base/luasrc/view/cbi/error.htm | 19 - modules/luci-base/luasrc/view/cbi/footer.htm | 41 - .../luci-base/luasrc/view/cbi/full_valuefooter.htm | 12 - .../luci-base/luasrc/view/cbi/full_valueheader.htm | 9 - modules/luci-base/luasrc/view/cbi/fvalue.htm | 12 - modules/luci-base/luasrc/view/cbi/header.htm | 18 - modules/luci-base/luasrc/view/cbi/ipaddr.htm | 27 - modules/luci-base/luasrc/view/cbi/lvalue.htm | 14 - modules/luci-base/luasrc/view/cbi/map.htm | 40 - modules/luci-base/luasrc/view/cbi/mvalue.htm | 24 - modules/luci-base/luasrc/view/cbi/nsection.htm | 29 - modules/luci-base/luasrc/view/cbi/nullsection.htm | 37 - modules/luci-base/luasrc/view/cbi/simpleform.htm | 77 - modules/luci-base/luasrc/view/cbi/tabcontainer.htm | 14 - modules/luci-base/luasrc/view/cbi/tblsection.htm | 203 -- modules/luci-base/luasrc/view/cbi/tsection.htm | 52 - modules/luci-base/luasrc/view/cbi/tvalue.htm | 5 - modules/luci-base/luasrc/view/cbi/ucisection.htm | 56 - modules/luci-base/luasrc/view/cbi/upload.htm | 14 - modules/luci-base/luasrc/view/cbi/value.htm | 35 - modules/luci-base/luasrc/view/cbi/valuefooter.htm | 1 - modules/luci-base/luasrc/view/cbi/valueheader.htm | 1 - .../luasrc/view/cbi/wireless_modefreq.htm | 173 -- modules/luci-compat/luasrc/cbi.lua | 1977 ++++++++++++++++++++ modules/luci-compat/luasrc/cbi/datatypes.lua | 470 +++++ modules/luci-compat/luasrc/model/firewall.lua | 568 ++++++ modules/luci-compat/luasrc/view/cbi/browser.htm | 10 + modules/luci-compat/luasrc/view/cbi/button.htm | 7 + .../luasrc/view/cbi/cell_valuefooter.htm | 2 + .../luasrc/view/cbi/cell_valueheader.htm | 12 + modules/luci-compat/luasrc/view/cbi/compound.htm | 1 + modules/luci-compat/luasrc/view/cbi/delegator.htm | 24 + modules/luci-compat/luasrc/view/cbi/dropdown.htm | 19 + modules/luci-compat/luasrc/view/cbi/dvalue.htm | 13 + modules/luci-compat/luasrc/view/cbi/dynlist.htm | 12 + modules/luci-compat/luasrc/view/cbi/error.htm | 19 + modules/luci-compat/luasrc/view/cbi/footer.htm | 41 + .../luasrc/view/cbi/full_valuefooter.htm | 12 + .../luasrc/view/cbi/full_valueheader.htm | 9 + modules/luci-compat/luasrc/view/cbi/fvalue.htm | 12 + modules/luci-compat/luasrc/view/cbi/header.htm | 18 + modules/luci-compat/luasrc/view/cbi/ipaddr.htm | 27 + modules/luci-compat/luasrc/view/cbi/lvalue.htm | 14 + modules/luci-compat/luasrc/view/cbi/map.htm | 40 + modules/luci-compat/luasrc/view/cbi/mvalue.htm | 24 + modules/luci-compat/luasrc/view/cbi/nsection.htm | 29 + .../luci-compat/luasrc/view/cbi/nullsection.htm | 37 + modules/luci-compat/luasrc/view/cbi/simpleform.htm | 77 + .../luci-compat/luasrc/view/cbi/tabcontainer.htm | 14 + modules/luci-compat/luasrc/view/cbi/tblsection.htm | 203 ++ modules/luci-compat/luasrc/view/cbi/tsection.htm | 52 + modules/luci-compat/luasrc/view/cbi/tvalue.htm | 5 + modules/luci-compat/luasrc/view/cbi/ucisection.htm | 56 + modules/luci-compat/luasrc/view/cbi/upload.htm | 14 + modules/luci-compat/luasrc/view/cbi/value.htm | 35 + .../luci-compat/luasrc/view/cbi/valuefooter.htm | 1 + .../luci-compat/luasrc/view/cbi/valueheader.htm | 1 + .../luasrc/view/cbi/wireless_modefreq.htm | 173 ++ modules/luci-mod-admin-mini/Makefile | 2 +- 119 files changed, 4078 insertions(+), 4077 deletions(-) delete mode 100644 modules/luci-base/luasrc/cbi.lua delete mode 100644 modules/luci-base/luasrc/cbi/datatypes.lua delete mode 100644 modules/luci-base/luasrc/model/firewall.lua delete mode 100644 modules/luci-base/luasrc/view/cbi/browser.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/button.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/cell_valuefooter.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/cell_valueheader.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/compound.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/delegator.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/dropdown.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/dvalue.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/dynlist.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/error.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/footer.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/full_valuefooter.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/full_valueheader.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/fvalue.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/header.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/ipaddr.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/lvalue.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/map.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/mvalue.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/nsection.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/nullsection.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/simpleform.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/tabcontainer.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/tblsection.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/tsection.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/tvalue.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/ucisection.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/upload.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/value.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/valuefooter.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/valueheader.htm delete mode 100644 modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm create mode 100644 modules/luci-compat/luasrc/cbi.lua create mode 100644 modules/luci-compat/luasrc/cbi/datatypes.lua create mode 100644 modules/luci-compat/luasrc/model/firewall.lua create mode 100644 modules/luci-compat/luasrc/view/cbi/browser.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/button.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/cell_valuefooter.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/cell_valueheader.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/compound.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/delegator.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/dropdown.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/dvalue.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/dynlist.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/error.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/footer.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/full_valueheader.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/fvalue.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/header.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/ipaddr.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/lvalue.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/map.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/mvalue.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/nsection.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/nullsection.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/simpleform.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/tabcontainer.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/tblsection.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/tsection.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/tvalue.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/ucisection.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/upload.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/value.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/valuefooter.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/valueheader.htm create mode 100644 modules/luci-compat/luasrc/view/cbi/wireless_modefreq.htm diff --git a/applications/luci-app-aria2/Makefile b/applications/luci-app-aria2/Makefile index 541672f4d2..30089f8612 100644 --- a/applications/luci-app-aria2/Makefile +++ b/applications/luci-app-aria2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Aria2 -LUCI_DEPENDS:=+aria2 +luci-lib-ipkg +LUCI_DEPENDS:=+luci-compat +aria2 +luci-lib-ipkg LUCI_PKGARCH:=all PKG_MAINTAINER:=Xingwang Liao diff --git a/applications/luci-app-bmx7/Makefile b/applications/luci-app-bmx7/Makefile index d614327e34..546aeb9159 100644 --- a/applications/luci-app-bmx7/Makefile +++ b/applications/luci-app-bmx7/Makefile @@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for BMX7 -LUCI_DEPENDS:=+luci-lib-json +luci-mod-admin-full +bmx7 +bmx7-json +LUCI_DEPENDS:=+luci-compat +luci-lib-json +luci-mod-admin-full +bmx7 +bmx7-json PKG_MAINTAINER:= Roger Pueyo \ Pau Escrich PKG_LICENSE:=GPL-2.0-or-later diff --git a/applications/luci-app-clamav/Makefile b/applications/luci-app-clamav/Makefile index f91e692af8..93df9edc90 100644 --- a/applications/luci-app-clamav/Makefile +++ b/applications/luci-app-clamav/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=ClamAV LuCI interface -LUCI_DEPENDS:=+luci-mod-admin-full +clamav +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +clamav PKG_MAINTAINER:=Marko Ratkaj PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-commands/Makefile b/applications/luci-app-commands/Makefile index f41d6e2d42..8cd3cf51e8 100644 --- a/applications/luci-app-commands/Makefile +++ b/applications/luci-app-commands/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Shell Command Module -LUCI_DEPENDS:= +LUCI_DEPENDS:=+luci-compat PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-coovachilli/Makefile b/applications/luci-app-coovachilli/Makefile index 61209917cd..4bcafdc8f8 100644 --- a/applications/luci-app-coovachilli/Makefile +++ b/applications/luci-app-coovachilli/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Coova Chilli -LUCI_DEPENDS:=@BROKEN +LUCI_DEPENDS:=+luci-compat @BROKEN include ../../luci.mk diff --git a/applications/luci-app-cshark/Makefile b/applications/luci-app-cshark/Makefile index 40b0e9fb7f..c8a283bea4 100644 --- a/applications/luci-app-cshark/Makefile +++ b/applications/luci-app-cshark/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Cloudshark capture tool Web UI -LUCI_DEPENDS:=+cshark +LUCI_DEPENDS:=+luci-compat +cshark LUCI_PKGARCH:=all PKG_MAINTAINER:=Luka Perkov diff --git a/applications/luci-app-ddns/Makefile b/applications/luci-app-ddns/Makefile index eb3a77aee7..5084c88e42 100644 --- a/applications/luci-app-ddns/Makefile +++ b/applications/luci-app-ddns/Makefile @@ -23,7 +23,7 @@ PKG_MAINTAINER:=Ansuel Smith # LuCI specific settings LUCI_TITLE:=LuCI Support for Dynamic DNS Client (ddns-scripts) -LUCI_DEPENDS:=+luci-lib-ipkg +luci-mod-admin-full +ddns-scripts +LUCI_DEPENDS:=+luci-compat +luci-lib-ipkg +luci-mod-admin-full +ddns-scripts # LUCI_PKGARCH:=all define Package/$(PKG_NAME)/config diff --git a/applications/luci-app-dnscrypt-proxy/Makefile b/applications/luci-app-dnscrypt-proxy/Makefile index d34fec87d7..c67b83000f 100644 --- a/applications/luci-app-dnscrypt-proxy/Makefile +++ b/applications/luci-app-dnscrypt-proxy/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for DNSCrypt-Proxy -LUCI_DEPENDS:=+uclient-fetch +dnscrypt-proxy +luci-lib-httpprotoutils +LUCI_DEPENDS:=+luci-compat +uclient-fetch +dnscrypt-proxy +luci-lib-httpprotoutils LUCI_PKGARCH:=all include ../../luci.mk diff --git a/applications/luci-app-dump1090/Makefile b/applications/luci-app-dump1090/Makefile index e6abd44b39..81cf9f0ed4 100644 --- a/applications/luci-app-dump1090/Makefile +++ b/applications/luci-app-dump1090/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for dump1090 -LUCI_DEPENDS:=+dump1090 +LUCI_DEPENDS:=+luci-compat +dump1090 include ../../luci.mk diff --git a/applications/luci-app-dynapoint/Makefile b/applications/luci-app-dynapoint/Makefile index e405cc41f1..a763dc6146 100644 --- a/applications/luci-app-dynapoint/Makefile +++ b/applications/luci-app-dynapoint/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for DynaPoint -LUCI_DEPENDS:=+luci-lib-ipkg +dynapoint +LUCI_DEPENDS:=+luci-compat +luci-lib-ipkg +dynapoint PKG_LICENSE:=GPL-3.0+ PKG_MAINTAINER:=Tobias Ilte diff --git a/applications/luci-app-e2guardian/Makefile b/applications/luci-app-e2guardian/Makefile index c3ac029885..b21738bfdf 100644 --- a/applications/luci-app-e2guardian/Makefile +++ b/applications/luci-app-e2guardian/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=E2Guardian LuCI Interface -LUCI_DEPENDS:=+luci-mod-admin-full +e2guardian +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +e2guardian PKG_MAINTAINER:=Marko Ratkaj PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-fwknopd/Makefile b/applications/luci-app-fwknopd/Makefile index ba7a8568e7..73a9e6864f 100644 --- a/applications/luci-app-fwknopd/Makefile +++ b/applications/luci-app-fwknopd/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Fwknopd config - web config for the firewall knock daemon -LUCI_DEPENDS:=+fwknopd +qrencode +LUCI_DEPENDS:=+luci-compat +fwknopd +qrencode PKG_LICENSE:=GPLv2 PKG_MAINTAINER:=Jonathan Bennett include ../../luci.mk diff --git a/applications/luci-app-hd-idle/Makefile b/applications/luci-app-hd-idle/Makefile index 07d5cadd99..cba55796dd 100644 --- a/applications/luci-app-hd-idle/Makefile +++ b/applications/luci-app-hd-idle/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Hard Disk Idle Spin-Down module -LUCI_DEPENDS:=+hd-idle +LUCI_DEPENDS:=+luci-compat +hd-idle include ../../luci.mk diff --git a/applications/luci-app-https_dns_proxy/Makefile b/applications/luci-app-https_dns_proxy/Makefile index 09ee8a3a92..d08940e59f 100644 --- a/applications/luci-app-https_dns_proxy/Makefile +++ b/applications/luci-app-https_dns_proxy/Makefile @@ -8,7 +8,7 @@ PKG_MAINTAINER:=Stan Grishin LUCI_TITLE:=HTTPS DNS Proxy Web UI LUCI_DESCRIPTION:=Provides Web UI for HTTPS DNS Proxy -LUCI_DEPENDS:=+luci-mod-admin-full +https_dns_proxy +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +https_dns_proxy LUCI_PKGARCH:=all PKG_RELEASE:=5 diff --git a/applications/luci-app-ltqtapi/Makefile b/applications/luci-app-ltqtapi/Makefile index bf4a99928b..c969248126 100644 --- a/applications/luci-app-ltqtapi/Makefile +++ b/applications/luci-app-ltqtapi/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Lantiq Devices -LUCI_DEPENDS:=@BROKEN +LUCI_DEPENDS:=+luci-compat @BROKEN include ../../luci.mk diff --git a/applications/luci-app-lxc/Makefile b/applications/luci-app-lxc/Makefile index b46a83bdee..c096db7491 100644 --- a/applications/luci-app-lxc/Makefile +++ b/applications/luci-app-lxc/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LXC management Web UI -LUCI_DEPENDS:=+luci-mod-admin-full +lxc +lxc-attach +lxc-console +lxc-create +liblxc +rpcd-mod-lxc +getopt +!LXC_BUSYBOX_OPTIONS:tar +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +lxc +lxc-attach +lxc-console +lxc-create +liblxc +rpcd-mod-lxc +getopt +!LXC_BUSYBOX_OPTIONS:tar LUCI_PKGARCH:=all define Package/luci-app-lxc/conffiles diff --git a/applications/luci-app-mjpg-streamer/Makefile b/applications/luci-app-mjpg-streamer/Makefile index faa024d1a7..876e99dd41 100644 --- a/applications/luci-app-mjpg-streamer/Makefile +++ b/applications/luci-app-mjpg-streamer/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=MJPG-Streamer service configuration module -LUCI_DEPENDS:=+mjpg-streamer +LUCI_DEPENDS:=+luci-compat +mjpg-streamer include ../../luci.mk diff --git a/applications/luci-app-mosquitto/Makefile b/applications/luci-app-mosquitto/Makefile index 1bfb7c3de7..7713bcf8ec 100644 --- a/applications/luci-app-mosquitto/Makefile +++ b/applications/luci-app-mosquitto/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Mosquitto LuCI interface -LUCI_DEPENDS:=+luci-mod-admin-full mosquitto +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full mosquitto LUCI_PKGARCH:=all LUCI_DESCRIPTION:=Provides a webadmin for most basic mosquitto parameters. diff --git a/applications/luci-app-nft-qos/Makefile b/applications/luci-app-nft-qos/Makefile index 01de879937..4f86217c43 100644 --- a/applications/luci-app-nft-qos/Makefile +++ b/applications/luci-app-nft-qos/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Qos over Nftables -LUCI_DEPENDS:=+nft-qos +LUCI_DEPENDS:=+luci-compat +nft-qos include ../../luci.mk diff --git a/applications/luci-app-noddos/Makefile b/applications/luci-app-noddos/Makefile index 4c2b9044a9..3a40938d9c 100644 --- a/applications/luci-app-noddos/Makefile +++ b/applications/luci-app-noddos/Makefile @@ -9,7 +9,7 @@ PKG_MAINTAINER:=Steven Hessing LUCI_TITLE:=Noddos Service Web UI LUCI_DESCRIPTION:=Provides Web UI for Noddos service. -LUCI_DEPENDS:=+luci +noddos +LUCI_DEPENDS:=+luci +luci-compat +noddos LUCI_PKGARCH:=all PKG_RELEASE:=1 diff --git a/applications/luci-app-ntpc/Makefile b/applications/luci-app-ntpc/Makefile index b30f967a1c..b144b7ba93 100644 --- a/applications/luci-app-ntpc/Makefile +++ b/applications/luci-app-ntpc/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=NTP time synchronisation configuration module -LUCI_DEPENDS:=+ntpclient +LUCI_DEPENDS:=+luci-compat +ntpclient include ../../luci.mk diff --git a/applications/luci-app-nut/Makefile b/applications/luci-app-nut/Makefile index b5c5b0d4c3..cce56e0c9f 100644 --- a/applications/luci-app-nut/Makefile +++ b/applications/luci-app-nut/Makefile @@ -8,6 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Network UPS Tools Configuration +LUCI_DEPENDS:=+luci-compat LUCI_PKGARCH:=all PKG_RELEASE:=1 diff --git a/applications/luci-app-openvpn/Makefile b/applications/luci-app-openvpn/Makefile index 380ee73a6d..4dfcc682ce 100644 --- a/applications/luci-app-openvpn/Makefile +++ b/applications/luci-app-openvpn/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for OpenVPN -LUCI_DEPENDS:= +LUCI_DEPENDS:=+luci-compat PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-pagekitec/Makefile b/applications/luci-app-pagekitec/Makefile index d875009772..ea61323420 100644 --- a/applications/luci-app-pagekitec/Makefile +++ b/applications/luci-app-pagekitec/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for PageKite -LUCI_DEPENDS:=+pagekitec +LUCI_DEPENDS:=+luci-compat +pagekitec PKG_MAINTAINER:=Karl Palsson diff --git a/applications/luci-app-polipo/Makefile b/applications/luci-app-polipo/Makefile index 1fbafe7ed6..0bd1843322 100644 --- a/applications/luci-app-polipo/Makefile +++ b/applications/luci-app-polipo/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for the Polipo Proxy -LUCI_DEPENDS:=+polipo +LUCI_DEPENDS:=+luci-compat +polipo include ../../luci.mk diff --git a/applications/luci-app-privoxy/Makefile b/applications/luci-app-privoxy/Makefile index 6728172836..f558603795 100644 --- a/applications/luci-app-privoxy/Makefile +++ b/applications/luci-app-privoxy/Makefile @@ -21,7 +21,7 @@ PKG_MAINTAINER:= # LuCI specific settings LUCI_TITLE:=LuCI Support for Privoxy WEB proxy -LUCI_DEPENDS:=+luci-lib-ipkg +luci-mod-admin-full +privoxy +LUCI_DEPENDS:=+luci-compat +luci-lib-ipkg +luci-mod-admin-full +privoxy LUCI_PKGARCH:=all define Package/$(PKG_NAME)/config diff --git a/applications/luci-app-qos/Makefile b/applications/luci-app-qos/Makefile index fd12557453..8361b6e2e6 100644 --- a/applications/luci-app-qos/Makefile +++ b/applications/luci-app-qos/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Quality of Service configuration module -LUCI_DEPENDS:=+qos-scripts +LUCI_DEPENDS:=+luci-compat +qos-scripts PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-radicale/Makefile b/applications/luci-app-radicale/Makefile index 90ef0deba6..b70683674e 100644 --- a/applications/luci-app-radicale/Makefile +++ b/applications/luci-app-radicale/Makefile @@ -21,7 +21,7 @@ PKG_MAINTAINER:= # LuCI specific settings LUCI_TITLE:=LuCI Support for Radicale CardDAV/CalDAV -LUCI_DEPENDS:=+luci-lib-ipkg +luci-mod-admin-full +LUCI_DEPENDS:=+luci-compat +luci-lib-ipkg +luci-mod-admin-full LUCI_PKGARCH:=all define Package/$(PKG_NAME)/config diff --git a/applications/luci-app-radicale2/Makefile b/applications/luci-app-radicale2/Makefile index 83a2e7125e..09551b06f6 100644 --- a/applications/luci-app-radicale2/Makefile +++ b/applications/luci-app-radicale2/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Radicale v2.x CalDAV/CardDAV Server -LUCI_DEPENDS:=+radicale2 +rpcd-mod-rad2-enc +LUCI_DEPENDS:=+luci-compat +radicale2 +rpcd-mod-rad2-enc LUCI_PKGARCH:=all PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-rosy-file-server/Makefile b/applications/luci-app-rosy-file-server/Makefile index 93d9a3a669..e048925b42 100644 --- a/applications/luci-app-rosy-file-server/Makefile +++ b/applications/luci-app-rosy-file-server/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Rosy File Server -LUCI_DEPENDS:=+luci-base +rosy-file-server +LUCI_DEPENDS:=+luci-compat +luci-base +rosy-file-server include ../../luci.mk diff --git a/applications/luci-app-samba/Makefile b/applications/luci-app-samba/Makefile index ba599b30c3..7c08c0f813 100644 --- a/applications/luci-app-samba/Makefile +++ b/applications/luci-app-samba/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Network Shares - Samba SMB/CIFS module -LUCI_DEPENDS:=+samba36-server +LUCI_DEPENDS:=+luci-compat +samba36-server include ../../luci.mk diff --git a/applications/luci-app-samba4/Makefile b/applications/luci-app-samba4/Makefile index 08403fb2fc..3366dd8a16 100644 --- a/applications/luci-app-samba4/Makefile +++ b/applications/luci-app-samba4/Makefile @@ -3,7 +3,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Network Shares - Samba 4 SMB/CIFS module -LUCI_DEPENDS:=+samba4-server +LUCI_DEPENDS:=+luci-compat +samba4-server include ../../luci.mk diff --git a/applications/luci-app-shairplay/Makefile b/applications/luci-app-shairplay/Makefile index dcc0611785..59ca53d1b1 100644 --- a/applications/luci-app-shairplay/Makefile +++ b/applications/luci-app-shairplay/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Shairplay -LUCI_DEPENDS:=+shairplay +LUCI_DEPENDS:=+luci-compat +shairplay include ../../luci.mk diff --git a/applications/luci-app-siitwizard/Makefile b/applications/luci-app-siitwizard/Makefile index e8a8e555e4..a411f6aa3d 100644 --- a/applications/luci-app-siitwizard/Makefile +++ b/applications/luci-app-siitwizard/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=SIIT IPv4-over-IPv6 configuration wizard -LUCI_DEPENDS:=+kmod-siit +LUCI_DEPENDS:=+luci-compat +kmod-siit include ../../luci.mk diff --git a/applications/luci-app-simple-adblock/Makefile b/applications/luci-app-simple-adblock/Makefile index a46abb821e..8a666d635a 100644 --- a/applications/luci-app-simple-adblock/Makefile +++ b/applications/luci-app-simple-adblock/Makefile @@ -8,7 +8,7 @@ PKG_MAINTAINER:=Stan Grishin LUCI_TITLE:=Simple Adblock Web UI LUCI_DESCRIPTION:=Provides Web UI for simple-adblock service. -LUCI_DEPENDS:=+luci-mod-admin-full +simple-adblock +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +simple-adblock LUCI_PKGARCH:=all PKG_RELEASE:=38 diff --git a/applications/luci-app-snmpd/Makefile b/applications/luci-app-snmpd/Makefile index 4c67a1558a..fc998ba282 100644 --- a/applications/luci-app-snmpd/Makefile +++ b/applications/luci-app-snmpd/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:= Net-SNMP LuCI interface -LUCI_DEPENDS:= +luci-base +LUCI_DEPENDS:=+luci-compat +luci-base LUCI_PKGARCH:=all LUCI_DESCRIPTION:=Some common net-snmp config items. In no way is this comprehensive. diff --git a/applications/luci-app-splash/Makefile b/applications/luci-app-splash/Makefile index 4653724871..db9117225f 100644 --- a/applications/luci-app-splash/Makefile +++ b/applications/luci-app-splash/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Freifunk DHCP-Splash application -LUCI_DEPENDS:=+luci-lib-nixio +luci-lib-iptparser +tc +kmod-sched +iptables-mod-nat-extra +iptables-mod-ipopt +LUCI_DEPENDS:=+luci-compat +luci-lib-nixio +luci-lib-iptparser +tc +kmod-sched +iptables-mod-nat-extra +iptables-mod-ipopt define Package/luci-app-splash/conffiles /etc/config/luci_splash diff --git a/applications/luci-app-squid/Makefile b/applications/luci-app-squid/Makefile index 82802c0e5a..b16bd5d752 100644 --- a/applications/luci-app-squid/Makefile +++ b/applications/luci-app-squid/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Squid LuCI Interface -LUCI_DEPENDS:=+luci-mod-admin-full +squid +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +squid PKG_MAINTAINER:=Marko Ratkaj PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-tinyproxy/Makefile b/applications/luci-app-tinyproxy/Makefile index 02751b849d..f4c7475b8b 100644 --- a/applications/luci-app-tinyproxy/Makefile +++ b/applications/luci-app-tinyproxy/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Tinyproxy - HTTP(S)-Proxy configuration -LUCI_DEPENDS:=+tinyproxy +LUCI_DEPENDS:=+luci-compat +tinyproxy include ../../luci.mk diff --git a/applications/luci-app-transmission/Makefile b/applications/luci-app-transmission/Makefile index 42b29e9a4c..1a1166f2d5 100644 --- a/applications/luci-app-transmission/Makefile +++ b/applications/luci-app-transmission/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Transmission -LUCI_DEPENDS:=+luci-lib-ipkg +LUCI_DEPENDS:=+luci-compat +luci-lib-ipkg include ../../luci.mk diff --git a/applications/luci-app-udpxy/Makefile b/applications/luci-app-udpxy/Makefile index cb8f179232..c4286baaff 100644 --- a/applications/luci-app-udpxy/Makefile +++ b/applications/luci-app-udpxy/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for udpxy -LUCI_DEPENDS:=+udpxy +LUCI_DEPENDS:=+luci-compat +udpxy include ../../luci.mk diff --git a/applications/luci-app-uhttpd/Makefile b/applications/luci-app-uhttpd/Makefile index 3014770665..a365353cc6 100644 --- a/applications/luci-app-uhttpd/Makefile +++ b/applications/luci-app-uhttpd/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=uHTTPd Webserver Configuration -LUCI_DEPENDS:=+uhttpd +LUCI_DEPENDS:=+luci-compat +uhttpd LUCI_PKGARCH:=all PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-upnp/Makefile b/applications/luci-app-upnp/Makefile index 324e3e2aa4..bd3cdeb3f2 100644 --- a/applications/luci-app-upnp/Makefile +++ b/applications/luci-app-upnp/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=Universal Plug & Play configuration module -LUCI_DEPENDS:=+miniupnpd +LUCI_DEPENDS:=+luci-compat +miniupnpd include ../../luci.mk diff --git a/applications/luci-app-vpnbypass/Makefile b/applications/luci-app-vpnbypass/Makefile index 1bf076f0a2..cddcf85363 100644 --- a/applications/luci-app-vpnbypass/Makefile +++ b/applications/luci-app-vpnbypass/Makefile @@ -8,7 +8,7 @@ PKG_MAINTAINER:=Stan Grishin LUCI_TITLE:=VPN Bypass Web UI LUCI_DESCRIPTION:=Provides Web UI for VPNBypass service. -LUCI_DEPENDS:=+luci-mod-admin-full +vpnbypass +LUCI_DEPENDS:=+luci-compat +luci-mod-admin-full +vpnbypass LUCI_PKGARCH:=all PKG_RELEASE:=13 diff --git a/applications/luci-app-watchcat/Makefile b/applications/luci-app-watchcat/Makefile index 7ad86c84c0..58e12ecbf5 100644 --- a/applications/luci-app-watchcat/Makefile +++ b/applications/luci-app-watchcat/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Watchcat -LUCI_DEPENDS:=+watchcat +LUCI_DEPENDS:=+luci-compat +watchcat include ../../luci.mk diff --git a/applications/luci-app-wifischedule/Makefile b/applications/luci-app-wifischedule/Makefile index 1708562a4e..891b41bf5a 100644 --- a/applications/luci-app-wifischedule/Makefile +++ b/applications/luci-app-wifischedule/Makefile @@ -10,12 +10,12 @@ # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -# Author: Nils Koenig +# Author: Nils Koenig include $(TOPDIR)/rules.mk LUCI_TITLE:=Turns WiFi on and off according to a schedule -LUCI_DEPENDS:=+wifischedule +LUCI_DEPENDS:=+luci-compat +wifischedule include ../../luci.mk diff --git a/applications/luci-app-wol/Makefile b/applications/luci-app-wol/Makefile index d935ee9030..9ffc322d39 100644 --- a/applications/luci-app-wol/Makefile +++ b/applications/luci-app-wol/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Support for Wake-on-LAN -LUCI_DEPENDS:=+etherwake +LUCI_DEPENDS:=+luci-compat +etherwake include ../../luci.mk diff --git a/build/mkbasepot.sh b/build/mkbasepot.sh index ce41e30cee..0f9247536b 100755 --- a/build/mkbasepot.sh +++ b/build/mkbasepot.sh @@ -8,7 +8,7 @@ echo -n "Updating modules/luci-base/po/templates/base.pot ... " ./build/i18n-scan.pl \ - modules/luci-base/ modules/luci-mod-admin-full/ \ + modules/luci-base/ modules/luci-compat/ modules/luci-mod-admin-full/ \ modules/luci-mod-network modules/luci-mod-status modules/luci-mod-system/ \ protocols/ themes/ \ > modules/luci-base/po/templates/base.pot diff --git a/modules/luci-base/luasrc/cbi.lua b/modules/luci-base/luasrc/cbi.lua deleted file mode 100644 index 450e413916..0000000000 --- a/modules/luci-base/luasrc/cbi.lua +++ /dev/null @@ -1,1977 +0,0 @@ --- Copyright 2008 Steven Barth --- Licensed to the public under the Apache License 2.0. - -module("luci.cbi", package.seeall) - -require("luci.template") -local util = require("luci.util") -require("luci.http") - - ---local event = require "luci.sys.event" -local fs = require("nixio.fs") -local uci = require("luci.model.uci") -local datatypes = require("luci.cbi.datatypes") -local dispatcher = require("luci.dispatcher") -local class = util.class -local instanceof = util.instanceof - -FORM_NODATA = 0 -FORM_PROCEED = 0 -FORM_VALID = 1 -FORM_DONE = 1 -FORM_INVALID = -1 -FORM_CHANGED = 2 -FORM_SKIP = 4 - -AUTO = true - -CREATE_PREFIX = "cbi.cts." -REMOVE_PREFIX = "cbi.rts." -RESORT_PREFIX = "cbi.sts." -FEXIST_PREFIX = "cbi.cbe." - --- Loads a CBI map from given file, creating an environment and returns it -function load(cbimap, ...) - local fs = require "nixio.fs" - local i18n = require "luci.i18n" - require("luci.config") - require("luci.util") - - local upldir = "/etc/luci-uploads/" - local cbidir = luci.util.libpath() .. "/model/cbi/" - local func, err - - if fs.access(cbidir..cbimap..".lua") then - func, err = loadfile(cbidir..cbimap..".lua") - elseif fs.access(cbimap) then - func, err = loadfile(cbimap) - else - func, err = nil, "Model '" .. cbimap .. "' not found!" - end - - assert(func, err) - - local env = { - translate=i18n.translate, - translatef=i18n.translatef, - arg={...} - } - - setfenv(func, setmetatable(env, {__index = - function(tbl, key) - return rawget(tbl, key) or _M[key] or _G[key] - end})) - - local maps = { func() } - local uploads = { } - local has_upload = false - - for i, map in ipairs(maps) do - if not instanceof(map, Node) then - error("CBI map returns no valid map object!") - return nil - else - map:prepare() - if map.upload_fields then - has_upload = true - for _, field in ipairs(map.upload_fields) do - uploads[ - field.config .. '.' .. - (field.section.sectiontype or '1') .. '.' .. - field.option - ] = true - end - end - end - end - - if has_upload then - local uci = luci.model.uci.cursor() - local prm = luci.http.context.request.message.params - local fd, cbid - - luci.http.setfilehandler( - function( field, chunk, eof ) - if not field then return end - if field.name and not cbid then - local c, s, o = field.name:gmatch( - "cbid%.([^%.]+)%.([^%.]+)%.([^%.]+)" - )() - - if c and s and o then - local t = uci:get( c, s ) or s - if uploads[c.."."..t.."."..o] then - local path = upldir .. field.name - fd = io.open(path, "w") - if fd then - cbid = field.name - prm[cbid] = path - end - end - end - end - - if field.name == cbid and fd then - fd:write(chunk) - end - - if eof and fd then - fd:close() - fd = nil - cbid = nil - end - end - ) - end - - return maps -end - --- --- Compile a datatype specification into a parse tree for evaluation later on --- -local cdt_cache = { } - -function compile_datatype(code) - local i - local pos = 0 - local esc = false - local depth = 0 - local stack = { } - - for i = 1, #code+1 do - local byte = code:byte(i) or 44 - if esc then - esc = false - elseif byte == 92 then - esc = true - elseif byte == 40 or byte == 44 then - if depth <= 0 then - if pos < i then - local label = code:sub(pos, i-1) - :gsub("\\(.)", "%1") - :gsub("^%s+", "") - :gsub("%s+$", "") - - if #label > 0 and tonumber(label) then - stack[#stack+1] = tonumber(label) - elseif label:match("^'.*'$") or label:match('^".*"$') then - stack[#stack+1] = label:gsub("[\"'](.*)[\"']", "%1") - elseif type(datatypes[label]) == "function" then - stack[#stack+1] = datatypes[label] - stack[#stack+1] = { } - else - error("Datatype error, bad token %q" % label) - end - end - pos = i + 1 - end - depth = depth + (byte == 40 and 1 or 0) - elseif byte == 41 then - depth = depth - 1 - if depth <= 0 then - if type(stack[#stack-1]) ~= "function" then - error("Datatype error, argument list follows non-function") - end - stack[#stack] = compile_datatype(code:sub(pos, i-1)) - pos = i + 1 - end - end - end - - return stack -end - -function verify_datatype(dt, value) - if dt and #dt > 0 then - if not cdt_cache[dt] then - local c = compile_datatype(dt) - if c and type(c[1]) == "function" then - cdt_cache[dt] = c - else - error("Datatype error, not a function expression") - end - end - if cdt_cache[dt] then - return cdt_cache[dt][1](value, unpack(cdt_cache[dt][2])) - end - end - return true -end - - --- Node pseudo abstract class -Node = class() - -function Node.__init__(self, title, description) - self.children = {} - self.title = title or "" - self.description = description or "" - self.template = "cbi/node" -end - --- hook helper -function Node._run_hook(self, hook) - if type(self[hook]) == "function" then - return self[hook](self) - end -end - -function Node._run_hooks(self, ...) - local f - local r = false - for _, f in ipairs(arg) do - if type(self[f]) == "function" then - self[f](self) - r = true - end - end - return r -end - --- Prepare nodes -function Node.prepare(self, ...) - for k, child in ipairs(self.children) do - child:prepare(...) - end -end - --- Append child nodes -function Node.append(self, obj) - table.insert(self.children, obj) -end - --- Parse this node and its children -function Node.parse(self, ...) - for k, child in ipairs(self.children) do - child:parse(...) - end -end - --- Render this node -function Node.render(self, scope) - scope = scope or {} - scope.self = self - - luci.template.render(self.template, scope) -end - --- Render the children -function Node.render_children(self, ...) - local k, node - for k, node in ipairs(self.children) do - node.last_child = (k == #self.children) - node.index = k - node:render(...) - end -end - - ---[[ -A simple template element -]]-- -Template = class(Node) - -function Template.__init__(self, template) - Node.__init__(self) - self.template = template -end - -function Template.render(self) - luci.template.render(self.template, {self=self}) -end - -function Template.parse(self, readinput) - self.readinput = (readinput ~= false) - return Map.formvalue(self, "cbi.submit") and FORM_DONE or FORM_NODATA -end - - ---[[ -Map - A map describing a configuration file -]]-- -Map = class(Node) - -function Map.__init__(self, config, ...) - Node.__init__(self, ...) - - self.config = config - self.parsechain = {self.config} - self.template = "cbi/map" - self.apply_on_parse = nil - self.readinput = true - self.proceed = false - self.flow = {} - - self.uci = uci.cursor() - self.save = true - - self.changed = false - - local path = "%s/%s" %{ self.uci:get_confdir(), self.config } - if fs.stat(path, "type") ~= "reg" then - fs.writefile(path, "") - end - - local ok, err = self.uci:load(self.config) - if not ok then - local url = dispatcher.build_url(unpack(dispatcher.context.request)) - local source = self:formvalue("cbi.source") - if type(source) == "string" then - fs.writefile(path, source:gsub("\r\n", "\n")) - ok, err = self.uci:load(self.config) - if ok then - luci.http.redirect(url) - end - end - self.save = false - end - - if not ok then - self.template = "cbi/error" - self.error = err - self.source = fs.readfile(path) or "" - self.pageaction = false - end -end - -function Map.formvalue(self, key) - return self.readinput and luci.http.formvalue(key) or nil -end - -function Map.formvaluetable(self, key) - return self.readinput and luci.http.formvaluetable(key) or {} -end - -function Map.get_scheme(self, sectiontype, option) - if not option then - return self.scheme and self.scheme.sections[sectiontype] - else - return self.scheme and self.scheme.variables[sectiontype] - and self.scheme.variables[sectiontype][option] - end -end - -function Map.submitstate(self) - return self:formvalue("cbi.submit") -end - --- Chain foreign config -function Map.chain(self, config) - table.insert(self.parsechain, config) -end - -function Map.state_handler(self, state) - return state -end - --- Use optimized UCI writing -function Map.parse(self, readinput, ...) - if self:formvalue("cbi.skip") then - self.state = FORM_SKIP - elseif not self.save then - self.state = FORM_INVALID - elseif not self:submitstate() then - self.state = FORM_NODATA - end - - -- Back out early to prevent unauthorized changes on the subsequent parse - if self.state ~= nil then - return self:state_handler(self.state) - end - - self.readinput = (readinput ~= false) - self:_run_hooks("on_parse") - - Node.parse(self, ...) - - if self.save then - self:_run_hooks("on_save", "on_before_save") - local i, config - for i, config in ipairs(self.parsechain) do - self.uci:save(config) - end - self:_run_hooks("on_after_save") - if (not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply") then - self:_run_hooks("on_before_commit") - if self.apply_on_parse == false then - for i, config in ipairs(self.parsechain) do - self.uci:commit(config) - end - end - self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") - if self.apply_on_parse == true or self.apply_on_parse == false then - self.uci:apply(self.apply_on_parse) - self:_run_hooks("on_apply", "on_after_apply") - else - -- This is evaluated by the dispatcher and delegated to the - -- template which in turn fires XHR to perform the actual - -- apply actions. - self.apply_needed = true - end - - -- Reparse sections - Node.parse(self, true) - end - for i, config in ipairs(self.parsechain) do - self.uci:unload(config) - end - if type(self.commit_handler) == "function" then - self:commit_handler(self:submitstate()) - end - end - - if not self.save then - self.state = FORM_INVALID - elseif self.proceed then - self.state = FORM_PROCEED - elseif self.changed then - self.state = FORM_CHANGED - else - self.state = FORM_VALID - end - - return self:state_handler(self.state) -end - -function Map.render(self, ...) - self:_run_hooks("on_init") - Node.render(self, ...) -end - --- Creates a child section -function Map.section(self, class, ...) - if instanceof(class, AbstractSection) then - local obj = class(self, ...) - self:append(obj) - return obj - else - error("class must be a descendent of AbstractSection") - end -end - --- UCI add -function Map.add(self, sectiontype) - return self.uci:add(self.config, sectiontype) -end - --- UCI set -function Map.set(self, section, option, value) - if type(value) ~= "table" or #value > 0 then - if option then - return self.uci:set(self.config, section, option, value) - else - return self.uci:set(self.config, section, value) - end - else - return Map.del(self, section, option) - end -end - --- UCI del -function Map.del(self, section, option) - if option then - return self.uci:delete(self.config, section, option) - else - return self.uci:delete(self.config, section) - end -end - --- UCI get -function Map.get(self, section, option) - if not section then - return self.uci:get_all(self.config) - elseif option then - return self.uci:get(self.config, section, option) - else - return self.uci:get_all(self.config, section) - end -end - ---[[ -Compound - Container -]]-- -Compound = class(Node) - -function Compound.__init__(self, ...) - Node.__init__(self) - self.template = "cbi/compound" - self.children = {...} -end - -function Compound.populate_delegator(self, delegator) - for _, v in ipairs(self.children) do - v.delegator = delegator - end -end - -function Compound.parse(self, ...) - local cstate, state = 0 - - for k, child in ipairs(self.children) do - cstate = child:parse(...) - state = (not state or cstate < state) and cstate or state - end - - return state -end - - ---[[ -Delegator - Node controller -]]-- -Delegator = class(Node) -function Delegator.__init__(self, ...) - Node.__init__(self, ...) - self.nodes = {} - self.defaultpath = {} - self.pageaction = false - self.readinput = true - self.allow_reset = false - self.allow_cancel = false - self.allow_back = false - self.allow_finish = false - self.template = "cbi/delegator" -end - -function Delegator.set(self, name, node) - assert(not self.nodes[name], "Duplicate entry") - - self.nodes[name] = node -end - -function Delegator.add(self, name, node) - node = self:set(name, node) - self.defaultpath[#self.defaultpath+1] = name -end - -function Delegator.insert_after(self, name, after) - local n = #self.chain + 1 - for k, v in ipairs(self.chain) do - if v == after then - n = k + 1 - break - end - end - table.insert(self.chain, n, name) -end - -function Delegator.set_route(self, ...) - local n, chain, route = 0, self.chain, {...} - for i = 1, #chain do - if chain[i] == self.current then - n = i - break - end - end - for i = 1, #route do - n = n + 1 - chain[n] = route[i] - end - for i = n + 1, #chain do - chain[i] = nil - end -end - -function Delegator.get(self, name) - local node = self.nodes[name] - - if type(node) == "string" then - node = load(node, name) - end - - if type(node) == "table" and getmetatable(node) == nil then - node = Compound(unpack(node)) - end - - return node -end - -function Delegator.parse(self, ...) - if self.allow_cancel and Map.formvalue(self, "cbi.cancel") then - if self:_run_hooks("on_cancel") then - return FORM_DONE - end - end - - if not Map.formvalue(self, "cbi.delg.current") then - self:_run_hooks("on_init") - end - - local newcurrent - self.chain = self.chain or self:get_chain() - self.current = self.current or self:get_active() - self.active = self.active or self:get(self.current) - assert(self.active, "Invalid state") - - local stat = FORM_DONE - if type(self.active) ~= "function" then - self.active:populate_delegator(self) - stat = self.active:parse() - else - self:active() - end - - if stat > FORM_PROCEED then - if Map.formvalue(self, "cbi.delg.back") then - newcurrent = self:get_prev(self.current) - else - newcurrent = self:get_next(self.current) - end - elseif stat < FORM_PROCEED then - return stat - end - - - if not Map.formvalue(self, "cbi.submit") then - return FORM_NODATA - elseif stat > FORM_PROCEED - and (not newcurrent or not self:get(newcurrent)) then - return self:_run_hook("on_done") or FORM_DONE - else - self.current = newcurrent or self.current - self.active = self:get(self.current) - if type(self.active) ~= "function" then - self.active:populate_delegator(self) - local stat = self.active:parse(false) - if stat == FORM_SKIP then - return self:parse(...) - else - return FORM_PROCEED - end - else - return self:parse(...) - end - end -end - -function Delegator.get_next(self, state) - for k, v in ipairs(self.chain) do - if v == state then - return self.chain[k+1] - end - end -end - -function Delegator.get_prev(self, state) - for k, v in ipairs(self.chain) do - if v == state then - return self.chain[k-1] - end - end -end - -function Delegator.get_chain(self) - local x = Map.formvalue(self, "cbi.delg.path") or self.defaultpath - return type(x) == "table" and x or {x} -end - -function Delegator.get_active(self) - return Map.formvalue(self, "cbi.delg.current") or self.chain[1] -end - ---[[ -Page - A simple node -]]-- - -Page = class(Node) -Page.__init__ = Node.__init__ -Page.parse = function() end - - ---[[ -SimpleForm - A Simple non-UCI form -]]-- -SimpleForm = class(Node) - -function SimpleForm.__init__(self, config, title, description, data) - Node.__init__(self, title, description) - self.config = config - self.data = data or {} - self.template = "cbi/simpleform" - self.dorender = true - self.pageaction = false - self.readinput = true -end - -SimpleForm.formvalue = Map.formvalue -SimpleForm.formvaluetable = Map.formvaluetable - -function SimpleForm.parse(self, readinput, ...) - self.readinput = (readinput ~= false) - - if self:formvalue("cbi.skip") then - return FORM_SKIP - end - - if self:formvalue("cbi.cancel") and self:_run_hooks("on_cancel") then - return FORM_DONE - end - - if self:submitstate() then - Node.parse(self, 1, ...) - end - - local valid = true - for k, j in ipairs(self.children) do - for i, v in ipairs(j.children) do - valid = valid - and (not v.tag_missing or not v.tag_missing[1]) - and (not v.tag_invalid or not v.tag_invalid[1]) - and (not v.error) - end - end - - local state = - not self:submitstate() and FORM_NODATA - or valid and FORM_VALID - or FORM_INVALID - - self.dorender = not self.handle - if self.handle then - local nrender, nstate = self:handle(state, self.data) - self.dorender = self.dorender or (nrender ~= false) - state = nstate or state - end - return state -end - -function SimpleForm.render(self, ...) - if self.dorender then - Node.render(self, ...) - end -end - -function SimpleForm.submitstate(self) - return self:formvalue("cbi.submit") -end - -function SimpleForm.section(self, class, ...) - if instanceof(class, AbstractSection) then - local obj = class(self, ...) - self:append(obj) - return obj - else - error("class must be a descendent of AbstractSection") - end -end - --- Creates a child field -function SimpleForm.field(self, class, ...) - local section - for k, v in ipairs(self.children) do - if instanceof(v, SimpleSection) then - section = v - break - end - end - if not section then - section = self:section(SimpleSection) - end - - if instanceof(class, AbstractValue) then - local obj = class(self, section, ...) - obj.track_missing = true - section:append(obj) - return obj - else - error("class must be a descendent of AbstractValue") - end -end - -function SimpleForm.set(self, section, option, value) - self.data[option] = value -end - - -function SimpleForm.del(self, section, option) - self.data[option] = nil -end - - -function SimpleForm.get(self, section, option) - return self.data[option] -end - - -function SimpleForm.get_scheme() - return nil -end - - -Form = class(SimpleForm) - -function Form.__init__(self, ...) - SimpleForm.__init__(self, ...) - self.embedded = true -end - - ---[[ -AbstractSection -]]-- -AbstractSection = class(Node) - -function AbstractSection.__init__(self, map, sectiontype, ...) - Node.__init__(self, ...) - self.sectiontype = sectiontype - self.map = map - self.config = map.config - self.optionals = {} - self.defaults = {} - self.fields = {} - self.tag_error = {} - self.tag_invalid = {} - self.tag_deperror = {} - self.changed = false - - self.optional = true - self.addremove = false - self.dynamic = false -end - --- Define a tab for the section -function AbstractSection.tab(self, tab, title, desc) - self.tabs = self.tabs or { } - self.tab_names = self.tab_names or { } - - self.tab_names[#self.tab_names+1] = tab - self.tabs[tab] = { - title = title, - description = desc, - childs = { } - } -end - --- Check whether the section has tabs -function AbstractSection.has_tabs(self) - return (self.tabs ~= nil) and (next(self.tabs) ~= nil) -end - --- Appends a new option -function AbstractSection.option(self, class, option, ...) - if instanceof(class, AbstractValue) then - local obj = class(self.map, self, option, ...) - self:append(obj) - self.fields[option] = obj - return obj - elseif class == true then - error("No valid class was given and autodetection failed.") - else - error("class must be a descendant of AbstractValue") - end -end - --- Appends a new tabbed option -function AbstractSection.taboption(self, tab, ...) - - assert(tab and self.tabs and self.tabs[tab], - "Cannot assign option to not existing tab %q" % tostring(tab)) - - local l = self.tabs[tab].childs - local o = AbstractSection.option(self, ...) - - if o then l[#l+1] = o end - - return o -end - --- Render a single tab -function AbstractSection.render_tab(self, tab, ...) - - assert(tab and self.tabs and self.tabs[tab], - "Cannot render not existing tab %q" % tostring(tab)) - - local k, node - for k, node in ipairs(self.tabs[tab].childs) do - node.last_child = (k == #self.tabs[tab].childs) - node.index = k - node:render(...) - end -end - --- Parse optional options -function AbstractSection.parse_optionals(self, section, noparse) - if not self.optional then - return - end - - self.optionals[section] = {} - - local field = nil - if not noparse then - field = self.map:formvalue("cbi.opt."..self.config.."."..section) - end - - for k,v in ipairs(self.children) do - if v.optional and not v:cfgvalue(section) and not self:has_tabs() then - if field == v.option then - field = nil - self.map.proceed = true - else - table.insert(self.optionals[section], v) - end - end - end - - if field and #field > 0 and self.dynamic then - self:add_dynamic(field) - end -end - --- Add a dynamic option -function AbstractSection.add_dynamic(self, field, optional) - local o = self:option(Value, field, field) - o.optional = optional -end - --- Parse all dynamic options -function AbstractSection.parse_dynamic(self, section) - if not self.dynamic then - return - end - - local arr = luci.util.clone(self:cfgvalue(section)) - local form = self.map:formvaluetable("cbid."..self.config.."."..section) - for k, v in pairs(form) do - arr[k] = v - end - - for key,val in pairs(arr) do - local create = true - - for i,c in ipairs(self.children) do - if c.option == key then - create = false - end - end - - if create and key:sub(1, 1) ~= "." then - self.map.proceed = true - self:add_dynamic(key, true) - end - end -end - --- Returns the section's UCI table -function AbstractSection.cfgvalue(self, section) - return self.map:get(section) -end - --- Push events -function AbstractSection.push_events(self) - --luci.util.append(self.map.events, self.events) - self.map.changed = true -end - --- Removes the section -function AbstractSection.remove(self, section) - self.map.proceed = true - return self.map:del(section) -end - --- Creates the section -function AbstractSection.create(self, section) - local stat - - if section then - stat = section:match("^[%w_]+$") and self.map:set(section, nil, self.sectiontype) - else - section = self.map:add(self.sectiontype) - stat = section - end - - if stat then - for k,v in pairs(self.children) do - if v.default then - self.map:set(section, v.option, v.default) - end - end - - for k,v in pairs(self.defaults) do - self.map:set(section, k, v) - end - end - - self.map.proceed = true - - return stat -end - - -SimpleSection = class(AbstractSection) - -function SimpleSection.__init__(self, form, ...) - AbstractSection.__init__(self, form, nil, ...) - self.template = "cbi/nullsection" -end - - -Table = class(AbstractSection) - -function Table.__init__(self, form, data, ...) - local datasource = {} - local tself = self - datasource.config = "table" - self.data = data or {} - - datasource.formvalue = Map.formvalue - datasource.formvaluetable = Map.formvaluetable - datasource.readinput = true - - function datasource.get(self, section, option) - return tself.data[section] and tself.data[section][option] - end - - function datasource.submitstate(self) - return Map.formvalue(self, "cbi.submit") - end - - function datasource.del(...) - return true - end - - function datasource.get_scheme() - return nil - end - - AbstractSection.__init__(self, datasource, "table", ...) - self.template = "cbi/tblsection" - self.rowcolors = true - self.anonymous = true -end - -function Table.parse(self, readinput) - self.map.readinput = (readinput ~= false) - for i, k in ipairs(self:cfgsections()) do - if self.map:submitstate() then - Node.parse(self, k) - end - end -end - -function Table.cfgsections(self) - local sections = {} - - for i, v in luci.util.kspairs(self.data) do - table.insert(sections, i) - end - - return sections -end - -function Table.update(self, data) - self.data = data -end - - - ---[[ -NamedSection - A fixed configuration section defined by its name -]]-- -NamedSection = class(AbstractSection) - -function NamedSection.__init__(self, map, section, stype, ...) - AbstractSection.__init__(self, map, stype, ...) - - -- Defaults - self.addremove = false - self.template = "cbi/nsection" - self.section = section -end - -function NamedSection.prepare(self) - AbstractSection.prepare(self) - AbstractSection.parse_optionals(self, self.section, true) -end - -function NamedSection.parse(self, novld) - local s = self.section - local active = self:cfgvalue(s) - - if self.addremove then - local path = self.config.."."..s - if active then -- Remove the section - if self.map:formvalue("cbi.rns."..path) and self:remove(s) then - self:push_events() - return - end - else -- Create and apply default values - if self.map:formvalue("cbi.cns."..path) then - self:create(s) - return - end - end - end - - if active then - AbstractSection.parse_dynamic(self, s) - if self.map:submitstate() then - Node.parse(self, s) - end - AbstractSection.parse_optionals(self, s) - - if self.changed then - self:push_events() - end - end -end - - ---[[ -TypedSection - A (set of) configuration section(s) defined by the type - addremove: Defines whether the user can add/remove sections of this type - anonymous: Allow creating anonymous sections - validate: a validation function returning nil if the section is invalid -]]-- -TypedSection = class(AbstractSection) - -function TypedSection.__init__(self, map, type, ...) - AbstractSection.__init__(self, map, type, ...) - - self.template = "cbi/tsection" - self.deps = {} - self.anonymous = false -end - -function TypedSection.prepare(self) - AbstractSection.prepare(self) - - local i, s - for i, s in ipairs(self:cfgsections()) do - AbstractSection.parse_optionals(self, s, true) - end -end - --- Return all matching UCI sections for this TypedSection -function TypedSection.cfgsections(self) - local sections = {} - self.map.uci:foreach(self.map.config, self.sectiontype, - function (section) - if self:checkscope(section[".name"]) then - table.insert(sections, section[".name"]) - end - end) - - return sections -end - --- Limits scope to sections that have certain option => value pairs -function TypedSection.depends(self, option, value) - table.insert(self.deps, {option=option, value=value}) -end - -function TypedSection.parse(self, novld) - if self.addremove then - -- Remove - local crval = REMOVE_PREFIX .. self.config - local name = self.map:formvaluetable(crval) - for k,v in pairs(name) do - if k:sub(-2) == ".x" then - k = k:sub(1, #k - 2) - end - if self:cfgvalue(k) and self:checkscope(k) then - self:remove(k) - end - end - end - - local co - for i, k in ipairs(self:cfgsections()) do - AbstractSection.parse_dynamic(self, k) - if self.map:submitstate() then - Node.parse(self, k, novld) - end - AbstractSection.parse_optionals(self, k) - end - - if self.addremove then - -- Create - local created - local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype - local origin, name = next(self.map:formvaluetable(crval)) - if self.anonymous then - if name then - created = self:create(nil, origin) - end - else - if name then - -- Ignore if it already exists - if self:cfgvalue(name) then - name = nil - self.err_invalid = true - else - name = self:checkscope(name) - - if not name then - self.err_invalid = true - end - - if name and #name > 0 then - created = self:create(name, origin) and name - if not created then - self.invalid_cts = true - end - end - end - end - end - - if created then - AbstractSection.parse_optionals(self, created) - end - end - - if self.sortable then - local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype - local order = self.map:formvalue(stval) - if order and #order > 0 then - local sids, sid = { }, nil - for sid in util.imatch(order) do - sids[#sids+1] = sid - end - if #sids > 0 then - self.map.uci:reorder(self.config, sids) - self.changed = true - end - end - end - - if created or self.changed then - self:push_events() - end -end - --- Verifies scope of sections -function TypedSection.checkscope(self, section) - -- Check if we are not excluded - if self.filter and not self:filter(section) then - return nil - end - - -- Check if at least one dependency is met - if #self.deps > 0 and self:cfgvalue(section) then - local stat = false - - for k, v in ipairs(self.deps) do - if self:cfgvalue(section)[v.option] == v.value then - stat = true - end - end - - if not stat then - return nil - end - end - - return self:validate(section) -end - - --- Dummy validate function -function TypedSection.validate(self, section) - return section -end - - ---[[ -AbstractValue - An abstract Value Type - null: Value can be empty - valid: A function returning the value if it is valid otherwise nil - depends: A table of option => value pairs of which one must be true - default: The default value - size: The size of the input fields - rmempty: Unset value if empty - optional: This value is optional (see AbstractSection.optionals) -]]-- -AbstractValue = class(Node) - -function AbstractValue.__init__(self, map, section, option, ...) - Node.__init__(self, ...) - self.section = section - self.option = option - self.map = map - self.config = map.config - self.tag_invalid = {} - self.tag_missing = {} - self.tag_reqerror = {} - self.tag_error = {} - self.deps = {} - --self.cast = "string" - - self.track_missing = false - self.rmempty = true - self.default = nil - self.size = nil - self.optional = false -end - -function AbstractValue.prepare(self) - self.cast = self.cast or "string" -end - --- Add a dependencie to another section field -function AbstractValue.depends(self, field, value) - local deps - if type(field) == "string" then - deps = {} - deps[field] = value - else - deps = field - end - - table.insert(self.deps, deps) -end - --- Serialize dependencies -function AbstractValue.deplist2json(self, section, deplist) - local deps, i, d = { } - - if type(self.deps) == "table" then - for i, d in ipairs(deplist or self.deps) do - local a, k, v = { } - for k, v in pairs(d) do - if k:find("!", 1, true) then - a[k] = v - elseif k:find(".", 1, true) then - a['cbid.%s' % k] = v - else - a['cbid.%s.%s.%s' %{ self.config, section, k }] = v - end - end - deps[#deps+1] = a - end - end - - return util.serialize_json(deps) -end - --- Serialize choices -function AbstractValue.choices(self) - if type(self.keylist) == "table" and #self.keylist > 0 then - local i, k, v = nil, nil, {} - for i, k in ipairs(self.keylist) do - v[k] = self.vallist[i] or k - end - return v - end - return nil -end - --- Generates the unique CBID -function AbstractValue.cbid(self, section) - return "cbid."..self.map.config.."."..section.."."..self.option -end - --- Return whether this object should be created -function AbstractValue.formcreated(self, section) - local key = "cbi.opt."..self.config.."."..section - return (self.map:formvalue(key) == self.option) -end - --- Returns the formvalue for this object -function AbstractValue.formvalue(self, section) - return self.map:formvalue(self:cbid(section)) -end - -function AbstractValue.additional(self, value) - self.optional = value -end - -function AbstractValue.mandatory(self, value) - self.rmempty = not value -end - -function AbstractValue.add_error(self, section, type, msg) - self.error = self.error or { } - self.error[section] = msg or type - - self.section.error = self.section.error or { } - self.section.error[section] = self.section.error[section] or { } - table.insert(self.section.error[section], msg or type) - - if type == "invalid" then - self.tag_invalid[section] = true - elseif type == "missing" then - self.tag_missing[section] = true - end - - self.tag_error[section] = true - self.map.save = false -end - -function AbstractValue.parse(self, section, novld) - local fvalue = self:formvalue(section) - local cvalue = self:cfgvalue(section) - - -- If favlue and cvalue are both tables and have the same content - -- make them identical - if type(fvalue) == "table" and type(cvalue) == "table" then - local equal = #fvalue == #cvalue - if equal then - for i=1, #fvalue do - if cvalue[i] ~= fvalue[i] then - equal = false - end - end - end - if equal then - fvalue = cvalue - end - end - - if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI - local val_err - fvalue, val_err = self:validate(fvalue, section) - fvalue = self:transform(fvalue) - - if not fvalue and not novld then - self:add_error(section, "invalid", val_err) - end - - if self.alias then - self.section.aliased = self.section.aliased or {} - self.section.aliased[section] = self.section.aliased[section] or {} - self.section.aliased[section][self.alias] = true - end - - if fvalue and (self.forcewrite or not (fvalue == cvalue)) then - if self:write(section, fvalue) then - -- Push events - self.section.changed = true - --luci.util.append(self.map.events, self.events) - end - end - else -- Unset the UCI or error - if self.rmempty or self.optional then - if not self.alias or - not self.section.aliased or - not self.section.aliased[section] or - not self.section.aliased[section][self.alias] - then - if self:remove(section) then - -- Push events - self.section.changed = true - --luci.util.append(self.map.events, self.events) - end - end - elseif cvalue ~= fvalue and not novld then - -- trigger validator with nil value to get custom user error msg. - local _, val_err = self:validate(nil, section) - self:add_error(section, "missing", val_err) - end - end -end - --- Render if this value exists or if it is mandatory -function AbstractValue.render(self, s, scope) - if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then - scope = scope or {} - scope.section = s - scope.cbid = self:cbid(s) - Node.render(self, scope) - end -end - --- Return the UCI value of this object -function AbstractValue.cfgvalue(self, section) - local value - if self.tag_error[section] then - value = self:formvalue(section) - else - value = self.map:get(section, self.alias or self.option) - end - - if not value then - return nil - elseif not self.cast or self.cast == type(value) then - return value - elseif self.cast == "string" then - if type(value) == "table" then - return value[1] - end - elseif self.cast == "table" then - return { value } - end -end - --- Validate the form value -function AbstractValue.validate(self, value) - if self.datatype and value then - if type(value) == "table" then - local v - for _, v in ipairs(value) do - if v and #v > 0 and not verify_datatype(self.datatype, v) then - return nil - end - end - else - if not verify_datatype(self.datatype, value) then - return nil - end - end - end - - return value -end - -AbstractValue.transform = AbstractValue.validate - - --- Write to UCI -function AbstractValue.write(self, section, value) - return self.map:set(section, self.alias or self.option, value) -end - --- Remove from UCI -function AbstractValue.remove(self, section) - return self.map:del(section, self.alias or self.option) -end - - - - ---[[ -Value - A one-line value - maxlength: The maximum length -]]-- -Value = class(AbstractValue) - -function Value.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/value" - self.keylist = {} - self.vallist = {} - self.readonly = nil -end - -function Value.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function Value.value(self, key, val) - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - -function Value.parse(self, section, novld) - if self.readonly then return end - AbstractValue.parse(self, section, novld) -end - --- DummyValue - This does nothing except being there -DummyValue = class(AbstractValue) - -function DummyValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/dvalue" - self.value = nil -end - -function DummyValue.cfgvalue(self, section) - local value - if self.value then - if type(self.value) == "function" then - value = self:value(section) - else - value = self.value - end - else - value = AbstractValue.cfgvalue(self, section) - end - return value -end - -function DummyValue.parse(self) - -end - - ---[[ -Flag - A flag being enabled or disabled -]]-- -Flag = class(AbstractValue) - -function Flag.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/fvalue" - - self.enabled = "1" - self.disabled = "0" - self.default = self.disabled -end - --- A flag can only have two states: set or unset -function Flag.parse(self, section, novld) - local fexists = self.map:formvalue( - FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option) - - if fexists then - local fvalue = self:formvalue(section) and self.enabled or self.disabled - local cvalue = self:cfgvalue(section) - local val_err - fvalue, val_err = self:validate(fvalue, section) - if not fvalue then - if not novld then - self:add_error(section, "invalid", val_err) - end - return - end - if fvalue == self.default and (self.optional or self.rmempty) then - self:remove(section) - else - self:write(section, fvalue) - end - if (fvalue ~= cvalue) then self.section.changed = true end - else - self:remove(section) - self.section.changed = true - end -end - -function Flag.cfgvalue(self, section) - return AbstractValue.cfgvalue(self, section) or self.default -end -function Flag.validate(self, value) - return value -end - ---[[ -ListValue - A one-line value predefined in a list - widget: The widget that will be used (select, radio) -]]-- -ListValue = class(AbstractValue) - -function ListValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/lvalue" - - self.size = 1 - self.widget = "select" - - self:reset_values() -end - -function ListValue.reset_values(self) - self.keylist = {} - self.vallist = {} - self.deplist = {} -end - -function ListValue.value(self, key, val, ...) - if luci.util.contains(self.keylist, key) then - return - end - - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) - table.insert(self.deplist, {...}) -end - -function ListValue.validate(self, val) - if luci.util.contains(self.keylist, val) then - return val - else - return nil - end -end - - - ---[[ -MultiValue - Multiple delimited values - widget: The widget that will be used (select, checkbox) - delimiter: The delimiter that will separate the values (default: " ") -]]-- -MultiValue = class(AbstractValue) - -function MultiValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/mvalue" - - self.widget = "checkbox" - self.delimiter = " " - - self:reset_values() -end - -function MultiValue.render(self, ...) - if self.widget == "select" and not self.size then - self.size = #self.vallist - end - - AbstractValue.render(self, ...) -end - -function MultiValue.reset_values(self) - self.keylist = {} - self.vallist = {} - self.deplist = {} -end - -function MultiValue.value(self, key, val) - if luci.util.contains(self.keylist, key) then - return - end - - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - -function MultiValue.valuelist(self, section) - local val = self:cfgvalue(section) - - if not(type(val) == "string") then - return {} - end - - return luci.util.split(val, self.delimiter) -end - -function MultiValue.validate(self, val) - val = (type(val) == "table") and val or {val} - - local result - - for i, value in ipairs(val) do - if luci.util.contains(self.keylist, value) then - result = result and (result .. self.delimiter .. value) or value - end - end - - return result -end - - -StaticList = class(MultiValue) - -function StaticList.__init__(self, ...) - MultiValue.__init__(self, ...) - self.cast = "table" - self.valuelist = self.cfgvalue - - if not self.override_scheme - and self.map:get_scheme(self.section.sectiontype, self.option) then - local vs = self.map:get_scheme(self.section.sectiontype, self.option) - if self.value and vs.values and not self.override_values then - for k, v in pairs(vs.values) do - self:value(k, v) - end - end - end -end - -function StaticList.validate(self, value) - value = (type(value) == "table") and value or {value} - - local valid = {} - for i, v in ipairs(value) do - if luci.util.contains(self.keylist, v) then - table.insert(valid, v) - end - end - return valid -end - - -DynamicList = class(AbstractValue) - -function DynamicList.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/dynlist" - self.cast = "table" - self:reset_values() -end - -function DynamicList.reset_values(self) - self.keylist = {} - self.vallist = {} -end - -function DynamicList.value(self, key, val) - val = val or key - table.insert(self.keylist, tostring(key)) - table.insert(self.vallist, tostring(val)) -end - -function DynamicList.write(self, section, value) - local t = { } - - if type(value) == "table" then - local x - for _, x in ipairs(value) do - if x and #x > 0 then - t[#t+1] = x - end - end - else - t = { value } - end - - if self.cast == "string" then - value = table.concat(t, " ") - else - value = t - end - - return AbstractValue.write(self, section, value) -end - -function DynamicList.cfgvalue(self, section) - local value = AbstractValue.cfgvalue(self, section) - - if type(value) == "string" then - local x - local t = { } - for x in value:gmatch("%S+") do - if #x > 0 then - t[#t+1] = x - end - end - value = t - end - - return value -end - -function DynamicList.formvalue(self, section) - local value = AbstractValue.formvalue(self, section) - - if type(value) == "string" then - if self.cast == "string" then - local x - local t = { } - for x in value:gmatch("%S+") do - t[#t+1] = x - end - value = t - else - value = { value } - end - end - - return value -end - - -DropDown = class(MultiValue) - -function DropDown.__init__(self, ...) - ListValue.__init__(self, ...) - self.template = "cbi/dropdown" - self.delimiter = " " -end - - ---[[ -TextValue - A multi-line value - rows: Rows -]]-- -TextValue = class(AbstractValue) - -function TextValue.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/tvalue" -end - ---[[ -Button -]]-- -Button = class(AbstractValue) - -function Button.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/button" - self.inputstyle = nil - self.rmempty = true - self.unsafeupload = false -end - - -FileUpload = class(AbstractValue) - -function FileUpload.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/upload" - if not self.map.upload_fields then - self.map.upload_fields = { self } - else - self.map.upload_fields[#self.map.upload_fields+1] = self - end -end - -function FileUpload.formcreated(self, section) - if self.unsafeupload then - return AbstractValue.formcreated(self, section) or - self.map:formvalue("cbi.rlf."..section.."."..self.option) or - self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or - self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") - else - return AbstractValue.formcreated(self, section) or - self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") - end -end - -function FileUpload.cfgvalue(self, section) - local val = AbstractValue.cfgvalue(self, section) - if val and fs.access(val) then - return val - end - return nil -end - --- If we have a new value, use it --- otherwise use old value --- deletion should be managed by a separate button object --- unless self.unsafeupload is set in which case if the user --- choose to remove the old file we do so. --- Also, allow to specify (via textbox) a file already on router -function FileUpload.formvalue(self, section) - local val = AbstractValue.formvalue(self, section) - if val then - if self.unsafeupload then - if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and - not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") - then - return val - end - fs.unlink(val) - self.value = nil - return nil - elseif val ~= "" then - return val - end - end - val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") - if val == "" then - val = nil - end - if not self.unsafeupload then - if not val then - val = self.map:formvalue("cbi.rlf."..section.."."..self.option) - end - end - return val -end - -function FileUpload.remove(self, section) - if self.unsafeupload then - local val = AbstractValue.formvalue(self, section) - if val and fs.access(val) then fs.unlink(val) end - return AbstractValue.remove(self, section) - else - return nil - end -end - -FileBrowser = class(AbstractValue) - -function FileBrowser.__init__(self, ...) - AbstractValue.__init__(self, ...) - self.template = "cbi/browser" -end diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua deleted file mode 100644 index c1cf01f9cd..0000000000 --- a/modules/luci-base/luasrc/cbi/datatypes.lua +++ /dev/null @@ -1,470 +0,0 @@ --- Copyright 2010 Jo-Philipp Wich --- Copyright 2017 Dan Luedtke --- Licensed to the public under the Apache License 2.0. - -local fs = require "nixio.fs" -local ip = require "luci.ip" -local math = require "math" -local util = require "luci.util" -local tonumber, tostring, type, unpack, select = tonumber, tostring, type, unpack, select - - -module "luci.cbi.datatypes" - - -_M['or'] = function(v, ...) - local i - for i = 1, select('#', ...), 2 do - local f = select(i, ...) - local a = select(i+1, ...) - if type(f) ~= "function" then - if f == v then - return true - end - i = i - 1 - elseif f(v, unpack(a)) then - return true - end - end - return false -end - -_M['and'] = function(v, ...) - local i - for i = 1, select('#', ...), 2 do - local f = select(i, ...) - local a = select(i+1, ...) - if type(f) ~= "function" then - if f ~= v then - return false - end - i = i - 1 - elseif not f(v, unpack(a)) then - return false - end - end - return true -end - -function neg(v, ...) - return _M['or'](v:gsub("^%s*!%s*", ""), ...) -end - -function list(v, subvalidator, subargs) - if type(subvalidator) ~= "function" then - return false - end - local token - for token in v:gmatch("%S+") do - if not subvalidator(token, unpack(subargs)) then - return false - end - end - return true -end - -function bool(val) - if val == "1" or val == "yes" or val == "on" or val == "true" then - return true - elseif val == "0" or val == "no" or val == "off" or val == "false" then - return true - elseif val == "" or val == nil then - return true - end - - return false -end - -function uinteger(val) - local n = tonumber(val) - if n ~= nil and math.floor(n) == n and n >= 0 then - return true - end - - return false -end - -function integer(val) - local n = tonumber(val) - if n ~= nil and math.floor(n) == n then - return true - end - - return false -end - -function ufloat(val) - local n = tonumber(val) - return ( n ~= nil and n >= 0 ) -end - -function float(val) - return ( tonumber(val) ~= nil ) -end - -function ipaddr(val) - return ip4addr(val) or ip6addr(val) -end - -function ip4addr(val) - if val then - return ip.IPv4(val) and true or false - end - - return false -end - -function ip4prefix(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 32 ) -end - -function ip6addr(val) - if val then - return ip.IPv6(val) and true or false - end - - return false -end - -function ip6prefix(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 128 ) -end - -function cidr(val) - return cidr4(val) or cidr6(val) -end - -function cidr4(val) - local ip, mask = val:match("^([^/]+)/([^/]+)$") - - return ip4addr(ip) and ip4prefix(mask) -end - -function cidr6(val) - local ip, mask = val:match("^([^/]+)/([^/]+)$") - - return ip6addr(ip) and ip6prefix(mask) -end - -function ipnet4(val) - local ip, mask = val:match("^([^/]+)/([^/]+)$") - - return ip4addr(ip) and ip4addr(mask) -end - -function ipnet6(val) - local ip, mask = val:match("^([^/]+)/([^/]+)$") - - return ip6addr(ip) and ip6addr(mask) -end - -function ipmask(val) - return ipmask4(val) or ipmask6(val) -end - -function ipmask4(val) - return cidr4(val) or ipnet4(val) or ip4addr(val) -end - -function ipmask6(val) - return cidr6(val) or ipnet6(val) or ip6addr(val) -end - -function ip6hostid(val) - if val == "eui64" or val == "random" then - return true - else - local addr = ip.IPv6(val) - if addr and addr:prefix() == 128 and addr:lower("::1:0:0:0:0") then - return true - end - end - - return false -end - -function port(val) - val = tonumber(val) - return ( val and val >= 0 and val <= 65535 ) -end - -function portrange(val) - local p1, p2 = val:match("^(%d+)%-(%d+)$") - if p1 and p2 and port(p1) and port(p2) then - return true - else - return port(val) - end -end - -function macaddr(val) - return ip.checkmac(val) and true or false -end - -function hostname(val, strict) - if val and (#val < 254) and ( - val:match("^[a-zA-Z_]+$") or - (val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and - val:match("[^0-9%.]")) - ) then - return (not strict or not val:match("^_")) - end - return false -end - -function host(val, ipv4only) - return hostname(val) or ((ipv4only == 1) and ip4addr(val)) or ((not (ipv4only == 1)) and ipaddr(val)) -end - -function network(val) - return uciname(val) or host(val) -end - -function hostport(val, ipv4only) - local h, p = val:match("^([^:]+):([^:]+)$") - return not not (h and p and host(h, ipv4only) and port(p)) -end - -function ip4addrport(val, bracket) - local h, p = val:match("^([^:]+):([^:]+)$") - return (h and p and ip4addr(h) and port(p)) -end - -function ip4addrport(val) - local h, p = val:match("^([^:]+):([^:]+)$") - return (h and p and ip4addr(h) and port(p)) -end - -function ipaddrport(val, bracket) - local h, p = val:match("^([^%[%]:]+):([^:]+)$") - if (h and p and ip4addr(h) and port(p)) then - return true - elseif (bracket == 1) then - h, p = val:match("^%[(.+)%]:([^:]+)$") - if (h and p and ip6addr(h) and port(p)) then - return true - end - end - h, p = val:match("^([^%[%]]+):([^:]+)$") - return (h and p and ip6addr(h) and port(p)) -end - -function wpakey(val) - if #val == 64 then - return (val:match("^[a-fA-F0-9]+$") ~= nil) - else - return (#val >= 8) and (#val <= 63) - end -end - -function wepkey(val) - if val:sub(1, 2) == "s:" then - val = val:sub(3) - end - - if (#val == 10) or (#val == 26) then - return (val:match("^[a-fA-F0-9]+$") ~= nil) - else - return (#val == 5) or (#val == 13) - end -end - -function hexstring(val) - if val then - return (val:match("^[a-fA-F0-9]+$") ~= nil) - end - return false -end - -function hex(val, maxbytes) - maxbytes = tonumber(maxbytes) - if val and maxbytes ~= nil then - return ((val:match("^0x[a-fA-F0-9]+$") ~= nil) and (#val <= 2 + maxbytes * 2)) - end - return false -end - -function base64(val) - if val then - return (val:match("^[a-zA-Z0-9/+]+=?=?$") ~= nil) and (math.fmod(#val, 4) == 0) - end - return false -end - -function string(val) - return true -- Everything qualifies as valid string -end - -function directory(val, seen) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "dir" then - return true - elseif s.type == "lnk" then - return directory( fs.readlink(val), seen ) - end - end - - return false -end - -function file(val, seen) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "reg" then - return true - elseif s.type == "lnk" then - return file( fs.readlink(val), seen ) - end - end - - return false -end - -function device(val, seen) - local s = fs.stat(val) - seen = seen or { } - - if s and not seen[s.ino] then - seen[s.ino] = true - if s.type == "chr" or s.type == "blk" then - return true - elseif s.type == "lnk" then - return device( fs.readlink(val), seen ) - end - end - - return false -end - -function uciname(val) - return (val:match("^[a-zA-Z0-9_]+$") ~= nil) -end - -function range(val, min, max) - val = tonumber(val) - min = tonumber(min) - max = tonumber(max) - - if val ~= nil and min ~= nil and max ~= nil then - return ((val >= min) and (val <= max)) - end - - return false -end - -function min(val, min) - val = tonumber(val) - min = tonumber(min) - - if val ~= nil and min ~= nil then - return (val >= min) - end - - return false -end - -function max(val, max) - val = tonumber(val) - max = tonumber(max) - - if val ~= nil and max ~= nil then - return (val <= max) - end - - return false -end - -function rangelength(val, min, max) - val = tostring(val) - min = tonumber(min) - max = tonumber(max) - - if val ~= nil and min ~= nil and max ~= nil then - return ((#val >= min) and (#val <= max)) - end - - return false -end - -function minlength(val, min) - val = tostring(val) - min = tonumber(min) - - if val ~= nil and min ~= nil then - return (#val >= min) - end - - return false -end - -function maxlength(val, max) - val = tostring(val) - max = tonumber(max) - - if val ~= nil and max ~= nil then - return (#val <= max) - end - - return false -end - -function phonedigit(val) - return (val:match("^[0-9%*#!%.]+$") ~= nil) -end - -function timehhmmss(val) - return (val:match("^[0-6][0-9]:[0-6][0-9]:[0-6][0-9]$") ~= nil) -end - -function dateyyyymmdd(val) - if val ~= nil then - yearstr, monthstr, daystr = val:match("^(%d%d%d%d)-(%d%d)-(%d%d)$") - if (yearstr == nil) or (monthstr == nil) or (daystr == nil) then - return false; - end - year = tonumber(yearstr) - month = tonumber(monthstr) - day = tonumber(daystr) - if (year == nil) or (month == nil) or (day == nil) then - return false; - end - - local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - - local function is_leap_year(year) - return (year % 4 == 0) and ((year % 100 ~= 0) or (year % 400 == 0)) - end - - function get_days_in_month(month, year) - if (month == 2) and is_leap_year(year) then - return 29 - else - return days_in_month[month] - end - end - if (year < 2015) then - return false - end - if ((month == 0) or (month > 12)) then - return false - end - if ((day == 0) or (day > get_days_in_month(month, year))) then - return false - end - return true - end - return false -end - -function unique(val) - return true -end diff --git a/modules/luci-base/luasrc/model/firewall.lua b/modules/luci-base/luasrc/model/firewall.lua deleted file mode 100644 index feff0855c4..0000000000 --- a/modules/luci-base/luasrc/model/firewall.lua +++ /dev/null @@ -1,568 +0,0 @@ --- Copyright 2009 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local type, pairs, ipairs, table, luci, math - = type, pairs, ipairs, table, luci, math - -local tpl = require "luci.template.parser" -local utl = require "luci.util" -local uci = require "luci.model.uci" - -module "luci.model.firewall" - - -local uci_r, uci_s - -function _valid_id(x) - return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$")) -end - -function _get(c, s, o) - return uci_r:get(c, s, o) -end - -function _set(c, s, o, v) - if v ~= nil then - if type(v) == "boolean" then v = v and "1" or "0" end - return uci_r:set(c, s, o, v) - else - return uci_r:delete(c, s, o) - end -end - - -function init(cursor) - uci_r = cursor or uci_r or uci.cursor() - uci_s = uci_r:substate() - - return _M -end - -function save(self, ...) - uci_r:save(...) - uci_r:load(...) -end - -function commit(self, ...) - uci_r:commit(...) - uci_r:load(...) -end - -function get_defaults() - return defaults() -end - -function new_zone(self) - local name = "newzone" - local count = 1 - - while self:get_zone(name) do - count = count + 1 - name = "newzone%d" % count - end - - return self:add_zone(name) -end - -function add_zone(self, n) - if _valid_id(n) and not self:get_zone(n) then - local d = defaults() - local z = uci_r:section("firewall", "zone", nil, { - name = n, - network = " ", - input = d:input() or "DROP", - forward = d:forward() or "DROP", - output = d:output() or "DROP" - }) - - return z and zone(z) - end -end - -function get_zone(self, n) - if uci_r:get("firewall", n) == "zone" then - return zone(n) - else - local z - uci_r:foreach("firewall", "zone", - function(s) - if n and s.name == n then - z = s['.name'] - return false - end - end) - return z and zone(z) - end -end - -function get_zones(self) - local zones = { } - local znl = { } - - uci_r:foreach("firewall", "zone", - function(s) - if s.name then - znl[s.name] = zone(s['.name']) - end - end) - - local z - for z in utl.kspairs(znl) do - zones[#zones+1] = znl[z] - end - - return zones -end - -function get_zone_by_network(self, net) - local z - - uci_r:foreach("firewall", "zone", - function(s) - if s.name and net then - local n - for n in utl.imatch(s.network or s.name) do - if n == net then - z = s['.name'] - return false - end - end - end - end) - - return z and zone(z) -end - -function del_zone(self, n) - local r = false - - if uci_r:get("firewall", n) == "zone" then - local z = uci_r:get("firewall", n, "name") - r = uci_r:delete("firewall", n) - n = z - else - uci_r:foreach("firewall", "zone", - function(s) - if n and s.name == n then - r = uci_r:delete("firewall", s['.name']) - return false - end - end) - end - - if r then - uci_r:foreach("firewall", "rule", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - - uci_r:foreach("firewall", "redirect", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src == n or s.dest == n then - uci_r:delete("firewall", s['.name']) - end - end) - end - - return r -end - -function rename_zone(self, old, new) - local r = false - - if _valid_id(new) and not self:get_zone(new) then - uci_r:foreach("firewall", "zone", - function(s) - if old and s.name == old then - if not s.network then - uci_r:set("firewall", s['.name'], "network", old) - end - uci_r:set("firewall", s['.name'], "name", new) - r = true - return false - end - end) - - if r then - uci_r:foreach("firewall", "rule", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - - uci_r:foreach("firewall", "redirect", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src == old then - uci_r:set("firewall", s['.name'], "src", new) - end - if s.dest == old then - uci_r:set("firewall", s['.name'], "dest", new) - end - end) - end - end - - return r -end - -function del_network(self, net) - local z - if net then - for _, z in ipairs(self:get_zones()) do - z:del_network(net) - end - end -end - - -defaults = utl.class() -function defaults.__init__(self) - uci_r:foreach("firewall", "defaults", - function(s) - self.sid = s['.name'] - return false - end) - - self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { }) -end - -function defaults.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function defaults.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function defaults.syn_flood(self) - return (self:get("syn_flood") == "1") -end - -function defaults.drop_invalid(self) - return (self:get("drop_invalid") == "1") -end - -function defaults.input(self) - return self:get("input") or "DROP" -end - -function defaults.forward(self) - return self:get("forward") or "DROP" -end - -function defaults.output(self) - return self:get("output") or "DROP" -end - - -zone = utl.class() -function zone.__init__(self, z) - if uci_r:get("firewall", z) == "zone" then - self.sid = z - self.data = uci_r:get_all("firewall", z) - else - uci_r:foreach("firewall", "zone", - function(s) - if s.name == z then - self.sid = s['.name'] - self.data = s - return false - end - end) - end -end - -function zone.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function zone.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function zone.masq(self) - return (self:get("masq") == "1") -end - -function zone.name(self) - return self:get("name") -end - -function zone.network(self) - return self:get("network") -end - -function zone.input(self) - return self:get("input") or defaults():input() or "DROP" -end - -function zone.forward(self) - return self:get("forward") or defaults():forward() or "DROP" -end - -function zone.output(self) - return self:get("output") or defaults():output() or "DROP" -end - -function zone.add_network(self, net) - if uci_r:get("network", net) == "interface" then - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - if n ~= net then - nets[#nets+1] = n - end - end - - nets[#nets+1] = net - - _M:del_network(net) - self:set("network", table.concat(nets, " ")) - end -end - -function zone.del_network(self, net) - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - if n ~= net then - nets[#nets+1] = n - end - end - - if #nets > 0 then - self:set("network", table.concat(nets, " ")) - else - self:set("network", " ") - end -end - -function zone.get_networks(self) - local nets = { } - - local n - for n in utl.imatch(self:get("network") or self:get("name")) do - nets[#nets+1] = n - end - - return nets -end - -function zone.clear_networks(self) - self:set("network", " ") -end - -function zone.get_forwardings_by(self, what) - local name = self:name() - local forwards = { } - - uci_r:foreach("firewall", "forwarding", - function(s) - if s.src and s.dest and s[what] == name then - forwards[#forwards+1] = forwarding(s['.name']) - end - end) - - return forwards -end - -function zone.add_forwarding_to(self, dest) - local exist, forward - - for _, forward in ipairs(self:get_forwardings_by('src')) do - if forward:dest() == dest then - exist = true - break - end - end - - if not exist and dest ~= self:name() and _valid_id(dest) then - local s = uci_r:section("firewall", "forwarding", nil, { - src = self:name(), - dest = dest - }) - - return s and forwarding(s) - end -end - -function zone.add_forwarding_from(self, src) - local exist, forward - - for _, forward in ipairs(self:get_forwardings_by('dest')) do - if forward:src() == src then - exist = true - break - end - end - - if not exist and src ~= self:name() and _valid_id(src) then - local s = uci_r:section("firewall", "forwarding", nil, { - src = src, - dest = self:name() - }) - - return s and forwarding(s) - end -end - -function zone.del_forwardings_by(self, what) - local name = self:name() - - uci_r:delete_all("firewall", "forwarding", - function(s) - return (s.src and s.dest and s[what] == name) - end) -end - -function zone.add_redirect(self, options) - options = options or { } - options.src = self:name() - - local s = uci_r:section("firewall", "redirect", nil, options) - return s and redirect(s) -end - -function zone.add_rule(self, options) - options = options or { } - options.src = self:name() - - local s = uci_r:section("firewall", "rule", nil, options) - return s and rule(s) -end - -function zone.get_color(self) - if self and self:name() == "lan" then - return "#90f090" - elseif self and self:name() == "wan" then - return "#f09090" - elseif self then - math.randomseed(tpl.hash(self:name())) - - local r = math.random(128) - local g = math.random(128) - local min = 0 - local max = 128 - - if ( r + g ) < 128 then - min = 128 - r - g - else - max = 255 - r - g - end - - local b = min + math.floor( math.random() * ( max - min ) ) - - return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b } - else - return "#eeeeee" - end -end - - -forwarding = utl.class() -function forwarding.__init__(self, f) - self.sid = f -end - -function forwarding.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function forwarding.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function forwarding.src_zone(self) - local z = zone(self:src()) - return z.sid and z -end - -function forwarding.dest_zone(self) - local z = zone(self:dest()) - return z.sid and z -end - - -rule = utl.class() -function rule.__init__(self, f) - self.sid = f -end - -function rule.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function rule.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function rule.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function rule.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function rule.src_zone(self) - return zone(self:src()) -end - -function rule.dest_zone(self) - return zone(self:dest()) -end - - -redirect = utl.class() -function redirect.__init__(self, f) - self.sid = f -end - -function redirect.get(self, opt) - return _get("firewall", self.sid, opt) -end - -function redirect.set(self, opt, val) - return _set("firewall", self.sid, opt, val) -end - -function redirect.src(self) - return uci_r:get("firewall", self.sid, "src") -end - -function redirect.dest(self) - return uci_r:get("firewall", self.sid, "dest") -end - -function redirect.src_zone(self) - return zone(self:src()) -end - -function redirect.dest_zone(self) - return zone(self:dest()) -end diff --git a/modules/luci-base/luasrc/view/cbi/browser.htm b/modules/luci-base/luasrc/view/cbi/browser.htm deleted file mode 100644 index eb47ffafe6..0000000000 --- a/modules/luci-base/luasrc/view/cbi/browser.htm +++ /dev/null @@ -1,10 +0,0 @@ -<%+cbi/valueheader%> - - /> - -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/button.htm b/modules/luci-base/luasrc/view/cbi/button.htm deleted file mode 100644 index 6ccba58f23..0000000000 --- a/modules/luci-base/luasrc/view/cbi/button.htm +++ /dev/null @@ -1,7 +0,0 @@ -<%+cbi/valueheader%> - <% if self:cfgvalue(section) ~= false then %> - " type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> - <% else %> - - - <% end %> -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/cell_valuefooter.htm b/modules/luci-base/luasrc/view/cbi/cell_valuefooter.htm deleted file mode 100644 index bdd6bc9687..0000000000 --- a/modules/luci-base/luasrc/view/cbi/cell_valuefooter.htm +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/modules/luci-base/luasrc/view/cbi/cell_valueheader.htm b/modules/luci-base/luasrc/view/cbi/cell_valueheader.htm deleted file mode 100644 index 4b70957543..0000000000 --- a/modules/luci-base/luasrc/view/cbi/cell_valueheader.htm +++ /dev/null @@ -1,12 +0,0 @@ -<%- - local title = luci.util.trim(striptags(self.title)) - local descr = luci.util.trim(striptags(self.description)) - local ftype = self.typename or (self.template and self.template:gsub("^.+/", "")) --%> -
0, "data-type", ftype) .. - ifattr(title and #title > 0, "data-title", title, true) .. - ifattr(descr and #descr > 0, "data-description", descr, true) -%>> -
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> diff --git a/modules/luci-base/luasrc/view/cbi/compound.htm b/modules/luci-base/luasrc/view/cbi/compound.htm deleted file mode 100644 index 12d02bb1d8..0000000000 --- a/modules/luci-base/luasrc/view/cbi/compound.htm +++ /dev/null @@ -1 +0,0 @@ -<%- self:render_children() %> diff --git a/modules/luci-base/luasrc/view/cbi/delegator.htm b/modules/luci-base/luasrc/view/cbi/delegator.htm deleted file mode 100644 index 4fd19265d8..0000000000 --- a/modules/luci-base/luasrc/view/cbi/delegator.htm +++ /dev/null @@ -1,24 +0,0 @@ -<%- self.active:render() %> -
- -<% for _, x in ipairs(self.chain) do %> - -<% end %> -<% if not self.disallow_pageactions then %> -<% if self.allow_finish and not self:get_next(self.current) then %> - -<% elseif self:get_next(self.current) then %> - -<% end %> -<% if self.allow_cancel then %> - -<% end %> -<% if self.allow_reset then %> - -<% end %> -<% if self.allow_back and self:get_prev(self.current) then %> - -<% end %> -<% end %> - -
diff --git a/modules/luci-base/luasrc/view/cbi/dropdown.htm b/modules/luci-base/luasrc/view/cbi/dropdown.htm deleted file mode 100644 index 927ecf2396..0000000000 --- a/modules/luci-base/luasrc/view/cbi/dropdown.htm +++ /dev/null @@ -1,19 +0,0 @@ -<%+cbi/valueheader%> ->
-<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/dvalue.htm b/modules/luci-base/luasrc/view/cbi/dvalue.htm deleted file mode 100644 index 78e6f323d7..0000000000 --- a/modules/luci-base/luasrc/view/cbi/dvalue.htm +++ /dev/null @@ -1,13 +0,0 @@ -<%+cbi/valueheader%> -<% if self.href then %><% end -%> - <% - local val = self:cfgvalue(section) or self.default or "" - if not self.rawhtml then - write(pcdata(val)) - else - write(val) - end - %> -<%- if self.href then %><%end%> -" /> -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/dynlist.htm b/modules/luci-base/luasrc/view/cbi/dynlist.htm deleted file mode 100644 index 2a3da67ff9..0000000000 --- a/modules/luci-base/luasrc/view/cbi/dynlist.htm +++ /dev/null @@ -1,12 +0,0 @@ -<%+cbi/valueheader%> ->
-<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/error.htm b/modules/luci-base/luasrc/view/cbi/error.htm deleted file mode 100644 index 75ec1082aa..0000000000 --- a/modules/luci-base/luasrc/view/cbi/error.htm +++ /dev/null @@ -1,19 +0,0 @@ -
- <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> - <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> - -

- <%: The configuration file could not be loaded due to the following error: %>
- <%=pcdata(self.error)%> -

- - - -

- <%: Edit the raw configuration data above to fix any error and hit "Save" to reload the page. %> -

- -
- -
-
diff --git a/modules/luci-base/luasrc/view/cbi/footer.htm b/modules/luci-base/luasrc/view/cbi/footer.htm deleted file mode 100644 index ed632202ce..0000000000 --- a/modules/luci-base/luasrc/view/cbi/footer.htm +++ /dev/null @@ -1,41 +0,0 @@ -<% - local display_back = (redirect and not flow.hidebackbtn) - local display_skip = (flow.skip) - local display_apply = (not autoapply and not flow.hideapplybtn) - local display_save = (not flow.hidesavebtn) - local display_reset = (not flow.hideresetbtn) - - if pageaction and - (display_back or display_skip or display_apply or display_save or display_reset) - then - %>
<% - - if display_back then - %> <% - end - - if display_skip then - %> <% - end - - if display_apply then - %> <% - end - - if display_save then - %> <% - end - - if display_reset then - %> <% - end - - %>
<% - end -%> - - - - - -<%+footer%> diff --git a/modules/luci-base/luasrc/view/cbi/full_valuefooter.htm b/modules/luci-base/luasrc/view/cbi/full_valuefooter.htm deleted file mode 100644 index d4ad093efa..0000000000 --- a/modules/luci-base/luasrc/view/cbi/full_valuefooter.htm +++ /dev/null @@ -1,12 +0,0 @@ - <% if self.description and #self.description > 0 then -%> - <% if not luci.util.instanceof(self, luci.cbi.DynamicList) and (not luci.util.instanceof(self, luci.cbi.Flag) or self.orientation == "horizontal") then -%> -
- <%- end %> -
- <%=self.description%> -
- <%- end %> - <%- if self.title and #self.title > 0 then -%> - - <%- end -%> - diff --git a/modules/luci-base/luasrc/view/cbi/full_valueheader.htm b/modules/luci-base/luasrc/view/cbi/full_valueheader.htm deleted file mode 100644 index 1d9ebeba94..0000000000 --- a/modules/luci-base/luasrc/view/cbi/full_valueheader.htm +++ /dev/null @@ -1,9 +0,0 @@ -
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> - <%- if self.title and #self.title > 0 then -%> - -
- <%- end -%> diff --git a/modules/luci-base/luasrc/view/cbi/fvalue.htm b/modules/luci-base/luasrc/view/cbi/fvalue.htm deleted file mode 100644 index 7f975b95e1..0000000000 --- a/modules/luci-base/luasrc/view/cbi/fvalue.htm +++ /dev/null @@ -1,12 +0,0 @@ -<%+cbi/valueheader%> ->
-<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/header.htm b/modules/luci-base/luasrc/view/cbi/header.htm deleted file mode 100644 index 821fa3efae..0000000000 --- a/modules/luci-base/luasrc/view/cbi/header.htm +++ /dev/null @@ -1,18 +0,0 @@ -<%+header%> -
> -
- - - -
diff --git a/modules/luci-base/luasrc/view/cbi/ipaddr.htm b/modules/luci-base/luasrc/view/cbi/ipaddr.htm deleted file mode 100644 index 1c924e1544..0000000000 --- a/modules/luci-base/luasrc/view/cbi/ipaddr.htm +++ /dev/null @@ -1,27 +0,0 @@ -<%+cbi/valueheader%> - - 0, "data-choices", { self.keylist, self.vallist }) - %> /> -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/lvalue.htm b/modules/luci-base/luasrc/view/cbi/lvalue.htm deleted file mode 100644 index 28141472f4..0000000000 --- a/modules/luci-base/luasrc/view/cbi/lvalue.htm +++ /dev/null @@ -1,14 +0,0 @@ -<%+cbi/valueheader%> ->
-<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/map.htm b/modules/luci-base/luasrc/view/cbi/map.htm deleted file mode 100644 index cda4d3530c..0000000000 --- a/modules/luci-base/luasrc/view/cbi/map.htm +++ /dev/null @@ -1,40 +0,0 @@ -<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%> -
<%=pcdata(msg)%>
-<%- end end -%> - -
- <% if self.title and #self.title > 0 then %> -

<%=self.title%>

- <% end %> - <% if self.description and #self.description > 0 then %> -
<%=self.description%>
- <% end %> - <% if self.tabbed then %> -
- <% for i, section in ipairs(self.children) do - tab = section.section or section.sectiontype %> -
> - <% section:render() %> -
- <% end %> -
- - <% if not self.save then -%> -
- <% for _, section in ipairs(self.children) do %> - <% if section.error and section.error[section.section] then -%> -
  • - <%:One or more invalid/required values on tab%>: <%=section.title or section.section or section.sectiontype%> -
- <%- end %> - <% end %> -
- <%- end %> - <% else %> - <%- self:render_children() %> - <% end %> -
diff --git a/modules/luci-base/luasrc/view/cbi/mvalue.htm b/modules/luci-base/luasrc/view/cbi/mvalue.htm deleted file mode 100644 index 1f4f4dbcc6..0000000000 --- a/modules/luci-base/luasrc/view/cbi/mvalue.htm +++ /dev/null @@ -1,24 +0,0 @@ -<%+cbi/valueheader%> -<% - local util = require "luci.util" - local values = {} - local value - for value in util.imatch(self:cfgvalue(section) or self.default) do - values[#values+1] = value - end -%> -> -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/nsection.htm b/modules/luci-base/luasrc/view/cbi/nsection.htm deleted file mode 100644 index 14232e3d94..0000000000 --- a/modules/luci-base/luasrc/view/cbi/nsection.htm +++ /dev/null @@ -1,29 +0,0 @@ -<% if self:cfgvalue(self.section) then section = self.section %> -
- <% if self.title and #self.title > 0 then -%> - <%=self.title%> - <%- end %> - <% if self.description and #self.description > 0 then -%> -
<%=self.description%>
- <%- end %> - <% if self.addremove then -%> -
- -
- <%- end %> -
- <%+cbi/ucisection%> -
-
-<% elseif self.addremove then %> - <% if self.template_addremove then include(self.template_addremove) else -%> -
- <% if self.title and #self.title > 0 then -%> - <%=self.title%> - <%- end %> -
<%=self.description%>
- -
- <%- end %> -<% end %> - diff --git a/modules/luci-base/luasrc/view/cbi/nullsection.htm b/modules/luci-base/luasrc/view/cbi/nullsection.htm deleted file mode 100644 index 7230719d19..0000000000 --- a/modules/luci-base/luasrc/view/cbi/nullsection.htm +++ /dev/null @@ -1,37 +0,0 @@ -
- <% if self.title and #self.title > 0 then -%> - <%=self.title%> - <%- end %> - <% if self.description and #self.description > 0 then -%> -
<%=self.description%>
- <%- end %> -
-
- <% self:render_children(1, scope or {}) %> -
- <% if self.error and self.error[1] then -%> -
-
    <% for _, e in ipairs(self.error[1]) do -%> -
  • - <%- if e == "invalid" then -%> - <%:One or more fields contain invalid values!%> - <%- elseif e == "missing" then -%> - <%:One or more required fields have no value!%> - <%- else -%> - <%=pcdata(e)%> - <%- end -%> -
  • - <%- end %>
-
- <%- end %> -
-
-<%- - if type(self.hidden) == "table" then - for k, v in pairs(self.hidden) do --%> - -<%- - end - end -%> diff --git a/modules/luci-base/luasrc/view/cbi/simpleform.htm b/modules/luci-base/luasrc/view/cbi/simpleform.htm deleted file mode 100644 index 3e10724ec5..0000000000 --- a/modules/luci-base/luasrc/view/cbi/simpleform.htm +++ /dev/null @@ -1,77 +0,0 @@ -<% - if not self.embedded then - %> - - <% - end - - %>
<% - - if self.title and #self.title > 0 then - %>

<%=self.title%>

<% - end - - if self.description and #self.description > 0 then - %>
<%=self.description%>
<% - end - - self:render_children() - - %>
<% - - if self.message then - %>
<%=self.message%>
<% - end - - if self.errmessage then - %>
<%=self.errmessage%>
<% - end - - if not self.embedded then - if type(self.hidden) == "table" then - local k, v - for k, v in pairs(self.hidden) do - %><% - end - end - - local display_back = (redirect) - local display_cancel = (self.cancel ~= false and self.on_cancel) - local display_skip = (self.flow and self.flow.skip) - local display_submit = (self.submit ~= false) - local display_reset = (self.reset ~= false) - - if display_back or display_cancel or display_skip or display_submit or display_reset then - %>
<% - - if display_back then - %> <% - end - - if display_cancel then - local label = pcdata(self.cancel or translate("Cancel")) - %> <% - end - - if display_skip then - %> <% - end - - if display_submit then - local label = pcdata(self.submit or translate("Submit")) - %> <% - end - - if display_reset then - local label = pcdata(self.reset or translate("Reset")) - %> <% - end - - %>
<% - end - - %><% - end -%> - - diff --git a/modules/luci-base/luasrc/view/cbi/tabcontainer.htm b/modules/luci-base/luasrc/view/cbi/tabcontainer.htm deleted file mode 100644 index 7fcb835783..0000000000 --- a/modules/luci-base/luasrc/view/cbi/tabcontainer.htm +++ /dev/null @@ -1,14 +0,0 @@ -<% for _, tab in ipairs(self.tab_names) do data = self.tabs[tab] %> -
> - <% if data.description then %> -
<%=data.description%>
- <% end %> - - <% self:render_tab(tab, section, scope or {}) %> -
-<% end %> diff --git a/modules/luci-base/luasrc/view/cbi/tblsection.htm b/modules/luci-base/luasrc/view/cbi/tblsection.htm deleted file mode 100644 index 11c2206d8c..0000000000 --- a/modules/luci-base/luasrc/view/cbi/tblsection.htm +++ /dev/null @@ -1,203 +0,0 @@ -<%- -local rowcnt = 0 - -function rowstyle() - rowcnt = rowcnt + 1 - if rowcnt % 2 == 0 then - return " cbi-rowstyle-1" - else - return " cbi-rowstyle-2" - end -end - -function width(o) - if o.width then - if type(o.width) == 'number' then - return ' style="width:%dpx"' % o.width - end - return ' style="width:%s"' % o.width - end - return '' -end - -local has_titles = false -local has_descriptions = false - -local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous" -local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name")) - -local i, k -for i, k in pairs(self.children) do - if not k.typename then - k.typename = k.template and k.template:gsub("^.+/", "") or "" - end - - if not has_titles and k.title and #k.title > 0 then - has_titles = true - end - - if not has_descriptions and k.description and #k.description > 0 then - has_descriptions = true - end -end - -function render_titles() - if not has_titles then - return - end - - %>
><% - - local i, k - for i, k in ipairs(self.children) do - if not k.optional then - %>
><% - - if k.titleref then - %><% - end - - write(k.title) - - if k.titleref then - %><% - end - - %>
<% - end - end - - if self.sortable or self.extedit or self.addremove then - %>
<% - end - - %>
<% - - rowcnt = rowcnt + 1 -end - -function render_descriptions() - if not has_descriptions then - return - end - - %>
<% - - local i, k - for i, k in ipairs(self.children) do - if not k.optional then - %>
><% - - write(k.description) - - %>
<% - end - end - - if self.sortable or self.extedit or self.addremove then - %>
<% - end - - %>
<% - - rowcnt = rowcnt + 1 -end - --%> - - -
- <% if self.title and #self.title > 0 then -%> -

<%=self.title%>

- <%- end %> - <%- if self.sortable then -%> - - <%- end -%> -
<%=self.description%>
-
- <%- - render_titles() - render_descriptions() - - local isempty, section, i, k = true, nil, nil - for i, k in ipairs(self:cfgsections()) do - isempty = false - 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, true) - local colorclass = (self.extedit or self.rowcolors) and rowstyle() or "" - local scope = { - valueheader = "cbi/cell_valueheader", - valuefooter = "cbi/cell_valuefooter" - } - -%> -
> - <%- - local node - for k, node in ipairs(self.children) do - if not node.optional then - node:render(section, scope or {}) - end - end - -%> - - <%- if self.sortable or self.extedit or self.addremove then -%> -
-
- <%- if self.sortable then -%> - - - <% end; if self.extedit then -%> - onclick="location.href='<%=self.extedit:format(section)%>'" - <%- elseif type(self.extedit) == "function" then - %> onclick="location.href='<%=self:extedit(section)%>'" - <%- end - %> alt="<%:Edit%>" title="<%:Edit%>" /> - <% end; if self.addremove then %> - - <%- end -%> -
-
- <%- end -%> -
- <%- end -%> - - <%- if isempty then -%> -
-
<%:This section contains no values yet%>
-
- <%- end -%> -
- - <% if self.error then %> -
-
    <% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%> -
  • <%=pcdata(e):gsub("\n","
    ")%>
  • - <%- end end %>
-
- <% end %> - - <%- if self.addremove then -%> - <% if self.template_addremove then include(self.template_addremove) else -%> -
- <% if self.anonymous then %> - - <% else %> - <% if self.invalid_cts then -%> -
<%:Invalid%>
- <%- end %> -
- -
- - <% end %> -
- <%- end %> - <%- end -%> -
- diff --git a/modules/luci-base/luasrc/view/cbi/tsection.htm b/modules/luci-base/luasrc/view/cbi/tsection.htm deleted file mode 100644 index 8f3b7f0ffb..0000000000 --- a/modules/luci-base/luasrc/view/cbi/tsection.htm +++ /dev/null @@ -1,52 +0,0 @@ -
- <% if self.title and #self.title > 0 then -%> - <%=self.title%> - <%- end %> - <% if self.error_msg and #self.error_msg > 0 then -%> -
- <%=self.error_msg%> -
- <%- end %> - <% if self.description and #self.description > 0 then -%> -
<%=self.description%>
- <%- end %> - <% local isempty = true for i, k in ipairs(self:cfgsections()) do -%> - <% if self.addremove then -%> -
- -
- <%- end %> - - <%- section = k; isempty = false -%> - - <% if not self.anonymous then -%> -

<%=section:upper()%>

- <%- end %> - -
- <%+cbi/ucisection%> -
- <%- end %> - - <% if isempty then -%> - <%:This section contains no values yet%>

- <%- end %> - - <% if self.addremove then -%> - <% if self.template_addremove then include(self.template_addremove) else -%> -
- <% if self.anonymous then -%> - - <%- else -%> - <% if self.invalid_cts then -%> -
<%:Invalid%>
- <%- end %> -
- -
- - <%- end %> -
- <%- end %> - <%- end %> -
diff --git a/modules/luci-base/luasrc/view/cbi/tvalue.htm b/modules/luci-base/luasrc/view/cbi/tvalue.htm deleted file mode 100644 index f3b12bd094..0000000000 --- a/modules/luci-base/luasrc/view/cbi/tvalue.htm +++ /dev/null @@ -1,5 +0,0 @@ -<%+cbi/valueheader%> - -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/ucisection.htm b/modules/luci-base/luasrc/view/cbi/ucisection.htm deleted file mode 100644 index 8fa11d68f8..0000000000 --- a/modules/luci-base/luasrc/view/cbi/ucisection.htm +++ /dev/null @@ -1,56 +0,0 @@ -<%- - if type(self.hidden) == "table" then - for k, v in pairs(self.hidden) do --%> - -<%- - end - end -%> - -<% if self.tabs then %> - <%+cbi/tabcontainer%> -<% else %> - <% self:render_children(section, scope or {}) %> -<% end %> - -<% if self.error and self.error[section] then -%> -
-
    <% for _, e in ipairs(self.error[section]) do -%> -
  • - <%- if e == "invalid" then -%> - <%:One or more fields contain invalid values!%> - <%- elseif e == "missing" then -%> - <%:One or more required fields have no value!%> - <%- else -%> - <%=pcdata(e)%> - <%- end -%> -
  • - <%- end %>
-
-<%- end %> - -<% if self.optionals[section] and #self.optionals[section] > 0 or self.dynamic then %> -
- <%- - if self.dynamic then - local keys, vals, name, opt = { }, { } - for name, opt in pairs(self.optionals[section]) do - keys[#keys+1] = name - vals[#vals+1] = opt.title - end - -%> - 0, "data-choices", luci.util.json_encode({keys, vals})) - %> /> - <%- else -%> - - <%- end -%> - -
-<% end %> diff --git a/modules/luci-base/luasrc/view/cbi/upload.htm b/modules/luci-base/luasrc/view/cbi/upload.htm deleted file mode 100644 index e610495380..0000000000 --- a/modules/luci-base/luasrc/view/cbi/upload.htm +++ /dev/null @@ -1,14 +0,0 @@ -<%+cbi/valueheader%> - -> - -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/value.htm b/modules/luci-base/luasrc/view/cbi/value.htm deleted file mode 100644 index 6060310b19..0000000000 --- a/modules/luci-base/luasrc/view/cbi/value.htm +++ /dev/null @@ -1,35 +0,0 @@ -<%+cbi/valueheader%> - -<% local choices = self:choices() - if choices then %> - > -<% else %> - > -<% end %> - -<%+cbi/valuefooter%> diff --git a/modules/luci-base/luasrc/view/cbi/valuefooter.htm b/modules/luci-base/luasrc/view/cbi/valuefooter.htm deleted file mode 100644 index 805312e451..0000000000 --- a/modules/luci-base/luasrc/view/cbi/valuefooter.htm +++ /dev/null @@ -1 +0,0 @@ -<% include( valuefooter or "cbi/full_valuefooter" ) %> diff --git a/modules/luci-base/luasrc/view/cbi/valueheader.htm b/modules/luci-base/luasrc/view/cbi/valueheader.htm deleted file mode 100644 index 761a54aed0..0000000000 --- a/modules/luci-base/luasrc/view/cbi/valueheader.htm +++ /dev/null @@ -1 +0,0 @@ -<% include( valueheader or "cbi/full_valueheader" ) %> diff --git a/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm b/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm deleted file mode 100644 index eeb1d5c5cb..0000000000 --- a/modules/luci-base/luasrc/view/cbi/wireless_modefreq.htm +++ /dev/null @@ -1,173 +0,0 @@ -<%+cbi/valueheader%> - - - - - - - -
- - - -<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/cbi.lua b/modules/luci-compat/luasrc/cbi.lua new file mode 100644 index 0000000000..450e413916 --- /dev/null +++ b/modules/luci-compat/luasrc/cbi.lua @@ -0,0 +1,1977 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +module("luci.cbi", package.seeall) + +require("luci.template") +local util = require("luci.util") +require("luci.http") + + +--local event = require "luci.sys.event" +local fs = require("nixio.fs") +local uci = require("luci.model.uci") +local datatypes = require("luci.cbi.datatypes") +local dispatcher = require("luci.dispatcher") +local class = util.class +local instanceof = util.instanceof + +FORM_NODATA = 0 +FORM_PROCEED = 0 +FORM_VALID = 1 +FORM_DONE = 1 +FORM_INVALID = -1 +FORM_CHANGED = 2 +FORM_SKIP = 4 + +AUTO = true + +CREATE_PREFIX = "cbi.cts." +REMOVE_PREFIX = "cbi.rts." +RESORT_PREFIX = "cbi.sts." +FEXIST_PREFIX = "cbi.cbe." + +-- Loads a CBI map from given file, creating an environment and returns it +function load(cbimap, ...) + local fs = require "nixio.fs" + local i18n = require "luci.i18n" + require("luci.config") + require("luci.util") + + local upldir = "/etc/luci-uploads/" + local cbidir = luci.util.libpath() .. "/model/cbi/" + local func, err + + if fs.access(cbidir..cbimap..".lua") then + func, err = loadfile(cbidir..cbimap..".lua") + elseif fs.access(cbimap) then + func, err = loadfile(cbimap) + else + func, err = nil, "Model '" .. cbimap .. "' not found!" + end + + assert(func, err) + + local env = { + translate=i18n.translate, + translatef=i18n.translatef, + arg={...} + } + + setfenv(func, setmetatable(env, {__index = + function(tbl, key) + return rawget(tbl, key) or _M[key] or _G[key] + end})) + + local maps = { func() } + local uploads = { } + local has_upload = false + + for i, map in ipairs(maps) do + if not instanceof(map, Node) then + error("CBI map returns no valid map object!") + return nil + else + map:prepare() + if map.upload_fields then + has_upload = true + for _, field in ipairs(map.upload_fields) do + uploads[ + field.config .. '.' .. + (field.section.sectiontype or '1') .. '.' .. + field.option + ] = true + end + end + end + end + + if has_upload then + local uci = luci.model.uci.cursor() + local prm = luci.http.context.request.message.params + local fd, cbid + + luci.http.setfilehandler( + function( field, chunk, eof ) + if not field then return end + if field.name and not cbid then + local c, s, o = field.name:gmatch( + "cbid%.([^%.]+)%.([^%.]+)%.([^%.]+)" + )() + + if c and s and o then + local t = uci:get( c, s ) or s + if uploads[c.."."..t.."."..o] then + local path = upldir .. field.name + fd = io.open(path, "w") + if fd then + cbid = field.name + prm[cbid] = path + end + end + end + end + + if field.name == cbid and fd then + fd:write(chunk) + end + + if eof and fd then + fd:close() + fd = nil + cbid = nil + end + end + ) + end + + return maps +end + +-- +-- Compile a datatype specification into a parse tree for evaluation later on +-- +local cdt_cache = { } + +function compile_datatype(code) + local i + local pos = 0 + local esc = false + local depth = 0 + local stack = { } + + for i = 1, #code+1 do + local byte = code:byte(i) or 44 + if esc then + esc = false + elseif byte == 92 then + esc = true + elseif byte == 40 or byte == 44 then + if depth <= 0 then + if pos < i then + local label = code:sub(pos, i-1) + :gsub("\\(.)", "%1") + :gsub("^%s+", "") + :gsub("%s+$", "") + + if #label > 0 and tonumber(label) then + stack[#stack+1] = tonumber(label) + elseif label:match("^'.*'$") or label:match('^".*"$') then + stack[#stack+1] = label:gsub("[\"'](.*)[\"']", "%1") + elseif type(datatypes[label]) == "function" then + stack[#stack+1] = datatypes[label] + stack[#stack+1] = { } + else + error("Datatype error, bad token %q" % label) + end + end + pos = i + 1 + end + depth = depth + (byte == 40 and 1 or 0) + elseif byte == 41 then + depth = depth - 1 + if depth <= 0 then + if type(stack[#stack-1]) ~= "function" then + error("Datatype error, argument list follows non-function") + end + stack[#stack] = compile_datatype(code:sub(pos, i-1)) + pos = i + 1 + end + end + end + + return stack +end + +function verify_datatype(dt, value) + if dt and #dt > 0 then + if not cdt_cache[dt] then + local c = compile_datatype(dt) + if c and type(c[1]) == "function" then + cdt_cache[dt] = c + else + error("Datatype error, not a function expression") + end + end + if cdt_cache[dt] then + return cdt_cache[dt][1](value, unpack(cdt_cache[dt][2])) + end + end + return true +end + + +-- Node pseudo abstract class +Node = class() + +function Node.__init__(self, title, description) + self.children = {} + self.title = title or "" + self.description = description or "" + self.template = "cbi/node" +end + +-- hook helper +function Node._run_hook(self, hook) + if type(self[hook]) == "function" then + return self[hook](self) + end +end + +function Node._run_hooks(self, ...) + local f + local r = false + for _, f in ipairs(arg) do + if type(self[f]) == "function" then + self[f](self) + r = true + end + end + return r +end + +-- Prepare nodes +function Node.prepare(self, ...) + for k, child in ipairs(self.children) do + child:prepare(...) + end +end + +-- Append child nodes +function Node.append(self, obj) + table.insert(self.children, obj) +end + +-- Parse this node and its children +function Node.parse(self, ...) + for k, child in ipairs(self.children) do + child:parse(...) + end +end + +-- Render this node +function Node.render(self, scope) + scope = scope or {} + scope.self = self + + luci.template.render(self.template, scope) +end + +-- Render the children +function Node.render_children(self, ...) + local k, node + for k, node in ipairs(self.children) do + node.last_child = (k == #self.children) + node.index = k + node:render(...) + end +end + + +--[[ +A simple template element +]]-- +Template = class(Node) + +function Template.__init__(self, template) + Node.__init__(self) + self.template = template +end + +function Template.render(self) + luci.template.render(self.template, {self=self}) +end + +function Template.parse(self, readinput) + self.readinput = (readinput ~= false) + return Map.formvalue(self, "cbi.submit") and FORM_DONE or FORM_NODATA +end + + +--[[ +Map - A map describing a configuration file +]]-- +Map = class(Node) + +function Map.__init__(self, config, ...) + Node.__init__(self, ...) + + self.config = config + self.parsechain = {self.config} + self.template = "cbi/map" + self.apply_on_parse = nil + self.readinput = true + self.proceed = false + self.flow = {} + + self.uci = uci.cursor() + self.save = true + + self.changed = false + + local path = "%s/%s" %{ self.uci:get_confdir(), self.config } + if fs.stat(path, "type") ~= "reg" then + fs.writefile(path, "") + end + + local ok, err = self.uci:load(self.config) + if not ok then + local url = dispatcher.build_url(unpack(dispatcher.context.request)) + local source = self:formvalue("cbi.source") + if type(source) == "string" then + fs.writefile(path, source:gsub("\r\n", "\n")) + ok, err = self.uci:load(self.config) + if ok then + luci.http.redirect(url) + end + end + self.save = false + end + + if not ok then + self.template = "cbi/error" + self.error = err + self.source = fs.readfile(path) or "" + self.pageaction = false + end +end + +function Map.formvalue(self, key) + return self.readinput and luci.http.formvalue(key) or nil +end + +function Map.formvaluetable(self, key) + return self.readinput and luci.http.formvaluetable(key) or {} +end + +function Map.get_scheme(self, sectiontype, option) + if not option then + return self.scheme and self.scheme.sections[sectiontype] + else + return self.scheme and self.scheme.variables[sectiontype] + and self.scheme.variables[sectiontype][option] + end +end + +function Map.submitstate(self) + return self:formvalue("cbi.submit") +end + +-- Chain foreign config +function Map.chain(self, config) + table.insert(self.parsechain, config) +end + +function Map.state_handler(self, state) + return state +end + +-- Use optimized UCI writing +function Map.parse(self, readinput, ...) + if self:formvalue("cbi.skip") then + self.state = FORM_SKIP + elseif not self.save then + self.state = FORM_INVALID + elseif not self:submitstate() then + self.state = FORM_NODATA + end + + -- Back out early to prevent unauthorized changes on the subsequent parse + if self.state ~= nil then + return self:state_handler(self.state) + end + + self.readinput = (readinput ~= false) + self:_run_hooks("on_parse") + + Node.parse(self, ...) + + if self.save then + self:_run_hooks("on_save", "on_before_save") + local i, config + for i, config in ipairs(self.parsechain) do + self.uci:save(config) + end + self:_run_hooks("on_after_save") + if (not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply") then + self:_run_hooks("on_before_commit") + if self.apply_on_parse == false then + for i, config in ipairs(self.parsechain) do + self.uci:commit(config) + end + end + self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") + if self.apply_on_parse == true or self.apply_on_parse == false then + self.uci:apply(self.apply_on_parse) + self:_run_hooks("on_apply", "on_after_apply") + else + -- This is evaluated by the dispatcher and delegated to the + -- template which in turn fires XHR to perform the actual + -- apply actions. + self.apply_needed = true + end + + -- Reparse sections + Node.parse(self, true) + end + for i, config in ipairs(self.parsechain) do + self.uci:unload(config) + end + if type(self.commit_handler) == "function" then + self:commit_handler(self:submitstate()) + end + end + + if not self.save then + self.state = FORM_INVALID + elseif self.proceed then + self.state = FORM_PROCEED + elseif self.changed then + self.state = FORM_CHANGED + else + self.state = FORM_VALID + end + + return self:state_handler(self.state) +end + +function Map.render(self, ...) + self:_run_hooks("on_init") + Node.render(self, ...) +end + +-- Creates a child section +function Map.section(self, class, ...) + if instanceof(class, AbstractSection) then + local obj = class(self, ...) + self:append(obj) + return obj + else + error("class must be a descendent of AbstractSection") + end +end + +-- UCI add +function Map.add(self, sectiontype) + return self.uci:add(self.config, sectiontype) +end + +-- UCI set +function Map.set(self, section, option, value) + if type(value) ~= "table" or #value > 0 then + if option then + return self.uci:set(self.config, section, option, value) + else + return self.uci:set(self.config, section, value) + end + else + return Map.del(self, section, option) + end +end + +-- UCI del +function Map.del(self, section, option) + if option then + return self.uci:delete(self.config, section, option) + else + return self.uci:delete(self.config, section) + end +end + +-- UCI get +function Map.get(self, section, option) + if not section then + return self.uci:get_all(self.config) + elseif option then + return self.uci:get(self.config, section, option) + else + return self.uci:get_all(self.config, section) + end +end + +--[[ +Compound - Container +]]-- +Compound = class(Node) + +function Compound.__init__(self, ...) + Node.__init__(self) + self.template = "cbi/compound" + self.children = {...} +end + +function Compound.populate_delegator(self, delegator) + for _, v in ipairs(self.children) do + v.delegator = delegator + end +end + +function Compound.parse(self, ...) + local cstate, state = 0 + + for k, child in ipairs(self.children) do + cstate = child:parse(...) + state = (not state or cstate < state) and cstate or state + end + + return state +end + + +--[[ +Delegator - Node controller +]]-- +Delegator = class(Node) +function Delegator.__init__(self, ...) + Node.__init__(self, ...) + self.nodes = {} + self.defaultpath = {} + self.pageaction = false + self.readinput = true + self.allow_reset = false + self.allow_cancel = false + self.allow_back = false + self.allow_finish = false + self.template = "cbi/delegator" +end + +function Delegator.set(self, name, node) + assert(not self.nodes[name], "Duplicate entry") + + self.nodes[name] = node +end + +function Delegator.add(self, name, node) + node = self:set(name, node) + self.defaultpath[#self.defaultpath+1] = name +end + +function Delegator.insert_after(self, name, after) + local n = #self.chain + 1 + for k, v in ipairs(self.chain) do + if v == after then + n = k + 1 + break + end + end + table.insert(self.chain, n, name) +end + +function Delegator.set_route(self, ...) + local n, chain, route = 0, self.chain, {...} + for i = 1, #chain do + if chain[i] == self.current then + n = i + break + end + end + for i = 1, #route do + n = n + 1 + chain[n] = route[i] + end + for i = n + 1, #chain do + chain[i] = nil + end +end + +function Delegator.get(self, name) + local node = self.nodes[name] + + if type(node) == "string" then + node = load(node, name) + end + + if type(node) == "table" and getmetatable(node) == nil then + node = Compound(unpack(node)) + end + + return node +end + +function Delegator.parse(self, ...) + if self.allow_cancel and Map.formvalue(self, "cbi.cancel") then + if self:_run_hooks("on_cancel") then + return FORM_DONE + end + end + + if not Map.formvalue(self, "cbi.delg.current") then + self:_run_hooks("on_init") + end + + local newcurrent + self.chain = self.chain or self:get_chain() + self.current = self.current or self:get_active() + self.active = self.active or self:get(self.current) + assert(self.active, "Invalid state") + + local stat = FORM_DONE + if type(self.active) ~= "function" then + self.active:populate_delegator(self) + stat = self.active:parse() + else + self:active() + end + + if stat > FORM_PROCEED then + if Map.formvalue(self, "cbi.delg.back") then + newcurrent = self:get_prev(self.current) + else + newcurrent = self:get_next(self.current) + end + elseif stat < FORM_PROCEED then + return stat + end + + + if not Map.formvalue(self, "cbi.submit") then + return FORM_NODATA + elseif stat > FORM_PROCEED + and (not newcurrent or not self:get(newcurrent)) then + return self:_run_hook("on_done") or FORM_DONE + else + self.current = newcurrent or self.current + self.active = self:get(self.current) + if type(self.active) ~= "function" then + self.active:populate_delegator(self) + local stat = self.active:parse(false) + if stat == FORM_SKIP then + return self:parse(...) + else + return FORM_PROCEED + end + else + return self:parse(...) + end + end +end + +function Delegator.get_next(self, state) + for k, v in ipairs(self.chain) do + if v == state then + return self.chain[k+1] + end + end +end + +function Delegator.get_prev(self, state) + for k, v in ipairs(self.chain) do + if v == state then + return self.chain[k-1] + end + end +end + +function Delegator.get_chain(self) + local x = Map.formvalue(self, "cbi.delg.path") or self.defaultpath + return type(x) == "table" and x or {x} +end + +function Delegator.get_active(self) + return Map.formvalue(self, "cbi.delg.current") or self.chain[1] +end + +--[[ +Page - A simple node +]]-- + +Page = class(Node) +Page.__init__ = Node.__init__ +Page.parse = function() end + + +--[[ +SimpleForm - A Simple non-UCI form +]]-- +SimpleForm = class(Node) + +function SimpleForm.__init__(self, config, title, description, data) + Node.__init__(self, title, description) + self.config = config + self.data = data or {} + self.template = "cbi/simpleform" + self.dorender = true + self.pageaction = false + self.readinput = true +end + +SimpleForm.formvalue = Map.formvalue +SimpleForm.formvaluetable = Map.formvaluetable + +function SimpleForm.parse(self, readinput, ...) + self.readinput = (readinput ~= false) + + if self:formvalue("cbi.skip") then + return FORM_SKIP + end + + if self:formvalue("cbi.cancel") and self:_run_hooks("on_cancel") then + return FORM_DONE + end + + if self:submitstate() then + Node.parse(self, 1, ...) + end + + local valid = true + for k, j in ipairs(self.children) do + for i, v in ipairs(j.children) do + valid = valid + and (not v.tag_missing or not v.tag_missing[1]) + and (not v.tag_invalid or not v.tag_invalid[1]) + and (not v.error) + end + end + + local state = + not self:submitstate() and FORM_NODATA + or valid and FORM_VALID + or FORM_INVALID + + self.dorender = not self.handle + if self.handle then + local nrender, nstate = self:handle(state, self.data) + self.dorender = self.dorender or (nrender ~= false) + state = nstate or state + end + return state +end + +function SimpleForm.render(self, ...) + if self.dorender then + Node.render(self, ...) + end +end + +function SimpleForm.submitstate(self) + return self:formvalue("cbi.submit") +end + +function SimpleForm.section(self, class, ...) + if instanceof(class, AbstractSection) then + local obj = class(self, ...) + self:append(obj) + return obj + else + error("class must be a descendent of AbstractSection") + end +end + +-- Creates a child field +function SimpleForm.field(self, class, ...) + local section + for k, v in ipairs(self.children) do + if instanceof(v, SimpleSection) then + section = v + break + end + end + if not section then + section = self:section(SimpleSection) + end + + if instanceof(class, AbstractValue) then + local obj = class(self, section, ...) + obj.track_missing = true + section:append(obj) + return obj + else + error("class must be a descendent of AbstractValue") + end +end + +function SimpleForm.set(self, section, option, value) + self.data[option] = value +end + + +function SimpleForm.del(self, section, option) + self.data[option] = nil +end + + +function SimpleForm.get(self, section, option) + return self.data[option] +end + + +function SimpleForm.get_scheme() + return nil +end + + +Form = class(SimpleForm) + +function Form.__init__(self, ...) + SimpleForm.__init__(self, ...) + self.embedded = true +end + + +--[[ +AbstractSection +]]-- +AbstractSection = class(Node) + +function AbstractSection.__init__(self, map, sectiontype, ...) + Node.__init__(self, ...) + self.sectiontype = sectiontype + self.map = map + self.config = map.config + self.optionals = {} + self.defaults = {} + self.fields = {} + self.tag_error = {} + self.tag_invalid = {} + self.tag_deperror = {} + self.changed = false + + self.optional = true + self.addremove = false + self.dynamic = false +end + +-- Define a tab for the section +function AbstractSection.tab(self, tab, title, desc) + self.tabs = self.tabs or { } + self.tab_names = self.tab_names or { } + + self.tab_names[#self.tab_names+1] = tab + self.tabs[tab] = { + title = title, + description = desc, + childs = { } + } +end + +-- Check whether the section has tabs +function AbstractSection.has_tabs(self) + return (self.tabs ~= nil) and (next(self.tabs) ~= nil) +end + +-- Appends a new option +function AbstractSection.option(self, class, option, ...) + if instanceof(class, AbstractValue) then + local obj = class(self.map, self, option, ...) + self:append(obj) + self.fields[option] = obj + return obj + elseif class == true then + error("No valid class was given and autodetection failed.") + else + error("class must be a descendant of AbstractValue") + end +end + +-- Appends a new tabbed option +function AbstractSection.taboption(self, tab, ...) + + assert(tab and self.tabs and self.tabs[tab], + "Cannot assign option to not existing tab %q" % tostring(tab)) + + local l = self.tabs[tab].childs + local o = AbstractSection.option(self, ...) + + if o then l[#l+1] = o end + + return o +end + +-- Render a single tab +function AbstractSection.render_tab(self, tab, ...) + + assert(tab and self.tabs and self.tabs[tab], + "Cannot render not existing tab %q" % tostring(tab)) + + local k, node + for k, node in ipairs(self.tabs[tab].childs) do + node.last_child = (k == #self.tabs[tab].childs) + node.index = k + node:render(...) + end +end + +-- Parse optional options +function AbstractSection.parse_optionals(self, section, noparse) + if not self.optional then + return + end + + self.optionals[section] = {} + + local field = nil + if not noparse then + field = self.map:formvalue("cbi.opt."..self.config.."."..section) + end + + for k,v in ipairs(self.children) do + if v.optional and not v:cfgvalue(section) and not self:has_tabs() then + if field == v.option then + field = nil + self.map.proceed = true + else + table.insert(self.optionals[section], v) + end + end + end + + if field and #field > 0 and self.dynamic then + self:add_dynamic(field) + end +end + +-- Add a dynamic option +function AbstractSection.add_dynamic(self, field, optional) + local o = self:option(Value, field, field) + o.optional = optional +end + +-- Parse all dynamic options +function AbstractSection.parse_dynamic(self, section) + if not self.dynamic then + return + end + + local arr = luci.util.clone(self:cfgvalue(section)) + local form = self.map:formvaluetable("cbid."..self.config.."."..section) + for k, v in pairs(form) do + arr[k] = v + end + + for key,val in pairs(arr) do + local create = true + + for i,c in ipairs(self.children) do + if c.option == key then + create = false + end + end + + if create and key:sub(1, 1) ~= "." then + self.map.proceed = true + self:add_dynamic(key, true) + end + end +end + +-- Returns the section's UCI table +function AbstractSection.cfgvalue(self, section) + return self.map:get(section) +end + +-- Push events +function AbstractSection.push_events(self) + --luci.util.append(self.map.events, self.events) + self.map.changed = true +end + +-- Removes the section +function AbstractSection.remove(self, section) + self.map.proceed = true + return self.map:del(section) +end + +-- Creates the section +function AbstractSection.create(self, section) + local stat + + if section then + stat = section:match("^[%w_]+$") and self.map:set(section, nil, self.sectiontype) + else + section = self.map:add(self.sectiontype) + stat = section + end + + if stat then + for k,v in pairs(self.children) do + if v.default then + self.map:set(section, v.option, v.default) + end + end + + for k,v in pairs(self.defaults) do + self.map:set(section, k, v) + end + end + + self.map.proceed = true + + return stat +end + + +SimpleSection = class(AbstractSection) + +function SimpleSection.__init__(self, form, ...) + AbstractSection.__init__(self, form, nil, ...) + self.template = "cbi/nullsection" +end + + +Table = class(AbstractSection) + +function Table.__init__(self, form, data, ...) + local datasource = {} + local tself = self + datasource.config = "table" + self.data = data or {} + + datasource.formvalue = Map.formvalue + datasource.formvaluetable = Map.formvaluetable + datasource.readinput = true + + function datasource.get(self, section, option) + return tself.data[section] and tself.data[section][option] + end + + function datasource.submitstate(self) + return Map.formvalue(self, "cbi.submit") + end + + function datasource.del(...) + return true + end + + function datasource.get_scheme() + return nil + end + + AbstractSection.__init__(self, datasource, "table", ...) + self.template = "cbi/tblsection" + self.rowcolors = true + self.anonymous = true +end + +function Table.parse(self, readinput) + self.map.readinput = (readinput ~= false) + for i, k in ipairs(self:cfgsections()) do + if self.map:submitstate() then + Node.parse(self, k) + end + end +end + +function Table.cfgsections(self) + local sections = {} + + for i, v in luci.util.kspairs(self.data) do + table.insert(sections, i) + end + + return sections +end + +function Table.update(self, data) + self.data = data +end + + + +--[[ +NamedSection - A fixed configuration section defined by its name +]]-- +NamedSection = class(AbstractSection) + +function NamedSection.__init__(self, map, section, stype, ...) + AbstractSection.__init__(self, map, stype, ...) + + -- Defaults + self.addremove = false + self.template = "cbi/nsection" + self.section = section +end + +function NamedSection.prepare(self) + AbstractSection.prepare(self) + AbstractSection.parse_optionals(self, self.section, true) +end + +function NamedSection.parse(self, novld) + local s = self.section + local active = self:cfgvalue(s) + + if self.addremove then + local path = self.config.."."..s + if active then -- Remove the section + if self.map:formvalue("cbi.rns."..path) and self:remove(s) then + self:push_events() + return + end + else -- Create and apply default values + if self.map:formvalue("cbi.cns."..path) then + self:create(s) + return + end + end + end + + if active then + AbstractSection.parse_dynamic(self, s) + if self.map:submitstate() then + Node.parse(self, s) + end + AbstractSection.parse_optionals(self, s) + + if self.changed then + self:push_events() + end + end +end + + +--[[ +TypedSection - A (set of) configuration section(s) defined by the type + addremove: Defines whether the user can add/remove sections of this type + anonymous: Allow creating anonymous sections + validate: a validation function returning nil if the section is invalid +]]-- +TypedSection = class(AbstractSection) + +function TypedSection.__init__(self, map, type, ...) + AbstractSection.__init__(self, map, type, ...) + + self.template = "cbi/tsection" + self.deps = {} + self.anonymous = false +end + +function TypedSection.prepare(self) + AbstractSection.prepare(self) + + local i, s + for i, s in ipairs(self:cfgsections()) do + AbstractSection.parse_optionals(self, s, true) + end +end + +-- Return all matching UCI sections for this TypedSection +function TypedSection.cfgsections(self) + local sections = {} + self.map.uci:foreach(self.map.config, self.sectiontype, + function (section) + if self:checkscope(section[".name"]) then + table.insert(sections, section[".name"]) + end + end) + + return sections +end + +-- Limits scope to sections that have certain option => value pairs +function TypedSection.depends(self, option, value) + table.insert(self.deps, {option=option, value=value}) +end + +function TypedSection.parse(self, novld) + if self.addremove then + -- Remove + local crval = REMOVE_PREFIX .. self.config + local name = self.map:formvaluetable(crval) + for k,v in pairs(name) do + if k:sub(-2) == ".x" then + k = k:sub(1, #k - 2) + end + if self:cfgvalue(k) and self:checkscope(k) then + self:remove(k) + end + end + end + + local co + for i, k in ipairs(self:cfgsections()) do + AbstractSection.parse_dynamic(self, k) + if self.map:submitstate() then + Node.parse(self, k, novld) + end + AbstractSection.parse_optionals(self, k) + end + + if self.addremove then + -- Create + local created + local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype + local origin, name = next(self.map:formvaluetable(crval)) + if self.anonymous then + if name then + created = self:create(nil, origin) + end + else + if name then + -- Ignore if it already exists + if self:cfgvalue(name) then + name = nil + self.err_invalid = true + else + name = self:checkscope(name) + + if not name then + self.err_invalid = true + end + + if name and #name > 0 then + created = self:create(name, origin) and name + if not created then + self.invalid_cts = true + end + end + end + end + end + + if created then + AbstractSection.parse_optionals(self, created) + end + end + + if self.sortable then + local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype + local order = self.map:formvalue(stval) + if order and #order > 0 then + local sids, sid = { }, nil + for sid in util.imatch(order) do + sids[#sids+1] = sid + end + if #sids > 0 then + self.map.uci:reorder(self.config, sids) + self.changed = true + end + end + end + + if created or self.changed then + self:push_events() + end +end + +-- Verifies scope of sections +function TypedSection.checkscope(self, section) + -- Check if we are not excluded + if self.filter and not self:filter(section) then + return nil + end + + -- Check if at least one dependency is met + if #self.deps > 0 and self:cfgvalue(section) then + local stat = false + + for k, v in ipairs(self.deps) do + if self:cfgvalue(section)[v.option] == v.value then + stat = true + end + end + + if not stat then + return nil + end + end + + return self:validate(section) +end + + +-- Dummy validate function +function TypedSection.validate(self, section) + return section +end + + +--[[ +AbstractValue - An abstract Value Type + null: Value can be empty + valid: A function returning the value if it is valid otherwise nil + depends: A table of option => value pairs of which one must be true + default: The default value + size: The size of the input fields + rmempty: Unset value if empty + optional: This value is optional (see AbstractSection.optionals) +]]-- +AbstractValue = class(Node) + +function AbstractValue.__init__(self, map, section, option, ...) + Node.__init__(self, ...) + self.section = section + self.option = option + self.map = map + self.config = map.config + self.tag_invalid = {} + self.tag_missing = {} + self.tag_reqerror = {} + self.tag_error = {} + self.deps = {} + --self.cast = "string" + + self.track_missing = false + self.rmempty = true + self.default = nil + self.size = nil + self.optional = false +end + +function AbstractValue.prepare(self) + self.cast = self.cast or "string" +end + +-- Add a dependencie to another section field +function AbstractValue.depends(self, field, value) + local deps + if type(field) == "string" then + deps = {} + deps[field] = value + else + deps = field + end + + table.insert(self.deps, deps) +end + +-- Serialize dependencies +function AbstractValue.deplist2json(self, section, deplist) + local deps, i, d = { } + + if type(self.deps) == "table" then + for i, d in ipairs(deplist or self.deps) do + local a, k, v = { } + for k, v in pairs(d) do + if k:find("!", 1, true) then + a[k] = v + elseif k:find(".", 1, true) then + a['cbid.%s' % k] = v + else + a['cbid.%s.%s.%s' %{ self.config, section, k }] = v + end + end + deps[#deps+1] = a + end + end + + return util.serialize_json(deps) +end + +-- Serialize choices +function AbstractValue.choices(self) + if type(self.keylist) == "table" and #self.keylist > 0 then + local i, k, v = nil, nil, {} + for i, k in ipairs(self.keylist) do + v[k] = self.vallist[i] or k + end + return v + end + return nil +end + +-- Generates the unique CBID +function AbstractValue.cbid(self, section) + return "cbid."..self.map.config.."."..section.."."..self.option +end + +-- Return whether this object should be created +function AbstractValue.formcreated(self, section) + local key = "cbi.opt."..self.config.."."..section + return (self.map:formvalue(key) == self.option) +end + +-- Returns the formvalue for this object +function AbstractValue.formvalue(self, section) + return self.map:formvalue(self:cbid(section)) +end + +function AbstractValue.additional(self, value) + self.optional = value +end + +function AbstractValue.mandatory(self, value) + self.rmempty = not value +end + +function AbstractValue.add_error(self, section, type, msg) + self.error = self.error or { } + self.error[section] = msg or type + + self.section.error = self.section.error or { } + self.section.error[section] = self.section.error[section] or { } + table.insert(self.section.error[section], msg or type) + + if type == "invalid" then + self.tag_invalid[section] = true + elseif type == "missing" then + self.tag_missing[section] = true + end + + self.tag_error[section] = true + self.map.save = false +end + +function AbstractValue.parse(self, section, novld) + local fvalue = self:formvalue(section) + local cvalue = self:cfgvalue(section) + + -- If favlue and cvalue are both tables and have the same content + -- make them identical + if type(fvalue) == "table" and type(cvalue) == "table" then + local equal = #fvalue == #cvalue + if equal then + for i=1, #fvalue do + if cvalue[i] ~= fvalue[i] then + equal = false + end + end + end + if equal then + fvalue = cvalue + end + end + + if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI + local val_err + fvalue, val_err = self:validate(fvalue, section) + fvalue = self:transform(fvalue) + + if not fvalue and not novld then + self:add_error(section, "invalid", val_err) + end + + if self.alias then + self.section.aliased = self.section.aliased or {} + self.section.aliased[section] = self.section.aliased[section] or {} + self.section.aliased[section][self.alias] = true + end + + if fvalue and (self.forcewrite or not (fvalue == cvalue)) then + if self:write(section, fvalue) then + -- Push events + self.section.changed = true + --luci.util.append(self.map.events, self.events) + end + end + else -- Unset the UCI or error + if self.rmempty or self.optional then + if not self.alias or + not self.section.aliased or + not self.section.aliased[section] or + not self.section.aliased[section][self.alias] + then + if self:remove(section) then + -- Push events + self.section.changed = true + --luci.util.append(self.map.events, self.events) + end + end + elseif cvalue ~= fvalue and not novld then + -- trigger validator with nil value to get custom user error msg. + local _, val_err = self:validate(nil, section) + self:add_error(section, "missing", val_err) + end + end +end + +-- Render if this value exists or if it is mandatory +function AbstractValue.render(self, s, scope) + if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then + scope = scope or {} + scope.section = s + scope.cbid = self:cbid(s) + Node.render(self, scope) + end +end + +-- Return the UCI value of this object +function AbstractValue.cfgvalue(self, section) + local value + if self.tag_error[section] then + value = self:formvalue(section) + else + value = self.map:get(section, self.alias or self.option) + end + + if not value then + return nil + elseif not self.cast or self.cast == type(value) then + return value + elseif self.cast == "string" then + if type(value) == "table" then + return value[1] + end + elseif self.cast == "table" then + return { value } + end +end + +-- Validate the form value +function AbstractValue.validate(self, value) + if self.datatype and value then + if type(value) == "table" then + local v + for _, v in ipairs(value) do + if v and #v > 0 and not verify_datatype(self.datatype, v) then + return nil + end + end + else + if not verify_datatype(self.datatype, value) then + return nil + end + end + end + + return value +end + +AbstractValue.transform = AbstractValue.validate + + +-- Write to UCI +function AbstractValue.write(self, section, value) + return self.map:set(section, self.alias or self.option, value) +end + +-- Remove from UCI +function AbstractValue.remove(self, section) + return self.map:del(section, self.alias or self.option) +end + + + + +--[[ +Value - A one-line value + maxlength: The maximum length +]]-- +Value = class(AbstractValue) + +function Value.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/value" + self.keylist = {} + self.vallist = {} + self.readonly = nil +end + +function Value.reset_values(self) + self.keylist = {} + self.vallist = {} +end + +function Value.value(self, key, val) + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) +end + +function Value.parse(self, section, novld) + if self.readonly then return end + AbstractValue.parse(self, section, novld) +end + +-- DummyValue - This does nothing except being there +DummyValue = class(AbstractValue) + +function DummyValue.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/dvalue" + self.value = nil +end + +function DummyValue.cfgvalue(self, section) + local value + if self.value then + if type(self.value) == "function" then + value = self:value(section) + else + value = self.value + end + else + value = AbstractValue.cfgvalue(self, section) + end + return value +end + +function DummyValue.parse(self) + +end + + +--[[ +Flag - A flag being enabled or disabled +]]-- +Flag = class(AbstractValue) + +function Flag.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/fvalue" + + self.enabled = "1" + self.disabled = "0" + self.default = self.disabled +end + +-- A flag can only have two states: set or unset +function Flag.parse(self, section, novld) + local fexists = self.map:formvalue( + FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option) + + if fexists then + local fvalue = self:formvalue(section) and self.enabled or self.disabled + local cvalue = self:cfgvalue(section) + local val_err + fvalue, val_err = self:validate(fvalue, section) + if not fvalue then + if not novld then + self:add_error(section, "invalid", val_err) + end + return + end + if fvalue == self.default and (self.optional or self.rmempty) then + self:remove(section) + else + self:write(section, fvalue) + end + if (fvalue ~= cvalue) then self.section.changed = true end + else + self:remove(section) + self.section.changed = true + end +end + +function Flag.cfgvalue(self, section) + return AbstractValue.cfgvalue(self, section) or self.default +end +function Flag.validate(self, value) + return value +end + +--[[ +ListValue - A one-line value predefined in a list + widget: The widget that will be used (select, radio) +]]-- +ListValue = class(AbstractValue) + +function ListValue.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/lvalue" + + self.size = 1 + self.widget = "select" + + self:reset_values() +end + +function ListValue.reset_values(self) + self.keylist = {} + self.vallist = {} + self.deplist = {} +end + +function ListValue.value(self, key, val, ...) + if luci.util.contains(self.keylist, key) then + return + end + + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) + table.insert(self.deplist, {...}) +end + +function ListValue.validate(self, val) + if luci.util.contains(self.keylist, val) then + return val + else + return nil + end +end + + + +--[[ +MultiValue - Multiple delimited values + widget: The widget that will be used (select, checkbox) + delimiter: The delimiter that will separate the values (default: " ") +]]-- +MultiValue = class(AbstractValue) + +function MultiValue.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/mvalue" + + self.widget = "checkbox" + self.delimiter = " " + + self:reset_values() +end + +function MultiValue.render(self, ...) + if self.widget == "select" and not self.size then + self.size = #self.vallist + end + + AbstractValue.render(self, ...) +end + +function MultiValue.reset_values(self) + self.keylist = {} + self.vallist = {} + self.deplist = {} +end + +function MultiValue.value(self, key, val) + if luci.util.contains(self.keylist, key) then + return + end + + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) +end + +function MultiValue.valuelist(self, section) + local val = self:cfgvalue(section) + + if not(type(val) == "string") then + return {} + end + + return luci.util.split(val, self.delimiter) +end + +function MultiValue.validate(self, val) + val = (type(val) == "table") and val or {val} + + local result + + for i, value in ipairs(val) do + if luci.util.contains(self.keylist, value) then + result = result and (result .. self.delimiter .. value) or value + end + end + + return result +end + + +StaticList = class(MultiValue) + +function StaticList.__init__(self, ...) + MultiValue.__init__(self, ...) + self.cast = "table" + self.valuelist = self.cfgvalue + + if not self.override_scheme + and self.map:get_scheme(self.section.sectiontype, self.option) then + local vs = self.map:get_scheme(self.section.sectiontype, self.option) + if self.value and vs.values and not self.override_values then + for k, v in pairs(vs.values) do + self:value(k, v) + end + end + end +end + +function StaticList.validate(self, value) + value = (type(value) == "table") and value or {value} + + local valid = {} + for i, v in ipairs(value) do + if luci.util.contains(self.keylist, v) then + table.insert(valid, v) + end + end + return valid +end + + +DynamicList = class(AbstractValue) + +function DynamicList.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/dynlist" + self.cast = "table" + self:reset_values() +end + +function DynamicList.reset_values(self) + self.keylist = {} + self.vallist = {} +end + +function DynamicList.value(self, key, val) + val = val or key + table.insert(self.keylist, tostring(key)) + table.insert(self.vallist, tostring(val)) +end + +function DynamicList.write(self, section, value) + local t = { } + + if type(value) == "table" then + local x + for _, x in ipairs(value) do + if x and #x > 0 then + t[#t+1] = x + end + end + else + t = { value } + end + + if self.cast == "string" then + value = table.concat(t, " ") + else + value = t + end + + return AbstractValue.write(self, section, value) +end + +function DynamicList.cfgvalue(self, section) + local value = AbstractValue.cfgvalue(self, section) + + if type(value) == "string" then + local x + local t = { } + for x in value:gmatch("%S+") do + if #x > 0 then + t[#t+1] = x + end + end + value = t + end + + return value +end + +function DynamicList.formvalue(self, section) + local value = AbstractValue.formvalue(self, section) + + if type(value) == "string" then + if self.cast == "string" then + local x + local t = { } + for x in value:gmatch("%S+") do + t[#t+1] = x + end + value = t + else + value = { value } + end + end + + return value +end + + +DropDown = class(MultiValue) + +function DropDown.__init__(self, ...) + ListValue.__init__(self, ...) + self.template = "cbi/dropdown" + self.delimiter = " " +end + + +--[[ +TextValue - A multi-line value + rows: Rows +]]-- +TextValue = class(AbstractValue) + +function TextValue.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/tvalue" +end + +--[[ +Button +]]-- +Button = class(AbstractValue) + +function Button.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/button" + self.inputstyle = nil + self.rmempty = true + self.unsafeupload = false +end + + +FileUpload = class(AbstractValue) + +function FileUpload.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/upload" + if not self.map.upload_fields then + self.map.upload_fields = { self } + else + self.map.upload_fields[#self.map.upload_fields+1] = self + end +end + +function FileUpload.formcreated(self, section) + if self.unsafeupload then + return AbstractValue.formcreated(self, section) or + self.map:formvalue("cbi.rlf."..section.."."..self.option) or + self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or + self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + else + return AbstractValue.formcreated(self, section) or + self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + end +end + +function FileUpload.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val and fs.access(val) then + return val + end + return nil +end + +-- If we have a new value, use it +-- otherwise use old value +-- deletion should be managed by a separate button object +-- unless self.unsafeupload is set in which case if the user +-- choose to remove the old file we do so. +-- Also, allow to specify (via textbox) a file already on router +function FileUpload.formvalue(self, section) + local val = AbstractValue.formvalue(self, section) + if val then + if self.unsafeupload then + if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and + not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") + then + return val + end + fs.unlink(val) + self.value = nil + return nil + elseif val ~= "" then + return val + end + end + val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + if val == "" then + val = nil + end + if not self.unsafeupload then + if not val then + val = self.map:formvalue("cbi.rlf."..section.."."..self.option) + end + end + return val +end + +function FileUpload.remove(self, section) + if self.unsafeupload then + local val = AbstractValue.formvalue(self, section) + if val and fs.access(val) then fs.unlink(val) end + return AbstractValue.remove(self, section) + else + return nil + end +end + +FileBrowser = class(AbstractValue) + +function FileBrowser.__init__(self, ...) + AbstractValue.__init__(self, ...) + self.template = "cbi/browser" +end diff --git a/modules/luci-compat/luasrc/cbi/datatypes.lua b/modules/luci-compat/luasrc/cbi/datatypes.lua new file mode 100644 index 0000000000..c1cf01f9cd --- /dev/null +++ b/modules/luci-compat/luasrc/cbi/datatypes.lua @@ -0,0 +1,470 @@ +-- Copyright 2010 Jo-Philipp Wich +-- Copyright 2017 Dan Luedtke +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local ip = require "luci.ip" +local math = require "math" +local util = require "luci.util" +local tonumber, tostring, type, unpack, select = tonumber, tostring, type, unpack, select + + +module "luci.cbi.datatypes" + + +_M['or'] = function(v, ...) + local i + for i = 1, select('#', ...), 2 do + local f = select(i, ...) + local a = select(i+1, ...) + if type(f) ~= "function" then + if f == v then + return true + end + i = i - 1 + elseif f(v, unpack(a)) then + return true + end + end + return false +end + +_M['and'] = function(v, ...) + local i + for i = 1, select('#', ...), 2 do + local f = select(i, ...) + local a = select(i+1, ...) + if type(f) ~= "function" then + if f ~= v then + return false + end + i = i - 1 + elseif not f(v, unpack(a)) then + return false + end + end + return true +end + +function neg(v, ...) + return _M['or'](v:gsub("^%s*!%s*", ""), ...) +end + +function list(v, subvalidator, subargs) + if type(subvalidator) ~= "function" then + return false + end + local token + for token in v:gmatch("%S+") do + if not subvalidator(token, unpack(subargs)) then + return false + end + end + return true +end + +function bool(val) + if val == "1" or val == "yes" or val == "on" or val == "true" then + return true + elseif val == "0" or val == "no" or val == "off" or val == "false" then + return true + elseif val == "" or val == nil then + return true + end + + return false +end + +function uinteger(val) + local n = tonumber(val) + if n ~= nil and math.floor(n) == n and n >= 0 then + return true + end + + return false +end + +function integer(val) + local n = tonumber(val) + if n ~= nil and math.floor(n) == n then + return true + end + + return false +end + +function ufloat(val) + local n = tonumber(val) + return ( n ~= nil and n >= 0 ) +end + +function float(val) + return ( tonumber(val) ~= nil ) +end + +function ipaddr(val) + return ip4addr(val) or ip6addr(val) +end + +function ip4addr(val) + if val then + return ip.IPv4(val) and true or false + end + + return false +end + +function ip4prefix(val) + val = tonumber(val) + return ( val and val >= 0 and val <= 32 ) +end + +function ip6addr(val) + if val then + return ip.IPv6(val) and true or false + end + + return false +end + +function ip6prefix(val) + val = tonumber(val) + return ( val and val >= 0 and val <= 128 ) +end + +function cidr(val) + return cidr4(val) or cidr6(val) +end + +function cidr4(val) + local ip, mask = val:match("^([^/]+)/([^/]+)$") + + return ip4addr(ip) and ip4prefix(mask) +end + +function cidr6(val) + local ip, mask = val:match("^([^/]+)/([^/]+)$") + + return ip6addr(ip) and ip6prefix(mask) +end + +function ipnet4(val) + local ip, mask = val:match("^([^/]+)/([^/]+)$") + + return ip4addr(ip) and ip4addr(mask) +end + +function ipnet6(val) + local ip, mask = val:match("^([^/]+)/([^/]+)$") + + return ip6addr(ip) and ip6addr(mask) +end + +function ipmask(val) + return ipmask4(val) or ipmask6(val) +end + +function ipmask4(val) + return cidr4(val) or ipnet4(val) or ip4addr(val) +end + +function ipmask6(val) + return cidr6(val) or ipnet6(val) or ip6addr(val) +end + +function ip6hostid(val) + if val == "eui64" or val == "random" then + return true + else + local addr = ip.IPv6(val) + if addr and addr:prefix() == 128 and addr:lower("::1:0:0:0:0") then + return true + end + end + + return false +end + +function port(val) + val = tonumber(val) + return ( val and val >= 0 and val <= 65535 ) +end + +function portrange(val) + local p1, p2 = val:match("^(%d+)%-(%d+)$") + if p1 and p2 and port(p1) and port(p2) then + return true + else + return port(val) + end +end + +function macaddr(val) + return ip.checkmac(val) and true or false +end + +function hostname(val, strict) + if val and (#val < 254) and ( + val:match("^[a-zA-Z_]+$") or + (val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and + val:match("[^0-9%.]")) + ) then + return (not strict or not val:match("^_")) + end + return false +end + +function host(val, ipv4only) + return hostname(val) or ((ipv4only == 1) and ip4addr(val)) or ((not (ipv4only == 1)) and ipaddr(val)) +end + +function network(val) + return uciname(val) or host(val) +end + +function hostport(val, ipv4only) + local h, p = val:match("^([^:]+):([^:]+)$") + return not not (h and p and host(h, ipv4only) and port(p)) +end + +function ip4addrport(val, bracket) + local h, p = val:match("^([^:]+):([^:]+)$") + return (h and p and ip4addr(h) and port(p)) +end + +function ip4addrport(val) + local h, p = val:match("^([^:]+):([^:]+)$") + return (h and p and ip4addr(h) and port(p)) +end + +function ipaddrport(val, bracket) + local h, p = val:match("^([^%[%]:]+):([^:]+)$") + if (h and p and ip4addr(h) and port(p)) then + return true + elseif (bracket == 1) then + h, p = val:match("^%[(.+)%]:([^:]+)$") + if (h and p and ip6addr(h) and port(p)) then + return true + end + end + h, p = val:match("^([^%[%]]+):([^:]+)$") + return (h and p and ip6addr(h) and port(p)) +end + +function wpakey(val) + if #val == 64 then + return (val:match("^[a-fA-F0-9]+$") ~= nil) + else + return (#val >= 8) and (#val <= 63) + end +end + +function wepkey(val) + if val:sub(1, 2) == "s:" then + val = val:sub(3) + end + + if (#val == 10) or (#val == 26) then + return (val:match("^[a-fA-F0-9]+$") ~= nil) + else + return (#val == 5) or (#val == 13) + end +end + +function hexstring(val) + if val then + return (val:match("^[a-fA-F0-9]+$") ~= nil) + end + return false +end + +function hex(val, maxbytes) + maxbytes = tonumber(maxbytes) + if val and maxbytes ~= nil then + return ((val:match("^0x[a-fA-F0-9]+$") ~= nil) and (#val <= 2 + maxbytes * 2)) + end + return false +end + +function base64(val) + if val then + return (val:match("^[a-zA-Z0-9/+]+=?=?$") ~= nil) and (math.fmod(#val, 4) == 0) + end + return false +end + +function string(val) + return true -- Everything qualifies as valid string +end + +function directory(val, seen) + local s = fs.stat(val) + seen = seen or { } + + if s and not seen[s.ino] then + seen[s.ino] = true + if s.type == "dir" then + return true + elseif s.type == "lnk" then + return directory( fs.readlink(val), seen ) + end + end + + return false +end + +function file(val, seen) + local s = fs.stat(val) + seen = seen or { } + + if s and not seen[s.ino] then + seen[s.ino] = true + if s.type == "reg" then + return true + elseif s.type == "lnk" then + return file( fs.readlink(val), seen ) + end + end + + return false +end + +function device(val, seen) + local s = fs.stat(val) + seen = seen or { } + + if s and not seen[s.ino] then + seen[s.ino] = true + if s.type == "chr" or s.type == "blk" then + return true + elseif s.type == "lnk" then + return device( fs.readlink(val), seen ) + end + end + + return false +end + +function uciname(val) + return (val:match("^[a-zA-Z0-9_]+$") ~= nil) +end + +function range(val, min, max) + val = tonumber(val) + min = tonumber(min) + max = tonumber(max) + + if val ~= nil and min ~= nil and max ~= nil then + return ((val >= min) and (val <= max)) + end + + return false +end + +function min(val, min) + val = tonumber(val) + min = tonumber(min) + + if val ~= nil and min ~= nil then + return (val >= min) + end + + return false +end + +function max(val, max) + val = tonumber(val) + max = tonumber(max) + + if val ~= nil and max ~= nil then + return (val <= max) + end + + return false +end + +function rangelength(val, min, max) + val = tostring(val) + min = tonumber(min) + max = tonumber(max) + + if val ~= nil and min ~= nil and max ~= nil then + return ((#val >= min) and (#val <= max)) + end + + return false +end + +function minlength(val, min) + val = tostring(val) + min = tonumber(min) + + if val ~= nil and min ~= nil then + return (#val >= min) + end + + return false +end + +function maxlength(val, max) + val = tostring(val) + max = tonumber(max) + + if val ~= nil and max ~= nil then + return (#val <= max) + end + + return false +end + +function phonedigit(val) + return (val:match("^[0-9%*#!%.]+$") ~= nil) +end + +function timehhmmss(val) + return (val:match("^[0-6][0-9]:[0-6][0-9]:[0-6][0-9]$") ~= nil) +end + +function dateyyyymmdd(val) + if val ~= nil then + yearstr, monthstr, daystr = val:match("^(%d%d%d%d)-(%d%d)-(%d%d)$") + if (yearstr == nil) or (monthstr == nil) or (daystr == nil) then + return false; + end + year = tonumber(yearstr) + month = tonumber(monthstr) + day = tonumber(daystr) + if (year == nil) or (month == nil) or (day == nil) then + return false; + end + + local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + + local function is_leap_year(year) + return (year % 4 == 0) and ((year % 100 ~= 0) or (year % 400 == 0)) + end + + function get_days_in_month(month, year) + if (month == 2) and is_leap_year(year) then + return 29 + else + return days_in_month[month] + end + end + if (year < 2015) then + return false + end + if ((month == 0) or (month > 12)) then + return false + end + if ((day == 0) or (day > get_days_in_month(month, year))) then + return false + end + return true + end + return false +end + +function unique(val) + return true +end diff --git a/modules/luci-compat/luasrc/model/firewall.lua b/modules/luci-compat/luasrc/model/firewall.lua new file mode 100644 index 0000000000..feff0855c4 --- /dev/null +++ b/modules/luci-compat/luasrc/model/firewall.lua @@ -0,0 +1,568 @@ +-- Copyright 2009 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local type, pairs, ipairs, table, luci, math + = type, pairs, ipairs, table, luci, math + +local tpl = require "luci.template.parser" +local utl = require "luci.util" +local uci = require "luci.model.uci" + +module "luci.model.firewall" + + +local uci_r, uci_s + +function _valid_id(x) + return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$")) +end + +function _get(c, s, o) + return uci_r:get(c, s, o) +end + +function _set(c, s, o, v) + if v ~= nil then + if type(v) == "boolean" then v = v and "1" or "0" end + return uci_r:set(c, s, o, v) + else + return uci_r:delete(c, s, o) + end +end + + +function init(cursor) + uci_r = cursor or uci_r or uci.cursor() + uci_s = uci_r:substate() + + return _M +end + +function save(self, ...) + uci_r:save(...) + uci_r:load(...) +end + +function commit(self, ...) + uci_r:commit(...) + uci_r:load(...) +end + +function get_defaults() + return defaults() +end + +function new_zone(self) + local name = "newzone" + local count = 1 + + while self:get_zone(name) do + count = count + 1 + name = "newzone%d" % count + end + + return self:add_zone(name) +end + +function add_zone(self, n) + if _valid_id(n) and not self:get_zone(n) then + local d = defaults() + local z = uci_r:section("firewall", "zone", nil, { + name = n, + network = " ", + input = d:input() or "DROP", + forward = d:forward() or "DROP", + output = d:output() or "DROP" + }) + + return z and zone(z) + end +end + +function get_zone(self, n) + if uci_r:get("firewall", n) == "zone" then + return zone(n) + else + local z + uci_r:foreach("firewall", "zone", + function(s) + if n and s.name == n then + z = s['.name'] + return false + end + end) + return z and zone(z) + end +end + +function get_zones(self) + local zones = { } + local znl = { } + + uci_r:foreach("firewall", "zone", + function(s) + if s.name then + znl[s.name] = zone(s['.name']) + end + end) + + local z + for z in utl.kspairs(znl) do + zones[#zones+1] = znl[z] + end + + return zones +end + +function get_zone_by_network(self, net) + local z + + uci_r:foreach("firewall", "zone", + function(s) + if s.name and net then + local n + for n in utl.imatch(s.network or s.name) do + if n == net then + z = s['.name'] + return false + end + end + end + end) + + return z and zone(z) +end + +function del_zone(self, n) + local r = false + + if uci_r:get("firewall", n) == "zone" then + local z = uci_r:get("firewall", n, "name") + r = uci_r:delete("firewall", n) + n = z + else + uci_r:foreach("firewall", "zone", + function(s) + if n and s.name == n then + r = uci_r:delete("firewall", s['.name']) + return false + end + end) + end + + if r then + uci_r:foreach("firewall", "rule", + function(s) + if s.src == n or s.dest == n then + uci_r:delete("firewall", s['.name']) + end + end) + + uci_r:foreach("firewall", "redirect", + function(s) + if s.src == n or s.dest == n then + uci_r:delete("firewall", s['.name']) + end + end) + + uci_r:foreach("firewall", "forwarding", + function(s) + if s.src == n or s.dest == n then + uci_r:delete("firewall", s['.name']) + end + end) + end + + return r +end + +function rename_zone(self, old, new) + local r = false + + if _valid_id(new) and not self:get_zone(new) then + uci_r:foreach("firewall", "zone", + function(s) + if old and s.name == old then + if not s.network then + uci_r:set("firewall", s['.name'], "network", old) + end + uci_r:set("firewall", s['.name'], "name", new) + r = true + return false + end + end) + + if r then + uci_r:foreach("firewall", "rule", + function(s) + if s.src == old then + uci_r:set("firewall", s['.name'], "src", new) + end + if s.dest == old then + uci_r:set("firewall", s['.name'], "dest", new) + end + end) + + uci_r:foreach("firewall", "redirect", + function(s) + if s.src == old then + uci_r:set("firewall", s['.name'], "src", new) + end + if s.dest == old then + uci_r:set("firewall", s['.name'], "dest", new) + end + end) + + uci_r:foreach("firewall", "forwarding", + function(s) + if s.src == old then + uci_r:set("firewall", s['.name'], "src", new) + end + if s.dest == old then + uci_r:set("firewall", s['.name'], "dest", new) + end + end) + end + end + + return r +end + +function del_network(self, net) + local z + if net then + for _, z in ipairs(self:get_zones()) do + z:del_network(net) + end + end +end + + +defaults = utl.class() +function defaults.__init__(self) + uci_r:foreach("firewall", "defaults", + function(s) + self.sid = s['.name'] + return false + end) + + self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { }) +end + +function defaults.get(self, opt) + return _get("firewall", self.sid, opt) +end + +function defaults.set(self, opt, val) + return _set("firewall", self.sid, opt, val) +end + +function defaults.syn_flood(self) + return (self:get("syn_flood") == "1") +end + +function defaults.drop_invalid(self) + return (self:get("drop_invalid") == "1") +end + +function defaults.input(self) + return self:get("input") or "DROP" +end + +function defaults.forward(self) + return self:get("forward") or "DROP" +end + +function defaults.output(self) + return self:get("output") or "DROP" +end + + +zone = utl.class() +function zone.__init__(self, z) + if uci_r:get("firewall", z) == "zone" then + self.sid = z + self.data = uci_r:get_all("firewall", z) + else + uci_r:foreach("firewall", "zone", + function(s) + if s.name == z then + self.sid = s['.name'] + self.data = s + return false + end + end) + end +end + +function zone.get(self, opt) + return _get("firewall", self.sid, opt) +end + +function zone.set(self, opt, val) + return _set("firewall", self.sid, opt, val) +end + +function zone.masq(self) + return (self:get("masq") == "1") +end + +function zone.name(self) + return self:get("name") +end + +function zone.network(self) + return self:get("network") +end + +function zone.input(self) + return self:get("input") or defaults():input() or "DROP" +end + +function zone.forward(self) + return self:get("forward") or defaults():forward() or "DROP" +end + +function zone.output(self) + return self:get("output") or defaults():output() or "DROP" +end + +function zone.add_network(self, net) + if uci_r:get("network", net) == "interface" then + local nets = { } + + local n + for n in utl.imatch(self:get("network") or self:get("name")) do + if n ~= net then + nets[#nets+1] = n + end + end + + nets[#nets+1] = net + + _M:del_network(net) + self:set("network", table.concat(nets, " ")) + end +end + +function zone.del_network(self, net) + local nets = { } + + local n + for n in utl.imatch(self:get("network") or self:get("name")) do + if n ~= net then + nets[#nets+1] = n + end + end + + if #nets > 0 then + self:set("network", table.concat(nets, " ")) + else + self:set("network", " ") + end +end + +function zone.get_networks(self) + local nets = { } + + local n + for n in utl.imatch(self:get("network") or self:get("name")) do + nets[#nets+1] = n + end + + return nets +end + +function zone.clear_networks(self) + self:set("network", " ") +end + +function zone.get_forwardings_by(self, what) + local name = self:name() + local forwards = { } + + uci_r:foreach("firewall", "forwarding", + function(s) + if s.src and s.dest and s[what] == name then + forwards[#forwards+1] = forwarding(s['.name']) + end + end) + + return forwards +end + +function zone.add_forwarding_to(self, dest) + local exist, forward + + for _, forward in ipairs(self:get_forwardings_by('src')) do + if forward:dest() == dest then + exist = true + break + end + end + + if not exist and dest ~= self:name() and _valid_id(dest) then + local s = uci_r:section("firewall", "forwarding", nil, { + src = self:name(), + dest = dest + }) + + return s and forwarding(s) + end +end + +function zone.add_forwarding_from(self, src) + local exist, forward + + for _, forward in ipairs(self:get_forwardings_by('dest')) do + if forward:src() == src then + exist = true + break + end + end + + if not exist and src ~= self:name() and _valid_id(src) then + local s = uci_r:section("firewall", "forwarding", nil, { + src = src, + dest = self:name() + }) + + return s and forwarding(s) + end +end + +function zone.del_forwardings_by(self, what) + local name = self:name() + + uci_r:delete_all("firewall", "forwarding", + function(s) + return (s.src and s.dest and s[what] == name) + end) +end + +function zone.add_redirect(self, options) + options = options or { } + options.src = self:name() + + local s = uci_r:section("firewall", "redirect", nil, options) + return s and redirect(s) +end + +function zone.add_rule(self, options) + options = options or { } + options.src = self:name() + + local s = uci_r:section("firewall", "rule", nil, options) + return s and rule(s) +end + +function zone.get_color(self) + if self and self:name() == "lan" then + return "#90f090" + elseif self and self:name() == "wan" then + return "#f09090" + elseif self then + math.randomseed(tpl.hash(self:name())) + + local r = math.random(128) + local g = math.random(128) + local min = 0 + local max = 128 + + if ( r + g ) < 128 then + min = 128 - r - g + else + max = 255 - r - g + end + + local b = min + math.floor( math.random() * ( max - min ) ) + + return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b } + else + return "#eeeeee" + end +end + + +forwarding = utl.class() +function forwarding.__init__(self, f) + self.sid = f +end + +function forwarding.src(self) + return uci_r:get("firewall", self.sid, "src") +end + +function forwarding.dest(self) + return uci_r:get("firewall", self.sid, "dest") +end + +function forwarding.src_zone(self) + local z = zone(self:src()) + return z.sid and z +end + +function forwarding.dest_zone(self) + local z = zone(self:dest()) + return z.sid and z +end + + +rule = utl.class() +function rule.__init__(self, f) + self.sid = f +end + +function rule.get(self, opt) + return _get("firewall", self.sid, opt) +end + +function rule.set(self, opt, val) + return _set("firewall", self.sid, opt, val) +end + +function rule.src(self) + return uci_r:get("firewall", self.sid, "src") +end + +function rule.dest(self) + return uci_r:get("firewall", self.sid, "dest") +end + +function rule.src_zone(self) + return zone(self:src()) +end + +function rule.dest_zone(self) + return zone(self:dest()) +end + + +redirect = utl.class() +function redirect.__init__(self, f) + self.sid = f +end + +function redirect.get(self, opt) + return _get("firewall", self.sid, opt) +end + +function redirect.set(self, opt, val) + return _set("firewall", self.sid, opt, val) +end + +function redirect.src(self) + return uci_r:get("firewall", self.sid, "src") +end + +function redirect.dest(self) + return uci_r:get("firewall", self.sid, "dest") +end + +function redirect.src_zone(self) + return zone(self:src()) +end + +function redirect.dest_zone(self) + return zone(self:dest()) +end diff --git a/modules/luci-compat/luasrc/view/cbi/browser.htm b/modules/luci-compat/luasrc/view/cbi/browser.htm new file mode 100644 index 0000000000..eb47ffafe6 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/browser.htm @@ -0,0 +1,10 @@ +<%+cbi/valueheader%> + + /> + +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/button.htm b/modules/luci-compat/luasrc/view/cbi/button.htm new file mode 100644 index 0000000000..6ccba58f23 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/cell_valuefooter.htm b/modules/luci-compat/luasrc/view/cbi/cell_valuefooter.htm new file mode 100644 index 0000000000..bdd6bc9687 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/cell_valuefooter.htm @@ -0,0 +1,2 @@ + + diff --git a/modules/luci-compat/luasrc/view/cbi/cell_valueheader.htm b/modules/luci-compat/luasrc/view/cbi/cell_valueheader.htm new file mode 100644 index 0000000000..4b70957543 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/cell_valueheader.htm @@ -0,0 +1,12 @@ +<%- + local title = luci.util.trim(striptags(self.title)) + local descr = luci.util.trim(striptags(self.description)) + local ftype = self.typename or (self.template and self.template:gsub("^.+/", "")) +-%> +
0, "data-type", ftype) .. + ifattr(title and #title > 0, "data-title", title, true) .. + ifattr(descr and #descr > 0, "data-description", descr, true) +%>> +
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> diff --git a/modules/luci-compat/luasrc/view/cbi/compound.htm b/modules/luci-compat/luasrc/view/cbi/compound.htm new file mode 100644 index 0000000000..12d02bb1d8 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/compound.htm @@ -0,0 +1 @@ +<%- self:render_children() %> diff --git a/modules/luci-compat/luasrc/view/cbi/delegator.htm b/modules/luci-compat/luasrc/view/cbi/delegator.htm new file mode 100644 index 0000000000..4fd19265d8 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/delegator.htm @@ -0,0 +1,24 @@ +<%- self.active:render() %> +
+ +<% for _, x in ipairs(self.chain) do %> + +<% end %> +<% if not self.disallow_pageactions then %> +<% if self.allow_finish and not self:get_next(self.current) then %> + +<% elseif self:get_next(self.current) then %> + +<% end %> +<% if self.allow_cancel then %> + +<% end %> +<% if self.allow_reset then %> + +<% end %> +<% if self.allow_back and self:get_prev(self.current) then %> + +<% end %> +<% end %> + +
diff --git a/modules/luci-compat/luasrc/view/cbi/dropdown.htm b/modules/luci-compat/luasrc/view/cbi/dropdown.htm new file mode 100644 index 0000000000..927ecf2396 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/dropdown.htm @@ -0,0 +1,19 @@ +<%+cbi/valueheader%> +>
+<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/dvalue.htm b/modules/luci-compat/luasrc/view/cbi/dvalue.htm new file mode 100644 index 0000000000..78e6f323d7 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/dvalue.htm @@ -0,0 +1,13 @@ +<%+cbi/valueheader%> +<% if self.href then %><% end -%> + <% + local val = self:cfgvalue(section) or self.default or "" + if not self.rawhtml then + write(pcdata(val)) + else + write(val) + end + %> +<%- if self.href then %><%end%> +" /> +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/dynlist.htm b/modules/luci-compat/luasrc/view/cbi/dynlist.htm new file mode 100644 index 0000000000..2a3da67ff9 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/dynlist.htm @@ -0,0 +1,12 @@ +<%+cbi/valueheader%> +>
+<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/error.htm b/modules/luci-compat/luasrc/view/cbi/error.htm new file mode 100644 index 0000000000..75ec1082aa --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/error.htm @@ -0,0 +1,19 @@ +
+ <% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> + <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> + +

+ <%: The configuration file could not be loaded due to the following error: %>
+ <%=pcdata(self.error)%> +

+ + + +

+ <%: Edit the raw configuration data above to fix any error and hit "Save" to reload the page. %> +

+ +
+ +
+
diff --git a/modules/luci-compat/luasrc/view/cbi/footer.htm b/modules/luci-compat/luasrc/view/cbi/footer.htm new file mode 100644 index 0000000000..ed632202ce --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/footer.htm @@ -0,0 +1,41 @@ +<% + local display_back = (redirect and not flow.hidebackbtn) + local display_skip = (flow.skip) + local display_apply = (not autoapply and not flow.hideapplybtn) + local display_save = (not flow.hidesavebtn) + local display_reset = (not flow.hideresetbtn) + + if pageaction and + (display_back or display_skip or display_apply or display_save or display_reset) + then + %>
<% + + if display_back then + %> <% + end + + if display_skip then + %> <% + end + + if display_apply then + %> <% + end + + if display_save then + %> <% + end + + if display_reset then + %> <% + end + + %>
<% + end +%> + + + + + +<%+footer%> diff --git a/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm b/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm new file mode 100644 index 0000000000..d4ad093efa --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/full_valuefooter.htm @@ -0,0 +1,12 @@ + <% if self.description and #self.description > 0 then -%> + <% if not luci.util.instanceof(self, luci.cbi.DynamicList) and (not luci.util.instanceof(self, luci.cbi.Flag) or self.orientation == "horizontal") then -%> +
+ <%- end %> +
+ <%=self.description%> +
+ <%- end %> + <%- if self.title and #self.title > 0 then -%> + + <%- end -%> + diff --git a/modules/luci-compat/luasrc/view/cbi/full_valueheader.htm b/modules/luci-compat/luasrc/view/cbi/full_valueheader.htm new file mode 100644 index 0000000000..1d9ebeba94 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/full_valueheader.htm @@ -0,0 +1,9 @@ +
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> + <%- if self.title and #self.title > 0 then -%> + +
+ <%- end -%> diff --git a/modules/luci-compat/luasrc/view/cbi/fvalue.htm b/modules/luci-compat/luasrc/view/cbi/fvalue.htm new file mode 100644 index 0000000000..7f975b95e1 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/fvalue.htm @@ -0,0 +1,12 @@ +<%+cbi/valueheader%> +>
+<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/header.htm b/modules/luci-compat/luasrc/view/cbi/header.htm new file mode 100644 index 0000000000..821fa3efae --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/header.htm @@ -0,0 +1,18 @@ +<%+header%> +
> +
+ + + +
diff --git a/modules/luci-compat/luasrc/view/cbi/ipaddr.htm b/modules/luci-compat/luasrc/view/cbi/ipaddr.htm new file mode 100644 index 0000000000..1c924e1544 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/ipaddr.htm @@ -0,0 +1,27 @@ +<%+cbi/valueheader%> + + 0, "data-choices", { self.keylist, self.vallist }) + %> /> +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/lvalue.htm b/modules/luci-compat/luasrc/view/cbi/lvalue.htm new file mode 100644 index 0000000000..28141472f4 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/lvalue.htm @@ -0,0 +1,14 @@ +<%+cbi/valueheader%> +>
+<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/map.htm b/modules/luci-compat/luasrc/view/cbi/map.htm new file mode 100644 index 0000000000..cda4d3530c --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/map.htm @@ -0,0 +1,40 @@ +<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%> +
<%=pcdata(msg)%>
+<%- end end -%> + +
+ <% if self.title and #self.title > 0 then %> +

<%=self.title%>

+ <% end %> + <% if self.description and #self.description > 0 then %> +
<%=self.description%>
+ <% end %> + <% if self.tabbed then %> +
+ <% for i, section in ipairs(self.children) do + tab = section.section or section.sectiontype %> +
> + <% section:render() %> +
+ <% end %> +
+ + <% if not self.save then -%> +
+ <% for _, section in ipairs(self.children) do %> + <% if section.error and section.error[section.section] then -%> +
  • + <%:One or more invalid/required values on tab%>: <%=section.title or section.section or section.sectiontype%> +
+ <%- end %> + <% end %> +
+ <%- end %> + <% else %> + <%- self:render_children() %> + <% end %> +
diff --git a/modules/luci-compat/luasrc/view/cbi/mvalue.htm b/modules/luci-compat/luasrc/view/cbi/mvalue.htm new file mode 100644 index 0000000000..1f4f4dbcc6 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/mvalue.htm @@ -0,0 +1,24 @@ +<%+cbi/valueheader%> +<% + local util = require "luci.util" + local values = {} + local value + for value in util.imatch(self:cfgvalue(section) or self.default) do + values[#values+1] = value + end +%> +> +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/nsection.htm b/modules/luci-compat/luasrc/view/cbi/nsection.htm new file mode 100644 index 0000000000..14232e3d94 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/nsection.htm @@ -0,0 +1,29 @@ +<% if self:cfgvalue(self.section) then section = self.section %> +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> + <% if self.description and #self.description > 0 then -%> +
<%=self.description%>
+ <%- end %> + <% if self.addremove then -%> +
+ +
+ <%- end %> +
+ <%+cbi/ucisection%> +
+
+<% elseif self.addremove then %> + <% if self.template_addremove then include(self.template_addremove) else -%> +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> +
<%=self.description%>
+ +
+ <%- end %> +<% end %> + diff --git a/modules/luci-compat/luasrc/view/cbi/nullsection.htm b/modules/luci-compat/luasrc/view/cbi/nullsection.htm new file mode 100644 index 0000000000..7230719d19 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/nullsection.htm @@ -0,0 +1,37 @@ +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> + <% if self.description and #self.description > 0 then -%> +
<%=self.description%>
+ <%- end %> +
+
+ <% self:render_children(1, scope or {}) %> +
+ <% if self.error and self.error[1] then -%> +
+
    <% for _, e in ipairs(self.error[1]) do -%> +
  • + <%- if e == "invalid" then -%> + <%:One or more fields contain invalid values!%> + <%- elseif e == "missing" then -%> + <%:One or more required fields have no value!%> + <%- else -%> + <%=pcdata(e)%> + <%- end -%> +
  • + <%- end %>
+
+ <%- end %> +
+
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> diff --git a/modules/luci-compat/luasrc/view/cbi/simpleform.htm b/modules/luci-compat/luasrc/view/cbi/simpleform.htm new file mode 100644 index 0000000000..3e10724ec5 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/simpleform.htm @@ -0,0 +1,77 @@ +<% + if not self.embedded then + %> + + <% + end + + %>
<% + + if self.title and #self.title > 0 then + %>

<%=self.title%>

<% + end + + if self.description and #self.description > 0 then + %>
<%=self.description%>
<% + end + + self:render_children() + + %>
<% + + if self.message then + %>
<%=self.message%>
<% + end + + if self.errmessage then + %>
<%=self.errmessage%>
<% + end + + if not self.embedded then + if type(self.hidden) == "table" then + local k, v + for k, v in pairs(self.hidden) do + %><% + end + end + + local display_back = (redirect) + local display_cancel = (self.cancel ~= false and self.on_cancel) + local display_skip = (self.flow and self.flow.skip) + local display_submit = (self.submit ~= false) + local display_reset = (self.reset ~= false) + + if display_back or display_cancel or display_skip or display_submit or display_reset then + %>
<% + + if display_back then + %> <% + end + + if display_cancel then + local label = pcdata(self.cancel or translate("Cancel")) + %> <% + end + + if display_skip then + %> <% + end + + if display_submit then + local label = pcdata(self.submit or translate("Submit")) + %> <% + end + + if display_reset then + local label = pcdata(self.reset or translate("Reset")) + %> <% + end + + %>
<% + end + + %><% + end +%> + + diff --git a/modules/luci-compat/luasrc/view/cbi/tabcontainer.htm b/modules/luci-compat/luasrc/view/cbi/tabcontainer.htm new file mode 100644 index 0000000000..7fcb835783 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/tabcontainer.htm @@ -0,0 +1,14 @@ +<% for _, tab in ipairs(self.tab_names) do data = self.tabs[tab] %> +
> + <% if data.description then %> +
<%=data.description%>
+ <% end %> + + <% self:render_tab(tab, section, scope or {}) %> +
+<% end %> diff --git a/modules/luci-compat/luasrc/view/cbi/tblsection.htm b/modules/luci-compat/luasrc/view/cbi/tblsection.htm new file mode 100644 index 0000000000..11c2206d8c --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/tblsection.htm @@ -0,0 +1,203 @@ +<%- +local rowcnt = 0 + +function rowstyle() + rowcnt = rowcnt + 1 + if rowcnt % 2 == 0 then + return " cbi-rowstyle-1" + else + return " cbi-rowstyle-2" + end +end + +function width(o) + if o.width then + if type(o.width) == 'number' then + return ' style="width:%dpx"' % o.width + end + return ' style="width:%s"' % o.width + end + return '' +end + +local has_titles = false +local has_descriptions = false + +local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous" +local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name")) + +local i, k +for i, k in pairs(self.children) do + if not k.typename then + k.typename = k.template and k.template:gsub("^.+/", "") or "" + end + + if not has_titles and k.title and #k.title > 0 then + has_titles = true + end + + if not has_descriptions and k.description and #k.description > 0 then + has_descriptions = true + end +end + +function render_titles() + if not has_titles then + return + end + + %>
><% + + local i, k + for i, k in ipairs(self.children) do + if not k.optional then + %>
><% + + if k.titleref then + %><% + end + + write(k.title) + + if k.titleref then + %><% + end + + %>
<% + end + end + + if self.sortable or self.extedit or self.addremove then + %>
<% + end + + %>
<% + + rowcnt = rowcnt + 1 +end + +function render_descriptions() + if not has_descriptions then + return + end + + %>
<% + + local i, k + for i, k in ipairs(self.children) do + if not k.optional then + %>
><% + + write(k.description) + + %>
<% + end + end + + if self.sortable or self.extedit or self.addremove then + %>
<% + end + + %>
<% + + rowcnt = rowcnt + 1 +end + +-%> + + +
+ <% if self.title and #self.title > 0 then -%> +

<%=self.title%>

+ <%- end %> + <%- if self.sortable then -%> + + <%- end -%> +
<%=self.description%>
+
+ <%- + render_titles() + render_descriptions() + + local isempty, section, i, k = true, nil, nil + for i, k in ipairs(self:cfgsections()) do + isempty = false + 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, true) + local colorclass = (self.extedit or self.rowcolors) and rowstyle() or "" + local scope = { + valueheader = "cbi/cell_valueheader", + valuefooter = "cbi/cell_valuefooter" + } + -%> +
> + <%- + local node + for k, node in ipairs(self.children) do + if not node.optional then + node:render(section, scope or {}) + end + end + -%> + + <%- if self.sortable or self.extedit or self.addremove then -%> +
+
+ <%- if self.sortable then -%> + + + <% end; if self.extedit then -%> + onclick="location.href='<%=self.extedit:format(section)%>'" + <%- elseif type(self.extedit) == "function" then + %> onclick="location.href='<%=self:extedit(section)%>'" + <%- end + %> alt="<%:Edit%>" title="<%:Edit%>" /> + <% end; if self.addremove then %> + + <%- end -%> +
+
+ <%- end -%> +
+ <%- end -%> + + <%- if isempty then -%> +
+
<%:This section contains no values yet%>
+
+ <%- end -%> +
+ + <% if self.error then %> +
+
    <% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%> +
  • <%=pcdata(e):gsub("\n","
    ")%>
  • + <%- end end %>
+
+ <% end %> + + <%- if self.addremove then -%> + <% if self.template_addremove then include(self.template_addremove) else -%> +
+ <% if self.anonymous then %> + + <% else %> + <% if self.invalid_cts then -%> +
<%:Invalid%>
+ <%- end %> +
+ +
+ + <% end %> +
+ <%- end %> + <%- end -%> +
+ diff --git a/modules/luci-compat/luasrc/view/cbi/tsection.htm b/modules/luci-compat/luasrc/view/cbi/tsection.htm new file mode 100644 index 0000000000..8f3b7f0ffb --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/tsection.htm @@ -0,0 +1,52 @@ +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> + <% if self.error_msg and #self.error_msg > 0 then -%> +
+ <%=self.error_msg%> +
+ <%- end %> + <% if self.description and #self.description > 0 then -%> +
<%=self.description%>
+ <%- end %> + <% local isempty = true for i, k in ipairs(self:cfgsections()) do -%> + <% if self.addremove then -%> +
+ +
+ <%- end %> + + <%- section = k; isempty = false -%> + + <% if not self.anonymous then -%> +

<%=section:upper()%>

+ <%- end %> + +
+ <%+cbi/ucisection%> +
+ <%- end %> + + <% if isempty then -%> + <%:This section contains no values yet%>

+ <%- end %> + + <% if self.addremove then -%> + <% if self.template_addremove then include(self.template_addremove) else -%> +
+ <% if self.anonymous then -%> + + <%- else -%> + <% if self.invalid_cts then -%> +
<%:Invalid%>
+ <%- end %> +
+ +
+ + <%- end %> +
+ <%- end %> + <%- end %> +
diff --git a/modules/luci-compat/luasrc/view/cbi/tvalue.htm b/modules/luci-compat/luasrc/view/cbi/tvalue.htm new file mode 100644 index 0000000000..f3b12bd094 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/tvalue.htm @@ -0,0 +1,5 @@ +<%+cbi/valueheader%> + +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/ucisection.htm b/modules/luci-compat/luasrc/view/cbi/ucisection.htm new file mode 100644 index 0000000000..8fa11d68f8 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/ucisection.htm @@ -0,0 +1,56 @@ +<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> + +<% if self.tabs then %> + <%+cbi/tabcontainer%> +<% else %> + <% self:render_children(section, scope or {}) %> +<% end %> + +<% if self.error and self.error[section] then -%> +
+
    <% for _, e in ipairs(self.error[section]) do -%> +
  • + <%- if e == "invalid" then -%> + <%:One or more fields contain invalid values!%> + <%- elseif e == "missing" then -%> + <%:One or more required fields have no value!%> + <%- else -%> + <%=pcdata(e)%> + <%- end -%> +
  • + <%- end %>
+
+<%- end %> + +<% if self.optionals[section] and #self.optionals[section] > 0 or self.dynamic then %> +
+ <%- + if self.dynamic then + local keys, vals, name, opt = { }, { } + for name, opt in pairs(self.optionals[section]) do + keys[#keys+1] = name + vals[#vals+1] = opt.title + end + -%> + 0, "data-choices", luci.util.json_encode({keys, vals})) + %> /> + <%- else -%> + + <%- end -%> + +
+<% end %> diff --git a/modules/luci-compat/luasrc/view/cbi/upload.htm b/modules/luci-compat/luasrc/view/cbi/upload.htm new file mode 100644 index 0000000000..e610495380 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/upload.htm @@ -0,0 +1,14 @@ +<%+cbi/valueheader%> + +> + +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/value.htm b/modules/luci-compat/luasrc/view/cbi/value.htm new file mode 100644 index 0000000000..6060310b19 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/value.htm @@ -0,0 +1,35 @@ +<%+cbi/valueheader%> + +<% local choices = self:choices() + if choices then %> + > +<% else %> + > +<% end %> + +<%+cbi/valuefooter%> diff --git a/modules/luci-compat/luasrc/view/cbi/valuefooter.htm b/modules/luci-compat/luasrc/view/cbi/valuefooter.htm new file mode 100644 index 0000000000..805312e451 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/valuefooter.htm @@ -0,0 +1 @@ +<% include( valuefooter or "cbi/full_valuefooter" ) %> diff --git a/modules/luci-compat/luasrc/view/cbi/valueheader.htm b/modules/luci-compat/luasrc/view/cbi/valueheader.htm new file mode 100644 index 0000000000..761a54aed0 --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/valueheader.htm @@ -0,0 +1 @@ +<% include( valueheader or "cbi/full_valueheader" ) %> diff --git a/modules/luci-compat/luasrc/view/cbi/wireless_modefreq.htm b/modules/luci-compat/luasrc/view/cbi/wireless_modefreq.htm new file mode 100644 index 0000000000..eeb1d5c5cb --- /dev/null +++ b/modules/luci-compat/luasrc/view/cbi/wireless_modefreq.htm @@ -0,0 +1,173 @@ +<%+cbi/valueheader%> + + + + + + + +
+ + + +<%+cbi/valuefooter%> diff --git a/modules/luci-mod-admin-mini/Makefile b/modules/luci-mod-admin-mini/Makefile index 5da4cafc94..de00489926 100644 --- a/modules/luci-mod-admin-mini/Makefile +++ b/modules/luci-mod-admin-mini/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Essentials - stripped down and user-friendly -LUCI_DEPENDS:=+luci-base @BROKEN +LUCI_DEPENDS:=+luci-base +luci-compat @BROKEN include ../../luci.mk -- cgit v1.2.3