From 3f05beee37781af8687dcfeb460dab8a22959f9a Mon Sep 17 00:00:00 2001 From: Cameron Thompson <50184035+iamromulan@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:39:32 -0500 Subject: [PATCH] Add Luci Theme argon and app - Also added missing depends from source: https://dl.openwrt.ai/packages-24.10/aarch64_cortex-a53/ - Argon theme and app source: https://github.com/jerrykuku/luci-theme-argon --- .../CONTROL/control | 14 + .../CONTROL/postinst | 5 + .../CONTROL/prerm | 4 + .../build-ipk | 74 + .../root/usr/lib/libucode.so.20230711 | Bin 0 -> 197155 bytes .../luci-app-argon-config/CONTROL/conffiles | 1 + .../luci-app-argon-config/CONTROL/control | 11 + .../luci-app-argon-config/CONTROL/postinst | 5 + .../CONTROL/postinst-pkg | 7 + .../luci-app-argon-config/CONTROL/prerm | 4 + ipk-source/luci-app-argon-config/build-ipk | 74 + .../root/etc/config/argon | 9 + .../root/etc/uci-defaults/luci-argon-config | 6 + .../lib/lua/luci/controller/argon-config.lua | 10 + .../lib/lua/luci/model/cbi/argon-config.lua | 217 +++ .../luci/view/argon-config/other_button.htm | 7 + .../luci/view/argon-config/other_dvalue.htm | 8 + .../luci/view/argon-config/other_upload.htm | 5 + .../rpcd/acl.d/luci-app-argon-config.json | 11 + .../CONTROL/control | 13 + .../CONTROL/postinst | 5 + .../CONTROL/postinst-pkg | 5 + .../CONTROL/prerm | 4 + .../build-ipk | 74 + .../root/usr/lib/lua/luci/cacheloader.lua | 12 + .../root/usr/lib/lua/luci/ccache.lua | 76 ++ .../root/usr/lib/lua/luci/config.lua | 18 + .../root/usr/lib/lua/luci/dispatcher.lua | 484 +++++++ .../root/usr/lib/lua/luci/i18n.lua | 55 + .../root/usr/lib/lua/luci/model/uci.lua | 508 +++++++ .../root/usr/lib/lua/luci/store.lua | 6 + .../root/usr/lib/lua/luci/sys.lua | 615 +++++++++ .../root/usr/lib/lua/luci/sys/zoneinfo.lua | 19 + .../usr/lib/lua/luci/sys/zoneinfo/tzdata.lua | 455 +++++++ .../lib/lua/luci/sys/zoneinfo/tzoffset.lua | 46 + .../root/usr/lib/lua/luci/template.lua | 184 +++ .../root/usr/lib/lua/luci/template/parser.so | Bin 0 -> 65666 bytes .../root/usr/lib/lua/luci/ucodebridge.lua | 54 + .../root/usr/lib/lua/luci/version.lua | 20 + .../lua/luci/view/admin_status/luaindex.htm | 18 + .../lua/luci/view/empty_node_placeholder.htm | 11 + .../root/usr/lib/lua/luci/view/indexer.htm | 7 + .../root/usr/lib/lua/luci/xml.lua | 26 + ipk-source/luci-theme-argon/CONTROL/control | 12 + ipk-source/luci-theme-argon/CONTROL/postinst | 5 + .../luci-theme-argon/CONTROL/postinst-pkg | 5 + ipk-source/luci-theme-argon/CONTROL/prerm | 4 + ipk-source/luci-theme-argon/build-ipk | 74 + .../root/etc/uci-defaults/30_luci-theme-argon | 12 + .../lib/lua/luci/view/themes/argon/footer.htm | 46 + .../luci/view/themes/argon/footer_login.htm | 44 + .../lib/lua/luci/view/themes/argon/header.htm | 180 +++ .../luci/view/themes/argon/header_login.htm | 119 ++ .../view/themes/argon/out_header_login.htm | 14 + .../lua/luci/view/themes/argon/sysauth.htm | 163 +++ .../root/usr/libexec/argon/online_wallpaper | 105 ++ .../luci-static/argon/background/README.md | 2 + .../www/luci-static/argon/css/cascade.css | 9 + .../root/www/luci-static/argon/css/dark.css | 1 + .../root/www/luci-static/argon/favicon.ico | Bin 0 -> 9662 bytes .../luci-static/argon/fonts/TypoGraphica.eot | Bin 0 -> 33846 bytes .../luci-static/argon/fonts/TypoGraphica.svg | 1191 +++++++++++++++++ .../luci-static/argon/fonts/TypoGraphica.ttf | Bin 0 -> 33632 bytes .../luci-static/argon/fonts/TypoGraphica.woff | Bin 0 -> 17816 bytes .../www/luci-static/argon/fonts/argon.eot | Bin 0 -> 8888 bytes .../www/luci-static/argon/fonts/argon.svg | 38 + .../www/luci-static/argon/fonts/argon.ttf | Bin 0 -> 8732 bytes .../www/luci-static/argon/fonts/argon.woff | Bin 0 -> 8808 bytes .../argon/icon/android-icon-192x192.png | Bin 0 -> 8300 bytes .../argon/icon/apple-icon-144x144.png | Bin 0 -> 6568 bytes .../argon/icon/apple-icon-60x60.png | Bin 0 -> 3590 bytes .../argon/icon/apple-icon-72x72.png | Bin 0 -> 4003 bytes .../root/www/luci-static/argon/icon/arrow.svg | 3 + .../luci-static/argon/icon/browserconfig.xml | 2 + .../luci-static/argon/icon/favicon-16x16.png | Bin 0 -> 2069 bytes .../luci-static/argon/icon/favicon-32x32.png | Bin 0 -> 2604 bytes .../luci-static/argon/icon/favicon-96x96.png | Bin 0 -> 4805 bytes .../www/luci-static/argon/icon/manifest.json | 41 + .../argon/icon/ms-icon-144x144.png | Bin 0 -> 6568 bytes .../www/luci-static/argon/icon/spinner.svg | 3 + .../root/www/luci-static/argon/img/argon.svg | 37 + .../root/www/luci-static/argon/img/bg1.jpg | Bin 0 -> 159265 bytes .../root/www/luci-static/argon/img/blank.png | Bin 0 -> 938 bytes .../www/luci-static/argon/img/volume_high.svg | 3 + .../www/luci-static/argon/img/volume_off.svg | 3 + .../www/luci-static/argon/js/jquery.min.js | 2 + .../www/luci-static/argon/js/jquery.min.js.o | 0 .../www/luci-static/argon/js/polyfill.min.js | 3 + .../luci-static/argon/js/polyfill.min.js.o | 0 .../www/luci-static/resources/menu-argon.js | 158 +++ .../www/luci-static/resources/menu-argon.js.o | 0 .../CONTROL/control | 12 + .../CONTROL/postinst | 5 + .../CONTROL/prerm | 4 + .../build-ipk | 74 + .../root/usr/lib/ucode/lua.so | Bin 0 -> 65539 bytes 96 files changed, 5561 insertions(+) create mode 100644 ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/control create mode 100755 ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/postinst create mode 100755 ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/prerm create mode 100755 ipk-source/libucode20230711_aarch64_cortex-a53/build-ipk create mode 100644 ipk-source/libucode20230711_aarch64_cortex-a53/root/usr/lib/libucode.so.20230711 create mode 100644 ipk-source/luci-app-argon-config/CONTROL/conffiles create mode 100644 ipk-source/luci-app-argon-config/CONTROL/control create mode 100755 ipk-source/luci-app-argon-config/CONTROL/postinst create mode 100755 ipk-source/luci-app-argon-config/CONTROL/postinst-pkg create mode 100755 ipk-source/luci-app-argon-config/CONTROL/prerm create mode 100755 ipk-source/luci-app-argon-config/build-ipk create mode 100644 ipk-source/luci-app-argon-config/root/etc/config/argon create mode 100755 ipk-source/luci-app-argon-config/root/etc/uci-defaults/luci-argon-config create mode 100644 ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/controller/argon-config.lua create mode 100644 ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/model/cbi/argon-config.lua create mode 100644 ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_button.htm create mode 100644 ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_dvalue.htm create mode 100644 ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_upload.htm create mode 100644 ipk-source/luci-app-argon-config/root/usr/share/rpcd/acl.d/luci-app-argon-config.json create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/control create mode 100755 ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst create mode 100755 ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst-pkg create mode 100755 ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/prerm create mode 100755 ipk-source/luci-lua-runtime_aarch64_cortex-a53/build-ipk create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/cacheloader.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/ccache.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/config.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/dispatcher.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/i18n.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/model/uci.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/store.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzdata.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzoffset.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template.lua create mode 100755 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template/parser.so create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/ucodebridge.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/version.lua create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/admin_status/luaindex.htm create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/empty_node_placeholder.htm create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/indexer.htm create mode 100644 ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/xml.lua create mode 100644 ipk-source/luci-theme-argon/CONTROL/control create mode 100755 ipk-source/luci-theme-argon/CONTROL/postinst create mode 100755 ipk-source/luci-theme-argon/CONTROL/postinst-pkg create mode 100755 ipk-source/luci-theme-argon/CONTROL/prerm create mode 100755 ipk-source/luci-theme-argon/build-ipk create mode 100644 ipk-source/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer.htm create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer_login.htm create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header.htm create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header_login.htm create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/out_header_login.htm create mode 100644 ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/sysauth.htm create mode 100755 ipk-source/luci-theme-argon/root/usr/libexec/argon/online_wallpaper create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/background/README.md create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/css/cascade.css create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/css/dark.css create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/favicon.ico create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/TypoGraphica.eot create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/TypoGraphica.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/TypoGraphica.ttf create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/TypoGraphica.woff create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/argon.eot create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/argon.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/argon.ttf create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/fonts/argon.woff create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/android-icon-192x192.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/apple-icon-144x144.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/apple-icon-60x60.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/apple-icon-72x72.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/arrow.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/browserconfig.xml create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/favicon-16x16.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/favicon-32x32.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/favicon-96x96.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/manifest.json create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/ms-icon-144x144.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/icon/spinner.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/img/argon.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/img/bg1.jpg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/img/blank.png create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/img/volume_high.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/img/volume_off.svg create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/js/jquery.min.js create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/js/jquery.min.js.o create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/js/polyfill.min.js create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/argon/js/polyfill.min.js.o create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/resources/menu-argon.js create mode 100644 ipk-source/luci-theme-argon/root/www/luci-static/resources/menu-argon.js.o create mode 100644 ipk-source/ucode-mod-lua_aarch64_cortex-a53/CONTROL/control create mode 100755 ipk-source/ucode-mod-lua_aarch64_cortex-a53/CONTROL/postinst create mode 100755 ipk-source/ucode-mod-lua_aarch64_cortex-a53/CONTROL/prerm create mode 100755 ipk-source/ucode-mod-lua_aarch64_cortex-a53/build-ipk create mode 100755 ipk-source/ucode-mod-lua_aarch64_cortex-a53/root/usr/lib/ucode/lua.so diff --git a/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/control b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/control new file mode 100644 index 0000000..a39e74e --- /dev/null +++ b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/control @@ -0,0 +1,14 @@ +Package: libucode20230711 +Version: 2024.07.22~b610860d-r3 +Depends: libc, libjson-c5 +Provides: libucode +Source: feeds/base/package/utils/ucode +SourceName: ucode +License: ISC +Section: libs +SourceDateEpoch: 1729600843 +ABIVersion: 20230711 +Maintainer: Jo-Philipp Wich +Architecture: aarch64_cortex-a53 +Installed-Size: 204800 +Description: The libucode package provides the shared runtime library for the ucode interpreter. diff --git a/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/postinst b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/postinst new file mode 100755 index 0000000..3bba77c --- /dev/null +++ b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/postinst @@ -0,0 +1,5 @@ +#!/bin/sh +[ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0 +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_postinst $0 $@ diff --git a/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/prerm b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/prerm new file mode 100755 index 0000000..12d06ec --- /dev/null +++ b/ipk-source/libucode20230711_aarch64_cortex-a53/CONTROL/prerm @@ -0,0 +1,4 @@ +#!/bin/sh +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_prerm $0 $@ diff --git a/ipk-source/libucode20230711_aarch64_cortex-a53/build-ipk b/ipk-source/libucode20230711_aarch64_cortex-a53/build-ipk new file mode 100755 index 0000000..eb83cf6 --- /dev/null +++ b/ipk-source/libucode20230711_aarch64_cortex-a53/build-ipk @@ -0,0 +1,74 @@ +#!/bin/sh + +# Script for building OpenWRT .ipk packages using tar by iamromulan +# Works with SDXPPINN OpenWRT - iamromulan +# This script accepts an optional path to the directory containing the `CONTROL` and `root` directories. +# Usage: ./build-ipk.sh [path] +# If no path is provided, the script will look in the current directory for `CONTROL` and `root` directories. +# This will spit out an ipk in the current directory + +# Check if the script is run as root. If not, rerun with sudo. +if [ "$(id -u)" -ne 0 ]; then + echo "Script is not running as root. Re-executing with sudo..." + exec sudo "$0" "$@" +fi + +# Set the default build path to the current directory +build_path="." + +# Check if a path is provided as the first argument +if [ "$1" ]; then + build_path="$1" +fi + +# Check if the required directories are present in the specified path +if [ ! -d "${build_path}/CONTROL" ] || [ ! -d "${build_path}/root" ]; then + echo "Error: CONTROL and root directories must be present in the specified path (${build_path})." + exit 1 +fi + +# Extract values from the CONTROL/control file in the specified path +pkgname=$(grep -i '^Package:' "${build_path}/CONTROL/control" | awk '{print $2}') +version=$(grep -i '^Version:' "${build_path}/CONTROL/control" | awk '{print $2}') +architecture=$(grep -i '^Architecture:' "${build_path}/CONTROL/control" | awk '{print $2}') + +# Check if values are extracted correctly +if [ -z "$pkgname" ] || [ -z "$version" ] || [ -z "$architecture" ]; then + echo "Error: Failed to extract Package, Version, or Architecture from ${build_path}/CONTROL/control." + exit 1 +fi + +# Set the final IPK name based on the extracted values +ipkname="${pkgname}_${version}_${architecture}.ipk" + +# Ensure all CONTROL scripts are executable +echo "Setting permissions for CONTROL scripts..." +chmod +x "${build_path}/CONTROL"/* + +# Set ownership for CONTROL and root files +echo "Setting ownership for all package files..." +chown -R root:root "${build_path}/CONTROL"/* +chown -R root:root "${build_path}/root"/* + +# Create control.tar.gz from the CONTROL directory +echo "Creating control.tar.gz..." +tar -czvf control.tar.gz -C "${build_path}/CONTROL" . + +# Create data.tar.gz from the root directory +echo "Creating data.tar.gz..." +tar -czvf data.tar.gz -C "${build_path}/root" . + +# Create debian-binary file (must contain exactly "2.0" without a newline) +echo -n "2.0" > debian-binary +chown -R root:root debian-binary + +# Combine the components into the final .ipk file using tar +echo "Packaging ${ipkname}..." +tar -czvf "$ipkname" debian-binary control.tar.gz data.tar.gz + +# Clean up intermediate files +echo "Cleaning up temporary files..." +rm -f control.tar.gz data.tar.gz debian-binary + +echo "IPK package ${ipkname} created successfully using tar." + diff --git a/ipk-source/libucode20230711_aarch64_cortex-a53/root/usr/lib/libucode.so.20230711 b/ipk-source/libucode20230711_aarch64_cortex-a53/root/usr/lib/libucode.so.20230711 new file mode 100644 index 0000000000000000000000000000000000000000..f17cd38749c704bdcbfd8ff20d3fba7366a4074c GIT binary patch literal 197155 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 literal 0 HcmV?d00001 diff --git a/ipk-source/luci-app-argon-config/CONTROL/conffiles b/ipk-source/luci-app-argon-config/CONTROL/conffiles new file mode 100644 index 0000000..bc3a0e2 --- /dev/null +++ b/ipk-source/luci-app-argon-config/CONTROL/conffiles @@ -0,0 +1 @@ +/etc/config/argon diff --git a/ipk-source/luci-app-argon-config/CONTROL/control b/ipk-source/luci-app-argon-config/CONTROL/control new file mode 100644 index 0000000..15b607d --- /dev/null +++ b/ipk-source/luci-app-argon-config/CONTROL/control @@ -0,0 +1,11 @@ +Package: luci-app-argon-config +Version: 0.9 +Depends: libc, luci-compat +Source: /home/runner/work/gl-sdk-action/gl-sdk-action/buildsource/luci-app-argon-config +SourceName: luci-app-argon-config +Section: luci +SourceDateEpoch: 1650782942 +Maintainer: OpenWrt LuCI community +Architecture: all +Installed-Size: 3586 +Description: LuCI page for Argon Config diff --git a/ipk-source/luci-app-argon-config/CONTROL/postinst b/ipk-source/luci-app-argon-config/CONTROL/postinst new file mode 100755 index 0000000..3bba77c --- /dev/null +++ b/ipk-source/luci-app-argon-config/CONTROL/postinst @@ -0,0 +1,5 @@ +#!/bin/sh +[ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0 +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_postinst $0 $@ diff --git a/ipk-source/luci-app-argon-config/CONTROL/postinst-pkg b/ipk-source/luci-app-argon-config/CONTROL/postinst-pkg new file mode 100755 index 0000000..ecfe266 --- /dev/null +++ b/ipk-source/luci-app-argon-config/CONTROL/postinst-pkg @@ -0,0 +1,7 @@ +[ -n "${IPKG_INSTROOT}" ] || { + (. /etc/uci-defaults/luci-argon-config) && rm -f /etc/uci-defaults/luci-argon-config + rm -f /tmp/luci-indexcache + rm -rf /tmp/luci-modulecache/ + killall -HUP rpcd 2>/dev/null + exit 0 +} diff --git a/ipk-source/luci-app-argon-config/CONTROL/prerm b/ipk-source/luci-app-argon-config/CONTROL/prerm new file mode 100755 index 0000000..12d06ec --- /dev/null +++ b/ipk-source/luci-app-argon-config/CONTROL/prerm @@ -0,0 +1,4 @@ +#!/bin/sh +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_prerm $0 $@ diff --git a/ipk-source/luci-app-argon-config/build-ipk b/ipk-source/luci-app-argon-config/build-ipk new file mode 100755 index 0000000..eb83cf6 --- /dev/null +++ b/ipk-source/luci-app-argon-config/build-ipk @@ -0,0 +1,74 @@ +#!/bin/sh + +# Script for building OpenWRT .ipk packages using tar by iamromulan +# Works with SDXPPINN OpenWRT - iamromulan +# This script accepts an optional path to the directory containing the `CONTROL` and `root` directories. +# Usage: ./build-ipk.sh [path] +# If no path is provided, the script will look in the current directory for `CONTROL` and `root` directories. +# This will spit out an ipk in the current directory + +# Check if the script is run as root. If not, rerun with sudo. +if [ "$(id -u)" -ne 0 ]; then + echo "Script is not running as root. Re-executing with sudo..." + exec sudo "$0" "$@" +fi + +# Set the default build path to the current directory +build_path="." + +# Check if a path is provided as the first argument +if [ "$1" ]; then + build_path="$1" +fi + +# Check if the required directories are present in the specified path +if [ ! -d "${build_path}/CONTROL" ] || [ ! -d "${build_path}/root" ]; then + echo "Error: CONTROL and root directories must be present in the specified path (${build_path})." + exit 1 +fi + +# Extract values from the CONTROL/control file in the specified path +pkgname=$(grep -i '^Package:' "${build_path}/CONTROL/control" | awk '{print $2}') +version=$(grep -i '^Version:' "${build_path}/CONTROL/control" | awk '{print $2}') +architecture=$(grep -i '^Architecture:' "${build_path}/CONTROL/control" | awk '{print $2}') + +# Check if values are extracted correctly +if [ -z "$pkgname" ] || [ -z "$version" ] || [ -z "$architecture" ]; then + echo "Error: Failed to extract Package, Version, or Architecture from ${build_path}/CONTROL/control." + exit 1 +fi + +# Set the final IPK name based on the extracted values +ipkname="${pkgname}_${version}_${architecture}.ipk" + +# Ensure all CONTROL scripts are executable +echo "Setting permissions for CONTROL scripts..." +chmod +x "${build_path}/CONTROL"/* + +# Set ownership for CONTROL and root files +echo "Setting ownership for all package files..." +chown -R root:root "${build_path}/CONTROL"/* +chown -R root:root "${build_path}/root"/* + +# Create control.tar.gz from the CONTROL directory +echo "Creating control.tar.gz..." +tar -czvf control.tar.gz -C "${build_path}/CONTROL" . + +# Create data.tar.gz from the root directory +echo "Creating data.tar.gz..." +tar -czvf data.tar.gz -C "${build_path}/root" . + +# Create debian-binary file (must contain exactly "2.0" without a newline) +echo -n "2.0" > debian-binary +chown -R root:root debian-binary + +# Combine the components into the final .ipk file using tar +echo "Packaging ${ipkname}..." +tar -czvf "$ipkname" debian-binary control.tar.gz data.tar.gz + +# Clean up intermediate files +echo "Cleaning up temporary files..." +rm -f control.tar.gz data.tar.gz debian-binary + +echo "IPK package ${ipkname} created successfully using tar." + diff --git a/ipk-source/luci-app-argon-config/root/etc/config/argon b/ipk-source/luci-app-argon-config/root/etc/config/argon new file mode 100644 index 0000000..fb7f35d --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/etc/config/argon @@ -0,0 +1,9 @@ +config global + option primary '#5e72e4' + option dark_primary '#483d8b' + option blur '10' + option blur_dark '10' + option transparency '0.5' + option transparency_dark '0.5' + option mode 'normal' + option bing_background '0' diff --git a/ipk-source/luci-app-argon-config/root/etc/uci-defaults/luci-argon-config b/ipk-source/luci-app-argon-config/root/etc/uci-defaults/luci-argon-config new file mode 100755 index 0000000..935d7c8 --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/etc/uci-defaults/luci-argon-config @@ -0,0 +1,6 @@ +#!/bin/sh + +sed -i 's/cbi.submit\"] = true/cbi.submit\"] = \"1\"/g' /usr/lib/lua/luci/dispatcher.lua + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/controller/argon-config.lua b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/controller/argon-config.lua new file mode 100644 index 0000000..5d7faf4 --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/controller/argon-config.lua @@ -0,0 +1,10 @@ +module("luci.controller.argon-config", package.seeall) + +function index() + if not nixio.fs.access('/www/luci-static/argon/css/cascade.css') then + return + end + + local page = entry({"admin", "system", "argon-config"}, form("argon-config"), _("Argon Config"), 90) + page.acl_depends = { "luci-app-argon-config" } +end diff --git a/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/model/cbi/argon-config.lua b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/model/cbi/argon-config.lua new file mode 100644 index 0000000..19e9aee --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/model/cbi/argon-config.lua @@ -0,0 +1,217 @@ +local nxfs = require 'nixio.fs' +local wa = require 'luci.tools.webadmin' +local opkg = require 'luci.model.ipkg' +local sys = require 'luci.sys' +local http = require 'luci.http' +local nutil = require 'nixio.util' +local name = 'argon' +local uci = require 'luci.model.uci'.cursor() + +local fstat = nxfs.statvfs(opkg.overlay_root()) +local space_total = fstat and fstat.blocks or 0 +local space_free = fstat and fstat.bfree or 0 +local space_used = space_total - space_free + +local free_byte = space_free * fstat.frsize + +local primary, dark_primary, blur_radius, blur_radius_dark, blur_opacity, mode +if nxfs.access('/etc/config/argon') then + primary = uci:get_first('argon', 'global', 'primary') + dark_primary = uci:get_first('argon', 'global', 'dark_primary') + blur_radius = uci:get_first('argon', 'global', 'blur') + blur_radius_dark = uci:get_first('argon', 'global', 'blur_dark') + blur_opacity = uci:get_first('argon', 'global', 'transparency') + blur_opacity_dark = uci:get_first('argon', 'global', 'transparency_dark') + mode = uci:get_first('argon', 'global', 'mode') + bing_background = uci:get_first('argon', 'global', 'bing_background') +end + +function glob(...) + local iter, code, msg = nxfs.glob(...) + if iter then + return nutil.consume(iter) + else + return nil, code, msg + end +end + +local transparency_sets = { + 0, + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.9, + 1 +} + +-- [[ 模糊设置 ]]-- +br = SimpleForm('config', translate('Argon Config'), translate('Here you can set the blur and transparency of the login page of argon theme, and manage the background pictures and videos.[Chrome is recommended]')) +br.reset = false +br.submit = false +s = br:section(SimpleSection) + +o = s:option(ListValue, 'bing_background', translate('Wallpaper Source')) +o:value('0', translate('Built-in')) +o:value('1', translate('Bing Wallpapers')) +o.default = bing_background +o.rmempty = false + +o = s:option(ListValue, 'mode', translate('Theme mode')) +o:value('normal', translate('Follow System')) +o:value('light', translate('Force Light')) +o:value('dark', translate('Force Dark')) +o.default = mode +o.rmempty = false +o.description = translate('You can choose Theme color mode here') + +o = s:option(Value, 'primary', translate('[Light mode] Primary Color'), translate('A HEX Color ; ( Default: #5e72e4 )')) +o.default = primary +o.datatype = ufloat +o.rmempty = false + + + +o = s:option(ListValue, 'transparency', translate('[Light mode] Transparency'), translate('0 transparent - 1 opaque ; ( Suggest: transparent: 0 or translucent preset: 0.5 )')) +for _, v in ipairs(transparency_sets) do + o:value(v) +end +o.default = blur_opacity +o.datatype = ufloat +o.rmempty = false + +o = s:option(Value, 'blur', translate('[Light mode] Frosted Glass Radius'), translate('Larger value will more blurred ; ( Suggest: clear: 1 or blur preset: 10 )')) +o.default = blur_radius +o.datatype = ufloat +o.rmempty = false + +o = s:option(Value, 'dark_primary', translate('[Dark mode] Primary Color'), translate('A HEX Color ; ( Default: #483d8b )')) +o.default = dark_primary +o.datatype = ufloat +o.rmempty = false + +o = s:option(ListValue, 'transparency_dark', translate('[Dark mode] Transparency'), translate('0 transparent - 1 opaque ; ( Suggest: Black translucent preset: 0.5 )')) +for _, v in ipairs(transparency_sets) do + o:value(v) +end +o.default = blur_opacity_dark +o.datatype = ufloat +o.rmempty = false + +o = s:option(Value, 'blur_dark', translate('[Dark mode] Frosted Glass Radius'), translate('Larger value will more blurred ; ( Suggest: clear: 1 or blur preset: 10 )')) +o.default = blur_radius_dark +o.datatype = ufloat +o.rmempty = false + +o = s:option(Button, 'save', translate('Save Changes')) +o.inputstyle = 'reload' + +function br.handle(self, state, data) + if (state == FORM_VALID and data.blur ~= nil and data.blur_dark ~= nil and data.transparency ~= nil and data.transparency_dark ~= nil and data.mode ~= nil) then + nxfs.writefile('/tmp/aaa', data) + for key, value in pairs(data) do + uci:set('argon','@global[0]',key,value) + end + uci:commit('argon') + end + return true +end + +ful = SimpleForm('upload', translate('Upload (Free: ') .. wa.byte_format(free_byte) .. ')', translate("You can upload files such as jpg,png,gif,mp4,webm files, To change the login page background.")) +ful.reset = false +ful.submit = false + +sul = ful:section(SimpleSection, '', translate("Upload file to '/www/luci-static/argon/background/'")) +fu = sul:option(FileUpload, '') +fu.template = 'argon-config/other_upload' +um = sul:option(DummyValue, '', nil) +um.template = 'argon-config/other_dvalue' + +local dir, fd +dir = '/www/luci-static/argon/background/' +nxfs.mkdir(dir) +http.setfilehandler( + function(meta, chunk, eof) + if not fd then + if not meta then + return + end + + if meta and chunk then + fd = nixio.open(dir .. meta.file, 'w') + end + + if not fd then + um.value = translate('Create upload file error.') + return + end + end + if chunk and fd then + fd:write(chunk) + end + if eof and fd then + fd:close() + fd = nil + um.value = translate('File saved to') .. ' "/www/luci-static/argon/background/' .. meta.file .. '"' + end + end +) + +if http.formvalue('upload') then + local f = http.formvalue('ulfile') + if #f <= 0 then + um.value = translate('No specify upload file.') + end +end + +local function getSizeStr(size) + local i = 0 + local byteUnits = {' kB', ' MB', ' GB', ' TB'} + repeat + size = size / 1024 + i = i + 1 + until (size <= 1024) + return string.format('%.1f', size) .. byteUnits[i] +end + +local inits, attr = {} +for i, f in ipairs(glob(dir .. '*')) do + attr = nxfs.stat(f) + if attr then + inits[i] = {} + inits[i].name = nxfs.basename(f) + inits[i].mtime = os.date('%Y-%m-%d %H:%M:%S', attr.mtime) + inits[i].modestr = attr.modestr + inits[i].size = getSizeStr(attr.size) + inits[i].remove = 0 + inits[i].install = false + end +end + +form = SimpleForm('filelist', translate('Background file list'), nil) +form.reset = false +form.submit = false + +tb = form:section(Table, inits) +nm = tb:option(DummyValue, 'name', translate('File name')) +mt = tb:option(DummyValue, 'mtime', translate('Modify time')) +sz = tb:option(DummyValue, 'size', translate('Size')) +btnrm = tb:option(Button, 'remove', translate('Remove')) +btnrm.render = function(self, section, scope) + self.inputstyle = 'remove' + Button.render(self, section, scope) +end + +btnrm.write = function(self, section) + local v = nxfs.unlink(dir .. nxfs.basename(inits[section].name)) + if v then + table.remove(inits, section) + end + return v +end + +return br, ful, form diff --git a/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_button.htm b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_button.htm new file mode 100644 index 0000000..1c391ad --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " style="display: <%= display %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> diff --git a/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_dvalue.htm b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_dvalue.htm new file mode 100644 index 0000000..296c61e --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_dvalue.htm @@ -0,0 +1,8 @@ +<%+cbi/valueheader%> + +<% + local val = self:cfgvalue(section) or self.default or "" + write(pcdata(val)) +%> + +<%+cbi/valuefooter%> diff --git a/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_upload.htm b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_upload.htm new file mode 100644 index 0000000..63a9b4f --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/lib/lua/luci/view/argon-config/other_upload.htm @@ -0,0 +1,5 @@ +<%+cbi/valueheader%> + + + +<%+cbi/valuefooter%> diff --git a/ipk-source/luci-app-argon-config/root/usr/share/rpcd/acl.d/luci-app-argon-config.json b/ipk-source/luci-app-argon-config/root/usr/share/rpcd/acl.d/luci-app-argon-config.json new file mode 100644 index 0000000..f0a3137 --- /dev/null +++ b/ipk-source/luci-app-argon-config/root/usr/share/rpcd/acl.d/luci-app-argon-config.json @@ -0,0 +1,11 @@ +{ + "luci-app-argon-config": { + "description": "Grant UCI access for luci-app-argon-config", + "read": { + "uci": [ "argon" ] + }, + "write": { + "uci": [ "argon" ] + } + } +} diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/control b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/control new file mode 100644 index 0000000..04e40ab --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/control @@ -0,0 +1,13 @@ +Package: luci-lua-runtime +Version: 25.034.70690~7b0663a +Depends: libc, luci-base, lua, luci-lib-base, luci-lib-nixio, luci-lib-ip, luci-lib-jsonc, libubus-lua, liblucihttp-lua, ucode-mod-lua +Source: feeds/luci/modules/luci-lua-runtime +SourceName: luci-lua-runtime +License: Apache-2.0 +Section: luci +SourceDateEpoch: 1738611490 +URL: https://github.com/openwrt/luci +Maintainer: OpenWrt LuCI community +Architecture: aarch64_cortex-a53 +Installed-Size: 153600 +Description: LuCI Lua runtime libraries diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst new file mode 100755 index 0000000..3bba77c --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst @@ -0,0 +1,5 @@ +#!/bin/sh +[ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0 +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_postinst $0 $@ diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst-pkg b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst-pkg new file mode 100755 index 0000000..2e52d45 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/postinst-pkg @@ -0,0 +1,5 @@ +[ -n "${IPKG_INSTROOT}" ] || { rm -f /tmp/luci-indexcache.* + rm -rf /tmp/luci-modulecache/ + killall -HUP rpcd 2>/dev/null + exit 0 +} diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/prerm b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/prerm new file mode 100755 index 0000000..12d06ec --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/CONTROL/prerm @@ -0,0 +1,4 @@ +#!/bin/sh +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_prerm $0 $@ diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/build-ipk b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/build-ipk new file mode 100755 index 0000000..eb83cf6 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/build-ipk @@ -0,0 +1,74 @@ +#!/bin/sh + +# Script for building OpenWRT .ipk packages using tar by iamromulan +# Works with SDXPPINN OpenWRT - iamromulan +# This script accepts an optional path to the directory containing the `CONTROL` and `root` directories. +# Usage: ./build-ipk.sh [path] +# If no path is provided, the script will look in the current directory for `CONTROL` and `root` directories. +# This will spit out an ipk in the current directory + +# Check if the script is run as root. If not, rerun with sudo. +if [ "$(id -u)" -ne 0 ]; then + echo "Script is not running as root. Re-executing with sudo..." + exec sudo "$0" "$@" +fi + +# Set the default build path to the current directory +build_path="." + +# Check if a path is provided as the first argument +if [ "$1" ]; then + build_path="$1" +fi + +# Check if the required directories are present in the specified path +if [ ! -d "${build_path}/CONTROL" ] || [ ! -d "${build_path}/root" ]; then + echo "Error: CONTROL and root directories must be present in the specified path (${build_path})." + exit 1 +fi + +# Extract values from the CONTROL/control file in the specified path +pkgname=$(grep -i '^Package:' "${build_path}/CONTROL/control" | awk '{print $2}') +version=$(grep -i '^Version:' "${build_path}/CONTROL/control" | awk '{print $2}') +architecture=$(grep -i '^Architecture:' "${build_path}/CONTROL/control" | awk '{print $2}') + +# Check if values are extracted correctly +if [ -z "$pkgname" ] || [ -z "$version" ] || [ -z "$architecture" ]; then + echo "Error: Failed to extract Package, Version, or Architecture from ${build_path}/CONTROL/control." + exit 1 +fi + +# Set the final IPK name based on the extracted values +ipkname="${pkgname}_${version}_${architecture}.ipk" + +# Ensure all CONTROL scripts are executable +echo "Setting permissions for CONTROL scripts..." +chmod +x "${build_path}/CONTROL"/* + +# Set ownership for CONTROL and root files +echo "Setting ownership for all package files..." +chown -R root:root "${build_path}/CONTROL"/* +chown -R root:root "${build_path}/root"/* + +# Create control.tar.gz from the CONTROL directory +echo "Creating control.tar.gz..." +tar -czvf control.tar.gz -C "${build_path}/CONTROL" . + +# Create data.tar.gz from the root directory +echo "Creating data.tar.gz..." +tar -czvf data.tar.gz -C "${build_path}/root" . + +# Create debian-binary file (must contain exactly "2.0" without a newline) +echo -n "2.0" > debian-binary +chown -R root:root debian-binary + +# Combine the components into the final .ipk file using tar +echo "Packaging ${ipkname}..." +tar -czvf "$ipkname" debian-binary control.tar.gz data.tar.gz + +# Clean up intermediate files +echo "Cleaning up temporary files..." +rm -f control.tar.gz data.tar.gz debian-binary + +echo "IPK package ${ipkname} created successfully using tar." + diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/cacheloader.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/cacheloader.lua new file mode 100644 index 0000000..7ef971d --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/cacheloader.lua @@ -0,0 +1,12 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2008 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local config = require "luci.config" +local ccache = require "luci.ccache" + +module "luci.cacheloader" + +if config.ccache and config.ccache.enable == "1" then + ccache.cache_ondemand() +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/ccache.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/ccache.lua new file mode 100644 index 0000000..d3be7cb --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/ccache.lua @@ -0,0 +1,76 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2008 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local io = require "io" +local fs = require "nixio.fs" +local util = require "luci.util" +local nixio = require "nixio" +local debug = require "debug" +local string = require "string" +local package = require "package" + +local type, loadfile = type, loadfile + + +module "luci.ccache" + +function cache_ondemand(...) + if debug.getinfo(1, 'S').source ~= "=?" then + cache_enable(...) + end +end + +function cache_enable(cachepath, mode) + cachepath = cachepath or "/tmp/luci-modulecache" + mode = mode or "r--r--r--" + + local loader = package.loaders[2] + local uid = nixio.getuid() + + if not fs.stat(cachepath) then + fs.mkdir(cachepath) + end + + local function _encode_filename(name) + local encoded = "" + for i=1, #name do + encoded = encoded .. ("%2X" % string.byte(name, i)) + end + return encoded + end + + local function _load_sane(file) + local stat = fs.stat(file) + if stat and stat.uid == uid and stat.modestr == mode then + return loadfile(file) + end + end + + local function _write_sane(file, func) + if nixio.getuid() == uid then + local fp = io.open(file, "w") + if fp then + fp:write(util.get_bytecode(func)) + fp:close() + fs.chmod(file, mode) + end + end + end + + package.loaders[2] = function(mod) + local encoded = cachepath .. "/" .. _encode_filename(mod) + local modcons = _load_sane(encoded) + + if modcons then + return modcons + end + + -- No cachefile + modcons = loader(mod) + if type(modcons) == "function" then + _write_sane(encoded, modcons) + end + return modcons + end +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/config.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/config.lua new file mode 100644 index 0000000..d01153f --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/config.lua @@ -0,0 +1,18 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local util = require "luci.util" +module("luci.config", + function(m) + if pcall(require, "luci.model.uci") then + local config = util.threadlocal() + setmetatable(m, { + __index = function(tbl, key) + if not config[key] then + config[key] = luci.model.uci.cursor():get_all("luci", key) + end + return config[key] + end + }) + end + end) diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/dispatcher.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/dispatcher.lua new file mode 100644 index 0000000..bbe7600 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/dispatcher.lua @@ -0,0 +1,484 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2008-2015 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.dispatcher", package.seeall) + +local http = _G.L.http + +context = setmetatable({}, { + __index = function(t, k) + if k == "request" or k == "requestpath" then + return _G.L.ctx.request_path + elseif k == "requestargs" then + return _G.L.ctx.request_args + else + return _G.L.ctx[k] + end + end +}) + +uci = require "luci.model.uci" +uci:set_session_id(_G.L.ctx.authsession) + +i18n = require "luci.i18n" +i18n.setlanguage(_G.L.dispatcher.lang) + +build_url = _G.L.dispatcher.build_url +menu_json = _G.L.dispatcher.menu_json +error404 = _G.L.dispatcher.error404 +error500 = _G.L.dispatcher.error500 + +function is_authenticated(auth) + local session = _G.L.dispatcher.is_authenticated(auth) + if session then + return session.sid, session.data, session.acls + end +end + +function assign(path, clone, title, order) + local obj = node(unpack(path)) + + obj.title = title + obj.order = order + + setmetatable(obj, {__index = node(unpack(clone))}) + + return obj +end + +function entry(path, target, title, order) + local c = node(unpack(path)) + + c.title = title + c.order = order + c.action = target + + return c +end + +-- enabling the node. +function get(...) + return node(...) +end + +function node(...) + local p = table.concat({ ... }, "/") + + if not __entries[p] then + __entries[p] = {} + end + + return __entries[p] +end + +function lookup(...) + local i, path = nil, {} + for i = 1, select('#', ...) do + local name, arg = nil, tostring(select(i, ...)) + for name in arg:gmatch("[^/]+") do + path[#path+1] = name + end + end + + local node = menu_json() + for i = 1, #path do + node = node.children[path[i]] + + if not node then + return nil + elseif node.leaf then + break + end + end + + return node, build_url(unpack(path)) +end + + +function process_lua_controller(path) + local base = "/usr/lib/lua/luci/controller/" + local modname = "luci.controller." .. path:sub(#base+1, #path-4):gsub("/", ".") + local mod = require(modname) + assert(mod ~= true, + "Invalid controller file found\n" .. + "The file '" .. path .. "' contains an invalid module line.\n" .. + "Please verify whether the module name is set to '" .. modname .. + "' - It must correspond to the file path!") + + local idx = mod.index + if type(idx) ~= "function" then + return nil + end + + local entries = {} + + __entries = entries + __controller = modname + + setfenv(idx, setmetatable({}, { __index = luci.dispatcher }))() + + __entries = nil + __controller = nil + + -- fixup gathered node specs + for path, entry in pairs(entries) do + if entry.leaf then + entry.wildcard = true + end + + if type(entry.file_depends) == "table" then + for _, v in ipairs(entry.file_depends) do + entry.depends = entry.depends or {} + entry.depends.fs = entry.depends.fs or {} + + local ft = fs.stat(v, "type") + if ft == "dir" then + entry.depends.fs[v] = "directory" + elseif v:match("/s?bin/") then + entry.depends.fs[v] = "executable" + else + entry.depends.fs[v] = "file" + end + end + end + + if type(entry.uci_depends) == "table" then + for k, v in pairs(entry.uci_depends) do + entry.depends = entry.depends or {} + entry.depends.uci = entry.depends.uci or {} + entry.depends.uci[k] = v + end + end + + if type(entry.acl_depends) == "table" then + for _, acl in ipairs(entry.acl_depends) do + entry.depends = entry.depends or {} + entry.depends.acl = entry.depends.acl or {} + entry.depends.acl[#entry.depends.acl + 1] = acl + end + end + + if (entry.sysauth_authenticator ~= nil) or + (entry.sysauth ~= nil and entry.sysauth ~= false) + then + if entry.sysauth_authenticator == "htmlauth" then + entry.auth = { + login = true, + methods = { "cookie:sysauth_https", "cookie:sysauth_http" } + } + elseif path == "rpc" and modname == "luci.controller.rpc" then + entry.auth = { + login = false, + methods = { "query:auth", "cookie:sysauth_https", "cookie:sysauth_http", "cookie:sysauth" } + } + elseif modname == "luci.controller.admin.uci" then + entry.auth = { + login = false, + methods = { "param:sid" } + } + end + elseif entry.sysauth == false then + entry.auth = {} + end + + if entry.action == nil and type(entry.target) == "table" then + entry.action = entry.target + entry.target = nil + end + + entry.leaf = nil + + entry.file_depends = nil + entry.uci_depends = nil + entry.acl_depends = nil + + entry.sysauth = nil + entry.sysauth_authenticator = nil + end + + return entries +end + +function invoke_cbi_action(model, config, ...) + local cbi = require "luci.cbi" + local tpl = require "luci.template" + local util = require "luci.util" + + if not config then + config = {} + end + + local maps = cbi.load(model, ...) + + local state = nil + + local function has_uci_access(config, level) + local rv = util.ubus("session", "access", { + ubus_rpc_session = context.authsession, + scope = "uci", object = config, + ["function"] = level + }) + + return (type(rv) == "table" and rv.access == true) or false + end + + local i, res + for i, res in ipairs(maps) do + if util.instanceof(res, cbi.SimpleForm) then + io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n" + % model) + + io.stderr:write("please change %s to use the form() action instead.\n" + % table.concat(context.request, "/")) + end + + res.flow = config + local cstate = res:parse() + if cstate and (not state or cstate < state) then + state = cstate + end + end + + local function _resolve_path(path) + return type(path) == "table" and build_url(unpack(path)) or path + end + + if config.on_valid_to and state and state > 0 and state < 2 then + http:redirect(_resolve_path(config.on_valid_to)) + return + end + + if config.on_changed_to and state and state > 1 then + http:redirect(_resolve_path(config.on_changed_to)) + return + end + + if config.on_success_to and state and state > 0 then + http:redirect(_resolve_path(config.on_success_to)) + return + end + + if config.state_handler then + if not config.state_handler(state, maps) then + return + end + end + + http:header("X-CBI-State", state or 0) + + if not config.noheader then + _G.L.include("cbi/header", {state = state}) + end + + local redirect + local messages + local applymap = false + local pageaction = true + local parsechain = { } + local writable = false + + for i, res in ipairs(maps) do + if res.apply_needed and res.parsechain then + local c + for _, c in ipairs(res.parsechain) do + parsechain[#parsechain+1] = c + end + applymap = true + end + + if res.redirect then + redirect = redirect or res.redirect + end + + if res.pageaction == false then + pageaction = false + end + + if res.message then + messages = messages or { } + messages[#messages+1] = res.message + end + end + + for i, res in ipairs(maps) do + local is_readable_map = has_uci_access(res.config, "read") + local is_writable_map = has_uci_access(res.config, "write") + + writable = writable or is_writable_map + + res:render({ + firstmap = (i == 1), + redirect = redirect, + messages = messages, + pageaction = pageaction, + parsechain = parsechain, + readable = is_readable_map, + writable = is_writable_map + }) + end + + if not config.nofooter then + _G.L.include("cbi/footer", { + flow = config, + pageaction = pageaction, + redirect = redirect, + state = state, + autoapply = config.autoapply, + trigger_apply = applymap, + writable = writable + }) + end +end + +function invoke_form_action(model, ...) + local cbi = require "luci.cbi" + local tpl = require "luci.template" + + local maps = luci.cbi.load(model, ...) + local state = nil + + local i, res + for i, res in ipairs(maps) do + local cstate = res:parse() + if cstate and (not state or cstate < state) then + state = cstate + end + end + + http:header("X-CBI-State", state or 0) + _G.L.include("header") + for i, res in ipairs(maps) do + res:render() + end + _G.L.include("footer") +end + +function render_lua_template(path) + local tpl = require "luci.template" + + tpl.render(path, getfenv(1)) +end + +function test_post_security() + if http:getenv("REQUEST_METHOD") ~= "POST" then + http:status(405, "Method Not Allowed") + http:header("Allow", "POST") + return false + end + + if http:formvalue("token") ~= context.authtoken then + http:status(403, "Forbidden") + _G.L.include("csrftoken") + return false + end + + return true +end + + +function call(name, ...) + return { + ["type"] = "call", + ["module"] = __controller, + ["function"] = name, + ["parameters"] = select('#', ...) > 0 and {...} or nil + } +end + +function post_on(params, name, ...) + return { + ["type"] = "call", + ["module"] = __controller, + ["function"] = name, + ["parameters"] = select('#', ...) > 0 and {...} or nil, + ["post"] = params + } +end + +function post(...) + return post_on(true, ...) +end + +function view(name) + return { + ["type"] = "view", + ["path"] = name + } +end + +function template(name) + return { + ["type"] = "template", + ["path"] = name + } +end + +function cbi(model, config) + return { + ["type"] = "call", + ["module"] = "luci.dispatcher", + ["function"] = "invoke_cbi_action", + ["parameters"] = { model, config or {} }, + ["post"] = { + ["cbi.submit"] = true + } + } +end + +function form(model) + return { + ["type"] = "call", + ["module"] = "luci.dispatcher", + ["function"] = "invoke_form_action", + ["parameters"] = { model }, + ["post"] = { + ["cbi.submit"] = true + } + } +end + +function firstchild() + return { + ["type"] = "firstchild" + } +end + +function firstnode() + return { + ["type"] = "firstchild", + ["recurse"] = true + } +end + +function arcombine(trg1, trg2) + return { + ["type"] = "arcombine", + ["targets"] = { trg1, trg2 } --, + --env = getfenv(), + } +end + +function alias(...) + return { + ["type"] = "alias", + ["path"] = table.concat({ ... }, "/") + } +end + +function rewrite(n, ...) + return { + ["type"] = "rewrite", + ["path"] = table.concat({ ... }, "/"), + ["remove"] = n + } +end + + +translate = i18n.translate + +-- This function does not actually translate the given argument but +-- is used by build/i18n-scan.pl to find translatable entries. +function _(text) + return text +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/i18n.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/i18n.lua new file mode 100644 index 0000000..323912b --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/i18n.lua @@ -0,0 +1,55 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local tparser = require "luci.template.parser" +local util = require "luci.util" +local tostring = tostring + +module "luci.i18n" + +i18ndir = util.libpath() .. "/i18n/" +context = util.threadlocal() +default = "en" + + +function setlanguage(lang) + local code, subcode = lang:match("^([A-Za-z][A-Za-z])[%-_]([A-Za-z][A-Za-z])$") + if not (code and subcode) then + subcode = lang:match("^([A-Za-z][A-Za-z])$") + if not subcode then + return nil + end + end + + context.parent = code and code:lower() + context.lang = context.parent and context.parent.."-"..subcode:lower() or subcode:lower() + + if tparser.load_catalog(context.lang, i18ndir) and + tparser.change_catalog(context.lang) + then + return context.lang + + elseif context.parent then + if tparser.load_catalog(context.parent, i18ndir) and + tparser.change_catalog(context.parent) + then + return context.parent + end + end + + return nil +end + +function translate(key) + return tparser.translate(key) or key +end + +function translatef(key, ...) + return tostring(translate(key)):format(...) +end + +function dump() + local rv = {} + tparser.get_translations(function(k, v) rv[k] = v end) + return rv +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/model/uci.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/model/uci.lua new file mode 100644 index 0000000..816f6f2 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/model/uci.lua @@ -0,0 +1,508 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local os = require "os" +local util = require "luci.util" +local table = require "table" + + +local setmetatable, rawget, rawset = setmetatable, rawget, rawset +local require, getmetatable, assert = require, getmetatable, assert +local error, pairs, ipairs, select = error, pairs, ipairs, select +local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack + +-- The typical workflow for UCI is: Get a cursor instance from the +-- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.), +-- save the changes to the staging area via Cursor.save and finally +-- Cursor.commit the data to the actual config files. +-- LuCI then needs to Cursor.apply the changes so daemons etc. are +-- reloaded. +module "luci.model.uci" + +local ERRSTR = { + "Invalid command", + "Invalid argument", + "Method not found", + "Entry not found", + "No data", + "Permission denied", + "Timeout", + "Not supported", + "Unknown error", + "Connection failed" +} + +local session_id = nil + +local function call(cmd, args) + if type(args) == "table" and session_id then + args.ubus_rpc_session = session_id + end + return util.ubus("uci", cmd, args) +end + + +function cursor() + return _M +end + +function cursor_state() + return _M +end + +function substate(self) + return self +end + + +function get_confdir(self) + return "/etc/config" +end + +function get_savedir(self) + return "/tmp/.uci" +end + +function get_session_id(self) + return session_id +end + +function set_confdir(self, directory) + return false +end + +function set_savedir(self, directory) + return false +end + +function set_session_id(self, id) + session_id = id + return true +end + + +function load(self, config) + return true +end + +function save(self, config) + return true +end + +function unload(self, config) + return true +end + + +function changes(self, config) + local rv, err = call("changes", { config = config }) + + if type(rv) == "table" and type(rv.changes) == "table" then + return rv.changes + elseif err then + return nil, ERRSTR[err] + else + return { } + end +end + + +function revert(self, config) + local _, err = call("revert", { config = config }) + return (err == nil), ERRSTR[err] +end + +function commit(self, config) + local _, err = call("commit", { config = config }) + return (err == nil), ERRSTR[err] +end + +function apply(self, rollback) + local _, err + + if rollback then + local sys = require "luci.sys" + local conf = require "luci.config" + local timeout = tonumber(conf and conf.apply and conf.apply.rollback or 90) or 0 + + _, err = call("apply", { + timeout = (timeout > 90) and timeout or 90, + rollback = true + }) + + if not err then + local now = os.time() + local token = sys.uniqueid(16) + + util.ubus("session", "set", { + ubus_rpc_session = "00000000000000000000000000000000", + values = { + rollback = { + token = token, + session = session_id, + timeout = now + timeout + } + } + }) + + return token + end + else + _, err = call("changes", {}) + + if not err then + if type(_) == "table" and type(_.changes) == "table" then + local k, v + for k, v in pairs(_.changes) do + _, err = call("commit", { config = k }) + if err then + break + end + end + end + end + + if not err then + _, err = call("apply", { rollback = false }) + end + end + + return (err == nil), ERRSTR[err] +end + +function confirm(self, token) + local is_pending, time_remaining, rollback_sid, rollback_token = self:rollback_pending() + + if is_pending then + if token ~= rollback_token then + return false, "Permission denied" + end + + local _, err = util.ubus("uci", "confirm", { + ubus_rpc_session = rollback_sid + }) + + if not err then + util.ubus("session", "set", { + ubus_rpc_session = "00000000000000000000000000000000", + values = { rollback = {} } + }) + end + + return (err == nil), ERRSTR[err] + end + + return false, "No data" +end + +function rollback(self) + local is_pending, time_remaining, rollback_sid = self:rollback_pending() + + if is_pending then + local _, err = util.ubus("uci", "rollback", { + ubus_rpc_session = rollback_sid + }) + + if not err then + util.ubus("session", "set", { + ubus_rpc_session = "00000000000000000000000000000000", + values = { rollback = {} } + }) + end + + return (err == nil), ERRSTR[err] + end + + return false, "No data" +end + +function rollback_pending(self) + local rv, err = util.ubus("session", "get", { + ubus_rpc_session = "00000000000000000000000000000000", + keys = { "rollback" } + }) + + local now = os.time() + + if type(rv) == "table" and + type(rv.values) == "table" and + type(rv.values.rollback) == "table" and + type(rv.values.rollback.token) == "string" and + type(rv.values.rollback.session) == "string" and + type(rv.values.rollback.timeout) == "number" and + rv.values.rollback.timeout > now + then + return true, + rv.values.rollback.timeout - now, + rv.values.rollback.session, + rv.values.rollback.token + end + + return false, ERRSTR[err] +end + + +function foreach(self, config, stype, callback) + if type(callback) == "function" then + local rv, err = call("get", { + config = config, + type = stype + }) + + if type(rv) == "table" and type(rv.values) == "table" then + local sections = { } + local res = false + local index = 1 + + local _, section + for _, section in pairs(rv.values) do + section[".index"] = section[".index"] or index + sections[index] = section + index = index + 1 + end + + table.sort(sections, function(a, b) + return a[".index"] < b[".index"] + end) + + for _, section in ipairs(sections) do + local continue = callback(section) + res = true + if continue == false then + break + end + end + return res + else + return false, ERRSTR[err] or "No data" + end + else + return false, "Invalid argument" + end +end + +local function _get(self, operation, config, section, option) + if section == nil then + return nil + elseif type(option) == "string" and option:byte(1) ~= 46 then + local rv, err = call(operation, { + config = config, + section = section, + option = option + }) + + if type(rv) == "table" then + return rv.value or nil + elseif err then + return false, ERRSTR[err] + else + return nil + end + elseif option == nil then + local values = self:get_all(config, section) + if values then + return values[".type"], values[".name"] + else + return nil + end + else + return false, "Invalid argument" + end +end + +function get(self, ...) + return _get(self, "get", ...) +end + +function get_state(self, ...) + return _get(self, "state", ...) +end + +function get_all(self, config, section) + local rv, err = call("get", { + config = config, + section = section + }) + + if type(rv) == "table" and type(rv.values) == "table" then + return rv.values + elseif err then + return false, ERRSTR[err] + else + return nil + end +end + +function get_bool(self, ...) + local val = self:get(...) + return (val == "1" or val == "true" or val == "yes" or val == "on") +end + +function get_first(self, config, stype, option, default) + local rv = default + + self:foreach(config, stype, function(s) + local val = not option and s[".name"] or s[option] + + if type(default) == "number" then + val = tonumber(val) + elseif type(default) == "boolean" then + val = (val == "1" or val == "true" or + val == "yes" or val == "on") + end + + if val ~= nil then + rv = val + return false + end + end) + + return rv +end + +function get_list(self, config, section, option) + if config and section and option then + local val = self:get(config, section, option) + return (type(val) == "table" and val or { val }) + end + return { } +end + + +function section(self, config, stype, name, values) + local rv, err = call("add", { + config = config, + type = stype, + name = name, + values = values + }) + + if type(rv) == "table" then + return rv.section + elseif err then + return false, ERRSTR[err] + else + return nil + end +end + + +function add(self, config, stype) + return self:section(config, stype) +end + +function set(self, config, section, option, ...) + if select('#', ...) == 0 then + local sname, err = self:section(config, option, section) + return (not not sname), err + else + local _, err = call("set", { + config = config, + section = section, + values = { [option] = select(1, ...) } + }) + return (err == nil), ERRSTR[err] + end +end + +function set_list(self, config, section, option, value) + if section == nil or option == nil then + return false + elseif value == nil or (type(value) == "table" and #value == 0) then + return self:delete(config, section, option) + elseif type(value) == "table" then + return self:set(config, section, option, value) + else + return self:set(config, section, option, { value }) + end +end + +function tset(self, config, section, values) + local _, err = call("set", { + config = config, + section = section, + values = values + }) + return (err == nil), ERRSTR[err] +end + +function reorder(self, config, section, index) + local sections + + if type(section) == "string" and type(index) == "number" then + local pos = 0 + + sections = { } + + self:foreach(config, nil, function(s) + if pos == index then + pos = pos + 1 + end + + if s[".name"] ~= section then + pos = pos + 1 + sections[pos] = s[".name"] + else + sections[index + 1] = section + end + end) + elseif type(section) == "table" then + sections = section + else + return false, "Invalid argument" + end + + local _, err = call("order", { + config = config, + sections = sections + }) + + return (err == nil), ERRSTR[err] +end + + +function delete(self, config, section, option) + local _, err = call("delete", { + config = config, + section = section, + option = option + }) + return (err == nil), ERRSTR[err] +end + +function delete_all(self, config, stype, comparator) + local _, err + if type(comparator) == "table" then + _, err = call("delete", { + config = config, + type = stype, + match = comparator + }) + elseif type(comparator) == "function" then + local rv = call("get", { + config = config, + type = stype + }) + + if type(rv) == "table" and type(rv.values) == "table" then + local sname, section + for sname, section in pairs(rv.values) do + if comparator(section) then + _, err = call("delete", { + config = config, + section = sname + }) + end + end + end + elseif comparator == nil then + _, err = call("delete", { + config = config, + type = stype + }) + else + return false, "Invalid argument" + end + + return (err == nil), ERRSTR[err] +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/store.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/store.lua new file mode 100644 index 0000000..a735981 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/store.lua @@ -0,0 +1,6 @@ +-- Copyright 2009 Steven Barth +-- Copyright 2009 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local util = require "luci.util" +module("luci.store", util.threadlocal) diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys.lua new file mode 100644 index 0000000..e6eb762 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys.lua @@ -0,0 +1,615 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local io = require "io" +local os = require "os" +local table = require "table" +local nixio = require "nixio" +local fs = require "nixio.fs" +local uci = require "luci.model.uci" + +local luci = {} +luci.util = require "luci.util" +luci.ip = require "luci.ip" + +local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack = + tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack + + +module "luci.sys" + +function call(...) + return os.execute(...) / 256 +end + +exec = luci.util.exec + +-- containing the whole environment is returned otherwise this function returns +-- the corresponding string value for the given name or nil if no such variable +-- exists. +getenv = nixio.getenv + +function hostname(newname) + if type(newname) == "string" and #newname > 0 then + fs.writefile( "/proc/sys/kernel/hostname", newname ) + return newname + else + return nixio.uname().nodename + end +end + +function httpget(url, stream, target) + if not target then + local source = stream and io.popen or luci.util.exec + return source("wget -qO- %s" % luci.util.shellquote(url)) + else + return os.execute("wget -qO %s %s" % + {luci.util.shellquote(target), luci.util.shellquote(url)}) + end +end + +function reboot() + return os.execute("reboot >/dev/null 2>&1") +end + +function syslog() + return luci.util.exec("logread") +end + +function dmesg() + return luci.util.exec("dmesg") +end + +function uniqueid(bytes) + local rand = fs.readfile("/dev/urandom", bytes) + return rand and nixio.bin.hexlify(rand) +end + +function uptime() + return nixio.sysinfo().uptime +end + + +net = {} + +local function _nethints(what, callback) + local _, k, e, mac, ip, name, duid, iaid + local cur = uci.cursor() + local ifn = { } + local hosts = { } + local lookup = { } + + local function _add(i, ...) + local k = select(i, ...) + if k then + if not hosts[k] then hosts[k] = { } end + hosts[k][1] = select(1, ...) or hosts[k][1] + hosts[k][2] = select(2, ...) or hosts[k][2] + hosts[k][3] = select(3, ...) or hosts[k][3] + hosts[k][4] = select(4, ...) or hosts[k][4] + end + end + + luci.ip.neighbors(nil, function(neigh) + if neigh.mac and neigh.family == 4 then + _add(what, neigh.mac:string(), neigh.dest:string(), nil, nil) + elseif neigh.mac and neigh.family == 6 then + _add(what, neigh.mac:string(), nil, neigh.dest:string(), nil) + end + end) + + if fs.access("/etc/ethers") then + for e in io.lines("/etc/ethers") do + mac, name = e:match("^([a-fA-F0-9:-]+)%s+(%S+)") + mac = luci.ip.checkmac(mac) + if mac and name then + if luci.ip.checkip4(name) then + _add(what, mac, name, nil, nil) + else + _add(what, mac, nil, nil, name) + end + end + end + end + + cur:foreach("dhcp", "dnsmasq", + function(s) + if s.leasefile and fs.access(s.leasefile) then + for e in io.lines(s.leasefile) do + mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)") + mac = luci.ip.checkmac(mac) + if mac and ip then + _add(what, mac, ip, nil, name ~= "*" and name) + end + end + end + end + ) + + cur:foreach("dhcp", "odhcpd", + function(s) + if type(s.leasefile) == "string" and fs.access(s.leasefile) then + for e in io.lines(s.leasefile) do + duid, iaid, name, _, ip = e:match("^# %S+ (%S+) (%S+) (%S+) (-?%d+) %S+ %S+ ([0-9a-f:.]+)/[0-9]+") + mac = net.duid_to_mac(duid) + if mac then + if ip and iaid == "ipv4" then + _add(what, mac, ip, nil, name ~= "*" and name) + elseif ip then + _add(what, mac, nil, ip, name ~= "*" and name) + end + end + end + end + end + ) + + cur:foreach("dhcp", "host", + function(s) + for mac in luci.util.imatch(s.mac) do + mac = luci.ip.checkmac(mac) + if mac then + _add(what, mac, s.ip, nil, s.name) + end + end + end) + + for _, e in ipairs(nixio.getifaddrs()) do + if e.name ~= "lo" then + ifn[e.name] = ifn[e.name] or { } + if e.family == "packet" and e.addr and #e.addr == 17 then + ifn[e.name][1] = e.addr:upper() + elseif e.family == "inet" then + ifn[e.name][2] = e.addr + elseif e.family == "inet6" then + ifn[e.name][3] = e.addr + end + end + end + + for _, e in pairs(ifn) do + if e[what] and (e[2] or e[3]) then + _add(what, e[1], e[2], e[3], e[4]) + end + end + + for _, e in pairs(hosts) do + lookup[#lookup+1] = (what > 1) and e[what] or (e[2] or e[3]) + end + + if #lookup > 0 then + lookup = luci.util.ubus("network.rrdns", "lookup", { + addrs = lookup, + timeout = 250, + limit = 1000 + }) or { } + end + + for _, e in luci.util.kspairs(hosts) do + callback(e[1], e[2], e[3], lookup[e[2]] or lookup[e[3]] or e[4]) + end +end + +-- Each entry contains the values in the following order: +-- [ "mac", "name" ] +function net.mac_hints(callback) + if callback then + _nethints(1, function(mac, v4, v6, name) + name = name or v4 + if name and name ~= mac then + callback(mac, name or v4) + end + end) + else + local rv = { } + _nethints(1, function(mac, v4, v6, name) + name = name or v4 + if name and name ~= mac then + rv[#rv+1] = { mac, name or v4 } + end + end) + return rv + end +end + +-- Each entry contains the values in the following order: +-- [ "ip", "name" ] +function net.ipv4_hints(callback) + if callback then + _nethints(2, function(mac, v4, v6, name) + name = name or mac + if name and name ~= v4 then + callback(v4, name) + end + end) + else + local rv = { } + _nethints(2, function(mac, v4, v6, name) + name = name or mac + if name and name ~= v4 then + rv[#rv+1] = { v4, name } + end + end) + return rv + end +end + +-- Each entry contains the values in the following order: +-- [ "ip", "name" ] +function net.ipv6_hints(callback) + if callback then + _nethints(3, function(mac, v4, v6, name) + name = name or mac + if name and name ~= v6 then + callback(v6, name) + end + end) + else + local rv = { } + _nethints(3, function(mac, v4, v6, name) + name = name or mac + if name and name ~= v6 then + rv[#rv+1] = { v6, name } + end + end) + return rv + end +end + +function net.host_hints(callback) + if callback then + _nethints(1, function(mac, v4, v6, name) + if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then + callback(mac, v4, v6, name) + end + end) + else + local rv = { } + _nethints(1, function(mac, v4, v6, name) + if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then + local e = { } + if v4 then e.ipv4 = v4 end + if v6 then e.ipv6 = v6 end + if name then e.name = name end + rv[mac] = e + end + end) + return rv + end +end + +function net.conntrack(callback) + local ok, nfct = pcall(io.lines, "/proc/net/nf_conntrack") + if not ok or not nfct then + return nil + end + + local line, connt = nil, (not callback) and { } + for line in nfct do + local fam, l3, l4, rest = + line:match("^(ipv[46]) +(%d+) +%S+ +(%d+) +(.+)$") + + local timeout, tuples = rest:match("^(%d+) +(.+)$") + + if not tuples then + tuples = rest + end + + if fam and l3 and l4 and not tuples:match("^TIME_WAIT ") then + l4 = nixio.getprotobynumber(l4) + + local entry = { + bytes = 0, + packets = 0, + layer3 = fam, + layer4 = l4 and l4.name or "unknown", + timeout = tonumber(timeout, 10) + } + + local key, val + for key, val in tuples:gmatch("(%w+)=(%S+)") do + if key == "bytes" or key == "packets" then + entry[key] = entry[key] + tonumber(val, 10) + elseif key == "src" or key == "dst" then + if entry[key] == nil then + entry[key] = luci.ip.new(val):string() + end + elseif key == "sport" or key == "dport" then + if entry[key] == nil then + entry[key] = val + end + elseif val then + entry[key] = val + end + end + + if callback then + callback(entry) + else + connt[#connt+1] = entry + end + end + end + + return callback and true or connt +end + +function net.devices() + local devs = {} + local seen = {} + for k, v in ipairs(nixio.getifaddrs()) do + if v.name and not seen[v.name] then + seen[v.name] = true + devs[#devs+1] = v.name + end + end + return devs +end + +function net.duid_to_mac(duid) + local b1, b2, b3, b4, b5, b6 + + if type(duid) == "string" then + -- DUID-LLT / Ethernet + if #duid == 28 then + b1, b2, b3, b4, b5, b6 = duid:match("^00010001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)%x%x%x%x%x%x%x%x$") + + -- DUID-LL / Ethernet + elseif #duid == 20 then + b1, b2, b3, b4, b5, b6 = duid:match("^00030001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$") + + -- DUID-LL / Ethernet (Without Header) + elseif #duid == 12 then + b1, b2, b3, b4, b5, b6 = duid:match("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$") + end + end + + return b1 and luci.ip.checkmac(table.concat({ b1, b2, b3, b4, b5, b6 }, ":")) +end + +process = {} + +function process.info(key) + local s = {uid = nixio.getuid(), gid = nixio.getgid()} + return not key and s or s[key] +end + +function process.list() + local data = {} + local k + local ps = luci.util.execi("/bin/busybox top -bn1") + + if not ps then + return + end + + for line in ps do + local pid, ppid, user, stat, vsz, mem, cpu, cmd = line:match( + "^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][ 2 then + fd:close() + end +end + +function process.exec(command, stdout, stderr, nowait) + local out_r, out_w, err_r, err_w + if stdout then out_r, out_w = nixio.pipe() end + if stderr then err_r, err_w = nixio.pipe() end + + local pid = nixio.fork() + if pid == 0 then + nixio.chdir("/") + + local null = nixio.open("/dev/null", "w+") + if null then + nixio.dup(out_w or null, nixio.stdout) + nixio.dup(err_w or null, nixio.stderr) + nixio.dup(null, nixio.stdin) + xclose(out_w) + xclose(out_r) + xclose(err_w) + xclose(err_r) + xclose(null) + end + + nixio.exec(unpack(command)) + os.exit(-1) + end + + local _, pfds, rv = nil, {}, { code = -1, pid = pid } + + xclose(out_w) + xclose(err_w) + + if out_r then + pfds[#pfds+1] = { + fd = out_r, + cb = type(stdout) == "function" and stdout, + name = "stdout", + events = nixio.poll_flags("in", "err", "hup") + } + end + + if err_r then + pfds[#pfds+1] = { + fd = err_r, + cb = type(stderr) == "function" and stderr, + name = "stderr", + events = nixio.poll_flags("in", "err", "hup") + } + end + + while #pfds > 0 do + local nfds, err = nixio.poll(pfds, -1) + if not nfds and err ~= nixio.const.EINTR then + break + end + + local i + for i = #pfds, 1, -1 do + local rfd = pfds[i] + if rfd.revents > 0 then + local chunk, err = rfd.fd:read(4096) + if chunk and #chunk > 0 then + if rfd.cb then + rfd.cb(chunk) + else + rfd.buf = rfd.buf or {} + rfd.buf[#rfd.buf + 1] = chunk + end + else + table.remove(pfds, i) + if rfd.buf then + rv[rfd.name] = table.concat(rfd.buf, "") + end + rfd.fd:close() + end + end + end + end + + if not nowait then + _, _, rv.code = nixio.waitpid(pid) + end + + return rv +end + + +user = {} + +-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" } +user.getuser = nixio.getpw + +function user.getpasswd(username) + local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username) + local pwh = pwe and (pwe.pwdp or pwe.passwd) + if not pwh or #pwh < 1 then + return nil, pwe + else + return pwh, pwe + end +end + +function user.checkpasswd(username, pass) + local pwh, pwe = user.getpasswd(username) + if pwe then + return (pwh == nil or nixio.crypt(pass, pwh) == pwh) + end + return false +end + +function user.setpasswd(username, password) + return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{ + luci.util.shellquote(password), + luci.util.shellquote(password), + luci.util.shellquote(username) + }) +end + + +wifi = {} + +function wifi.getiwinfo(ifname) + local ntm = require "luci.model.network" + + ntm.init() + + local wnet = ntm:get_wifinet(ifname) + if wnet and wnet.iwinfo then + return wnet.iwinfo + end + + local wdev = ntm:get_wifidev(ifname) + if wdev and wdev.iwinfo then + return wdev.iwinfo + end + + return { ifname = ifname } +end + + +init = {} +init.dir = "/etc/init.d/" + +function init.names() + local names = { } + for name in fs.glob(init.dir.."*") do + names[#names+1] = fs.basename(name) + end + return names +end + +function init.index(name) + name = fs.basename(name) + if fs.access(init.dir..name) then + return call("env -i sh -c 'source %s%s enabled; exit ${START:-255}' >/dev/null" + %{ init.dir, name }) + end +end + +local function init_action(action, name) + name = fs.basename(name) + if fs.access(init.dir..name) then + return call("env -i %s%s %s >/dev/null" %{ init.dir, name, action }) + end +end + +function init.enabled(name) + return (init_action("enabled", name) == 0) +end + +function init.enable(name) + return (init_action("enable", name) == 0) +end + +function init.disable(name) + return (init_action("disable", name) == 0) +end + +function init.start(name) + return (init_action("start", name) == 0) +end + +function init.stop(name) + return (init_action("stop", name) == 0) +end + +function init.restart(name) + return (init_action("restart", name) == 0) +end + +function init.reload(name) + return (init_action("reload", name) == 0) +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo.lua new file mode 100644 index 0000000..aa054a2 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo.lua @@ -0,0 +1,19 @@ +-- Licensed to the public under the Apache License 2.0. + +local setmetatable, require, rawget, rawset = setmetatable, require, rawget, rawset + +module "luci.sys.zoneinfo" + +setmetatable(_M, { + __index = function(t, k) + if k == "TZ" and not rawget(t, k) then + local m = require "luci.sys.zoneinfo.tzdata" + rawset(t, k, rawget(m, k)) + elseif k == "OFFSET" and not rawget(t, k) then + local m = require "luci.sys.zoneinfo.tzoffset" + rawset(t, k, rawget(m, k)) + end + + return rawget(t, k) + end +}) diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzdata.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzdata.lua new file mode 100644 index 0000000..3ef2f4c --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzdata.lua @@ -0,0 +1,455 @@ +-- Licensed to the public under the Apache License 2.0. + +module "luci.sys.zoneinfo.tzdata" + +TZ = { + { 'Africa/Abidjan', 'GMT0' }, + { 'Africa/Accra', 'GMT0' }, + { 'Africa/Addis Ababa', 'EAT-3' }, + { 'Africa/Algiers', 'CET-1' }, + { 'Africa/Asmara', 'EAT-3' }, + { 'Africa/Bamako', 'GMT0' }, + { 'Africa/Bangui', 'WAT-1' }, + { 'Africa/Banjul', 'GMT0' }, + { 'Africa/Bissau', 'GMT0' }, + { 'Africa/Blantyre', 'CAT-2' }, + { 'Africa/Brazzaville', 'WAT-1' }, + { 'Africa/Bujumbura', 'CAT-2' }, + { 'Africa/Cairo', 'EET-2' }, + { 'Africa/Casablanca', '<+01>-1' }, + { 'Africa/Ceuta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Africa/Conakry', 'GMT0' }, + { 'Africa/Dakar', 'GMT0' }, + { 'Africa/Dar es Salaam', 'EAT-3' }, + { 'Africa/Djibouti', 'EAT-3' }, + { 'Africa/Douala', 'WAT-1' }, + { 'Africa/El Aaiun', '<+01>-1' }, + { 'Africa/Freetown', 'GMT0' }, + { 'Africa/Gaborone', 'CAT-2' }, + { 'Africa/Harare', 'CAT-2' }, + { 'Africa/Johannesburg', 'SAST-2' }, + { 'Africa/Juba', 'CAT-2' }, + { 'Africa/Kampala', 'EAT-3' }, + { 'Africa/Khartoum', 'CAT-2' }, + { 'Africa/Kigali', 'CAT-2' }, + { 'Africa/Kinshasa', 'WAT-1' }, + { 'Africa/Lagos', 'WAT-1' }, + { 'Africa/Libreville', 'WAT-1' }, + { 'Africa/Lome', 'GMT0' }, + { 'Africa/Luanda', 'WAT-1' }, + { 'Africa/Lubumbashi', 'CAT-2' }, + { 'Africa/Lusaka', 'CAT-2' }, + { 'Africa/Malabo', 'WAT-1' }, + { 'Africa/Maputo', 'CAT-2' }, + { 'Africa/Maseru', 'SAST-2' }, + { 'Africa/Mbabane', 'SAST-2' }, + { 'Africa/Mogadishu', 'EAT-3' }, + { 'Africa/Monrovia', 'GMT0' }, + { 'Africa/Nairobi', 'EAT-3' }, + { 'Africa/Ndjamena', 'WAT-1' }, + { 'Africa/Niamey', 'WAT-1' }, + { 'Africa/Nouakchott', 'GMT0' }, + { 'Africa/Ouagadougou', 'GMT0' }, + { 'Africa/Porto-Novo', 'WAT-1' }, + { 'Africa/Sao Tome', 'GMT0' }, + { 'Africa/Tripoli', 'EET-2' }, + { 'Africa/Tunis', 'CET-1' }, + { 'Africa/Windhoek', 'CAT-2' }, + { 'America/Adak', 'HST10HDT,M3.2.0,M11.1.0' }, + { 'America/Anchorage', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Anguilla', 'AST4' }, + { 'America/Antigua', 'AST4' }, + { 'America/Araguaina', '<-03>3' }, + { 'America/Argentina/Buenos Aires', '<-03>3' }, + { 'America/Argentina/Catamarca', '<-03>3' }, + { 'America/Argentina/Cordoba', '<-03>3' }, + { 'America/Argentina/Jujuy', '<-03>3' }, + { 'America/Argentina/La Rioja', '<-03>3' }, + { 'America/Argentina/Mendoza', '<-03>3' }, + { 'America/Argentina/Rio Gallegos', '<-03>3' }, + { 'America/Argentina/Salta', '<-03>3' }, + { 'America/Argentina/San Juan', '<-03>3' }, + { 'America/Argentina/San Luis', '<-03>3' }, + { 'America/Argentina/Tucuman', '<-03>3' }, + { 'America/Argentina/Ushuaia', '<-03>3' }, + { 'America/Aruba', 'AST4' }, + { 'America/Asuncion', '<-04>4<-03>,M10.1.0/0,M3.4.0/0' }, + { 'America/Atikokan', 'EST5' }, + { 'America/Bahia', '<-03>3' }, + { 'America/Bahia Banderas', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Barbados', 'AST4' }, + { 'America/Belem', '<-03>3' }, + { 'America/Belize', 'CST6' }, + { 'America/Blanc-Sablon', 'AST4' }, + { 'America/Boa Vista', '<-04>4' }, + { 'America/Bogota', '<-05>5' }, + { 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Campo Grande', '<-04>4' }, + { 'America/Cancun', 'EST5' }, + { 'America/Caracas', '<-04>4' }, + { 'America/Cayenne', '<-03>3' }, + { 'America/Cayman', 'EST5' }, + { 'America/Chicago', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' }, + { 'America/Costa Rica', 'CST6' }, + { 'America/Creston', 'MST7' }, + { 'America/Cuiaba', '<-04>4' }, + { 'America/Curacao', 'AST4' }, + { 'America/Danmarkshavn', 'GMT0' }, + { 'America/Dawson', 'MST7' }, + { 'America/Dawson Creek', 'MST7' }, + { 'America/Denver', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Detroit', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Dominica', 'AST4' }, + { 'America/Edmonton', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Eirunepe', '<-05>5' }, + { 'America/El Salvador', 'CST6' }, + { 'America/Fort Nelson', 'MST7' }, + { 'America/Fortaleza', '<-03>3' }, + { 'America/Glace Bay', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Goose Bay', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Grand Turk', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Grenada', 'AST4' }, + { 'America/Guadeloupe', 'AST4' }, + { 'America/Guatemala', 'CST6' }, + { 'America/Guayaquil', '<-05>5' }, + { 'America/Guyana', '<-04>4' }, + { 'America/Halifax', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Havana', 'CST5CDT,M3.2.0/0,M11.1.0/1' }, + { 'America/Hermosillo', 'MST7' }, + { 'America/Indiana/Indianapolis', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Knox', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Marengo', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Petersburg', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Tell City', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Vevay', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Vincennes', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Winamac', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Inuvik', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Iqaluit', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Jamaica', 'EST5' }, + { 'America/Juneau', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Kentucky/Louisville', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Kentucky/Monticello', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Kralendijk', 'AST4' }, + { 'America/La Paz', '<-04>4' }, + { 'America/Lima', '<-05>5' }, + { 'America/Los Angeles', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Lower Princes', 'AST4' }, + { 'America/Maceio', '<-03>3' }, + { 'America/Managua', 'CST6' }, + { 'America/Manaus', '<-04>4' }, + { 'America/Marigot', 'AST4' }, + { 'America/Martinique', 'AST4' }, + { 'America/Matamoros', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Mazatlan', 'MST7MDT,M4.1.0,M10.5.0' }, + { 'America/Menominee', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Merida', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Metlakatla', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Mexico City', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Miquelon', '<-03>3<-02>,M3.2.0,M11.1.0' }, + { 'America/Moncton', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Monterrey', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Montevideo', '<-03>3' }, + { 'America/Montserrat', 'AST4' }, + { 'America/Nassau', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/New York', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Nipigon', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Nome', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Noronha', '<-02>2' }, + { 'America/North Dakota/Beulah', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/North Dakota/Center', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/North Dakota/New Salem', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Nuuk', '<-03>3<-02>,M3.5.0/-2,M10.5.0/-1' }, + { 'America/Ojinaga', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Panama', 'EST5' }, + { 'America/Pangnirtung', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Paramaribo', '<-03>3' }, + { 'America/Phoenix', 'MST7' }, + { 'America/Port of Spain', 'AST4' }, + { 'America/Port-au-Prince', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Porto Velho', '<-04>4' }, + { 'America/Puerto Rico', 'AST4' }, + { 'America/Punta Arenas', '<-03>3' }, + { 'America/Rainy River', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Rankin Inlet', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Recife', '<-03>3' }, + { 'America/Regina', 'CST6' }, + { 'America/Resolute', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Rio Branco', '<-05>5' }, + { 'America/Santarem', '<-03>3' }, + { 'America/Santiago', '<-04>4<-03>,M9.1.6/24,M4.1.6/24' }, + { 'America/Santo Domingo', 'AST4' }, + { 'America/Sao Paulo', '<-03>3' }, + { 'America/Scoresbysund', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' }, + { 'America/Sitka', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/St Barthelemy', 'AST4' }, + { 'America/St Johns', 'NST3:30NDT,M3.2.0,M11.1.0' }, + { 'America/St Kitts', 'AST4' }, + { 'America/St Lucia', 'AST4' }, + { 'America/St Thomas', 'AST4' }, + { 'America/St Vincent', 'AST4' }, + { 'America/Swift Current', 'CST6' }, + { 'America/Tegucigalpa', 'CST6' }, + { 'America/Thule', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Thunder Bay', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Tijuana', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Toronto', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Tortola', 'AST4' }, + { 'America/Vancouver', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Whitehorse', 'MST7' }, + { 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'Antarctica/Casey', '<+11>-11' }, + { 'Antarctica/Davis', '<+07>-7' }, + { 'Antarctica/DumontDUrville', '<+10>-10' }, + { 'Antarctica/Macquarie', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Antarctica/Mawson', '<+05>-5' }, + { 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, + { 'Antarctica/Palmer', '<-03>3' }, + { 'Antarctica/Rothera', '<-03>3' }, + { 'Antarctica/Syowa', '<+03>-3' }, + { 'Antarctica/Troll', '<+00>0<+02>-2,M3.5.0/1,M10.5.0/3' }, + { 'Antarctica/Vostok', '<+06>-6' }, + { 'Arctic/Longyearbyen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Asia/Aden', '<+03>-3' }, + { 'Asia/Almaty', '<+06>-6' }, + { 'Asia/Amman', '<+03>-3' }, + { 'Asia/Anadyr', '<+12>-12' }, + { 'Asia/Aqtau', '<+05>-5' }, + { 'Asia/Aqtobe', '<+05>-5' }, + { 'Asia/Ashgabat', '<+05>-5' }, + { 'Asia/Atyrau', '<+05>-5' }, + { 'Asia/Baghdad', '<+03>-3' }, + { 'Asia/Bahrain', '<+03>-3' }, + { 'Asia/Baku', '<+04>-4' }, + { 'Asia/Bangkok', '<+07>-7' }, + { 'Asia/Barnaul', '<+07>-7' }, + { 'Asia/Beirut', 'EET-2EEST,M3.5.0/0,M10.5.0/0' }, + { 'Asia/Bishkek', '<+06>-6' }, + { 'Asia/Brunei', '<+08>-8' }, + { 'Asia/Chita', '<+09>-9' }, + { 'Asia/Choibalsan', '<+08>-8' }, + { 'Asia/Colombo', '<+0530>-5:30' }, + { 'Asia/Damascus', '<+03>-3' }, + { 'Asia/Dhaka', '<+06>-6' }, + { 'Asia/Dili', '<+09>-9' }, + { 'Asia/Dubai', '<+04>-4' }, + { 'Asia/Dushanbe', '<+05>-5' }, + { 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Asia/Gaza', 'EET-2EEST,M3.4.4/50,M10.4.4/50' }, + { 'Asia/Hebron', 'EET-2EEST,M3.4.4/50,M10.4.4/50' }, + { 'Asia/Ho Chi Minh', '<+07>-7' }, + { 'Asia/Hong Kong', 'HKT-8' }, + { 'Asia/Hovd', '<+07>-7' }, + { 'Asia/Irkutsk', '<+08>-8' }, + { 'Asia/Jakarta', 'WIB-7' }, + { 'Asia/Jayapura', 'WIT-9' }, + { 'Asia/Jerusalem', 'IST-2IDT,M3.4.4/26,M10.5.0' }, + { 'Asia/Kabul', '<+0430>-4:30' }, + { 'Asia/Kamchatka', '<+12>-12' }, + { 'Asia/Karachi', 'PKT-5' }, + { 'Asia/Kathmandu', '<+0545>-5:45' }, + { 'Asia/Khandyga', '<+09>-9' }, + { 'Asia/Kolkata', 'IST-5:30' }, + { 'Asia/Krasnoyarsk', '<+07>-7' }, + { 'Asia/Kuala Lumpur', '<+08>-8' }, + { 'Asia/Kuching', '<+08>-8' }, + { 'Asia/Kuwait', '<+03>-3' }, + { 'Asia/Macau', 'CST-8' }, + { 'Asia/Magadan', '<+11>-11' }, + { 'Asia/Makassar', 'WITA-8' }, + { 'Asia/Manila', 'PST-8' }, + { 'Asia/Muscat', '<+04>-4' }, + { 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Asia/Novokuznetsk', '<+07>-7' }, + { 'Asia/Novosibirsk', '<+07>-7' }, + { 'Asia/Omsk', '<+06>-6' }, + { 'Asia/Oral', '<+05>-5' }, + { 'Asia/Phnom Penh', '<+07>-7' }, + { 'Asia/Pontianak', 'WIB-7' }, + { 'Asia/Pyongyang', 'KST-9' }, + { 'Asia/Qatar', '<+03>-3' }, + { 'Asia/Qostanay', '<+06>-6' }, + { 'Asia/Qyzylorda', '<+05>-5' }, + { 'Asia/Riyadh', '<+03>-3' }, + { 'Asia/Sakhalin', '<+11>-11' }, + { 'Asia/Samarkand', '<+05>-5' }, + { 'Asia/Seoul', 'KST-9' }, + { 'Asia/Shanghai', 'CST-8' }, + { 'Asia/Singapore', '<+08>-8' }, + { 'Asia/Srednekolymsk', '<+11>-11' }, + { 'Asia/Taipei', 'CST-8' }, + { 'Asia/Tashkent', '<+05>-5' }, + { 'Asia/Tbilisi', '<+04>-4' }, + { 'Asia/Tehran', '<+0330>-3:30' }, + { 'Asia/Thimphu', '<+06>-6' }, + { 'Asia/Tokyo', 'JST-9' }, + { 'Asia/Tomsk', '<+07>-7' }, + { 'Asia/Ulaanbaatar', '<+08>-8' }, + { 'Asia/Urumqi', '<+06>-6' }, + { 'Asia/Ust-Nera', '<+10>-10' }, + { 'Asia/Vientiane', '<+07>-7' }, + { 'Asia/Vladivostok', '<+10>-10' }, + { 'Asia/Yakutsk', '<+09>-9' }, + { 'Asia/Yangon', '<+0630>-6:30' }, + { 'Asia/Yekaterinburg', '<+05>-5' }, + { 'Asia/Yerevan', '<+04>-4' }, + { 'Atlantic/Azores', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' }, + { 'Atlantic/Bermuda', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'Atlantic/Canary', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Cape Verde', '<-01>1' }, + { 'Atlantic/Faroe', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Madeira', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Reykjavik', 'GMT0' }, + { 'Atlantic/South Georgia', '<-02>2' }, + { 'Atlantic/St Helena', 'GMT0' }, + { 'Atlantic/Stanley', '<-03>3' }, + { 'Australia/Adelaide', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Brisbane', 'AEST-10' }, + { 'Australia/Broken Hill', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Darwin', 'ACST-9:30' }, + { 'Australia/Eucla', '<+0845>-8:45' }, + { 'Australia/Hobart', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Lindeman', 'AEST-10' }, + { 'Australia/Lord Howe', '<+1030>-10:30<+11>-11,M10.1.0,M4.1.0' }, + { 'Australia/Melbourne', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Perth', 'AWST-8' }, + { 'Australia/Sydney', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Etc/GMT', 'GMT0' }, + { 'Etc/GMT+1', '<-01>1' }, + { 'Etc/GMT+10', '<-10>10' }, + { 'Etc/GMT+11', '<-11>11' }, + { 'Etc/GMT+12', '<-12>12' }, + { 'Etc/GMT+2', '<-02>2' }, + { 'Etc/GMT+3', '<-03>3' }, + { 'Etc/GMT+4', '<-04>4' }, + { 'Etc/GMT+5', '<-05>5' }, + { 'Etc/GMT+6', '<-06>6' }, + { 'Etc/GMT+7', '<-07>7' }, + { 'Etc/GMT+8', '<-08>8' }, + { 'Etc/GMT+9', '<-09>9' }, + { 'Etc/GMT-1', '<+01>-1' }, + { 'Etc/GMT-10', '<+10>-10' }, + { 'Etc/GMT-11', '<+11>-11' }, + { 'Etc/GMT-12', '<+12>-12' }, + { 'Etc/GMT-13', '<+13>-13' }, + { 'Etc/GMT-14', '<+14>-14' }, + { 'Etc/GMT-2', '<+02>-2' }, + { 'Etc/GMT-3', '<+03>-3' }, + { 'Etc/GMT-4', '<+04>-4' }, + { 'Etc/GMT-5', '<+05>-5' }, + { 'Etc/GMT-6', '<+06>-6' }, + { 'Etc/GMT-7', '<+07>-7' }, + { 'Etc/GMT-8', '<+08>-8' }, + { 'Etc/GMT-9', '<+09>-9' }, + { 'Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Andorra', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Astrakhan', '<+04>-4' }, + { 'Europe/Athens', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Belgrade', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Berlin', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Bratislava', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Brussels', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Bucharest', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Budapest', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Busingen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Chisinau', 'EET-2EEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Dublin', 'IST-1GMT0,M10.5.0,M3.5.0/1' }, + { 'Europe/Gibraltar', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Guernsey', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Helsinki', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Isle of Man', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Istanbul', '<+03>-3' }, + { 'Europe/Jersey', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Kaliningrad', 'EET-2' }, + { 'Europe/Kirov', '<+03>-3' }, + { 'Europe/Kyiv', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Lisbon', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Europe/Ljubljana', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/London', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Luxembourg', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Madrid', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Malta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Mariehamn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Minsk', '<+03>-3' }, + { 'Europe/Monaco', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Moscow', 'MSK-3' }, + { 'Europe/Oslo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Paris', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Podgorica', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Prague', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Riga', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Rome', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Samara', '<+04>-4' }, + { 'Europe/San Marino', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Sarajevo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Saratov', '<+04>-4' }, + { 'Europe/Simferopol', 'MSK-3' }, + { 'Europe/Skopje', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Sofia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Stockholm', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Tallinn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Tirane', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Ulyanovsk', '<+04>-4' }, + { 'Europe/Vaduz', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vatican', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vienna', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vilnius', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Volgograd', '<+03>-3' }, + { 'Europe/Warsaw', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Zagreb', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Zurich', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Indian/Antananarivo', 'EAT-3' }, + { 'Indian/Chagos', '<+06>-6' }, + { 'Indian/Christmas', '<+07>-7' }, + { 'Indian/Cocos', '<+0630>-6:30' }, + { 'Indian/Comoro', 'EAT-3' }, + { 'Indian/Kerguelen', '<+05>-5' }, + { 'Indian/Mahe', '<+04>-4' }, + { 'Indian/Maldives', '<+05>-5' }, + { 'Indian/Mauritius', '<+04>-4' }, + { 'Indian/Mayotte', 'EAT-3' }, + { 'Indian/Reunion', '<+04>-4' }, + { 'Pacific/Apia', '<+13>-13' }, + { 'Pacific/Auckland', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, + { 'Pacific/Bougainville', '<+11>-11' }, + { 'Pacific/Chatham', '<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45' }, + { 'Pacific/Chuuk', '<+10>-10' }, + { 'Pacific/Easter', '<-06>6<-05>,M9.1.6/22,M4.1.6/22' }, + { 'Pacific/Efate', '<+11>-11' }, + { 'Pacific/Fakaofo', '<+13>-13' }, + { 'Pacific/Fiji', '<+12>-12<+13>,M11.2.0,M1.2.3/99' }, + { 'Pacific/Funafuti', '<+12>-12' }, + { 'Pacific/Galapagos', '<-06>6' }, + { 'Pacific/Gambier', '<-09>9' }, + { 'Pacific/Guadalcanal', '<+11>-11' }, + { 'Pacific/Guam', 'ChST-10' }, + { 'Pacific/Honolulu', 'HST10' }, + { 'Pacific/Kanton', '<+13>-13' }, + { 'Pacific/Kiritimati', '<+14>-14' }, + { 'Pacific/Kosrae', '<+11>-11' }, + { 'Pacific/Kwajalein', '<+12>-12' }, + { 'Pacific/Majuro', '<+12>-12' }, + { 'Pacific/Marquesas', '<-0930>9:30' }, + { 'Pacific/Midway', 'SST11' }, + { 'Pacific/Nauru', '<+12>-12' }, + { 'Pacific/Niue', '<-11>11' }, + { 'Pacific/Norfolk', '<+11>-11<+12>,M10.1.0,M4.1.0/3' }, + { 'Pacific/Noumea', '<+11>-11' }, + { 'Pacific/Pago Pago', 'SST11' }, + { 'Pacific/Palau', '<+09>-9' }, + { 'Pacific/Pitcairn', '<-08>8' }, + { 'Pacific/Pohnpei', '<+11>-11' }, + { 'Pacific/Port Moresby', '<+10>-10' }, + { 'Pacific/Rarotonga', '<-10>10' }, + { 'Pacific/Saipan', 'ChST-10' }, + { 'Pacific/Tahiti', '<-10>10' }, + { 'Pacific/Tarawa', '<+12>-12' }, + { 'Pacific/Tongatapu', '<+13>-13' }, + { 'Pacific/Wake', '<+12>-12' }, + { 'Pacific/Wallis', '<+12>-12' }, +} diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzoffset.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzoffset.lua new file mode 100644 index 0000000..caee1d2 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/sys/zoneinfo/tzoffset.lua @@ -0,0 +1,46 @@ +-- Licensed to the public under the Apache License 2.0. + +module "luci.sys.zoneinfo.tzoffset" + +OFFSET = { + gmt = 0, -- GMT + eat = 10800, -- EAT + cet = 3600, -- CET + wat = 3600, -- WAT + cat = 7200, -- CAT + eet = 7200, -- EET + sast = 7200, -- SAST + hst = -36000, -- HST + hdt = -32400, -- HDT + akst = -32400, -- AKST + akdt = -28800, -- AKDT + ast = -14400, -- AST + est = -18000, -- EST + cst = -21600, -- CST + cdt = -18000, -- CDT + mst = -25200, -- MST + mdt = -21600, -- MDT + pst = -28800, -- PST + pdt = -25200, -- PDT + nst = -12600, -- NST + ndt = -9000, -- NDT + aest = 36000, -- AEST + aedt = 39600, -- AEDT + nzst = 43200, -- NZST + nzdt = 46800, -- NZDT + hkt = 28800, -- HKT + wib = 25200, -- WIB + wit = 32400, -- WIT + ist = 7200, -- IST + idt = 10800, -- IDT + pkt = 18000, -- PKT + wita = 28800, -- WITA + kst = 32400, -- KST + jst = 32400, -- JST + wet = 0, -- WET + acst = 34200, -- ACST + acdt = 37800, -- ACDT + awst = 28800, -- AWST + msk = 10800, -- MSK + sst = -39600, -- SST +} diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template.lua new file mode 100644 index 0000000..b6b9af0 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template.lua @@ -0,0 +1,184 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local util = require "luci.util" +local config = require "luci.config" +local tparser = require "luci.template.parser" + +local tostring, pairs, loadstring = tostring, pairs, loadstring +local setmetatable, loadfile = setmetatable, loadfile +local getfenv, setfenv, rawget = getfenv, setfenv, rawget +local assert, type, error = assert, type, error +local table, string, unpack = table, string, unpack + + +--- +--- bootstrap +--- +local _G = _G +local L = _G.L + +local http = _G.L.http + +local disp = require "luci.dispatcher" +local i18n = require "luci.i18n" +local xml = require "luci.xml" +local fs = require "nixio.fs" + + +--- LuCI template library. +module "luci.template" + +config.template = config.template or {} +viewdir = config.template.viewdir or util.libpath() .. "/view" + + +-- Define the namespace for template modules +context = {} --util.threadlocal() + +--- Render a certain template. +-- @param name Template name +-- @param scope Scope to assign to template (optional) +function render(name, scope) + return Template(name):render(scope or getfenv(2)) +end + +--- Render a template from a string. +-- @param template Template string +-- @param scope Scope to assign to template (optional) +function render_string(template, scope) + return Template(nil, template):render(scope or getfenv(2)) +end + + +-- Template class +Template = util.class() + +-- Shared template cache to store templates in to avoid unnecessary reloading +Template.cache = setmetatable({}, {__mode = "v"}) + + + +local function _ifattr(cond, key, val, noescape) + if cond then + local env = getfenv(3) + local scope = (type(env.self) == "table") and env.self + if type(val) == "table" then + if not next(val) then + return '' + else + val = util.serialize_json(val) + end + end + + val = tostring(val or + (type(env[key]) ~= "function" and env[key]) or + (scope and type(scope[key]) ~= "function" and scope[key]) or "") + + if noescape ~= true then + val = xml.pcdata(val) + end + + return string.format(' %s="%s"', tostring(key), val) + else + return '' + end +end + +context.viewns = setmetatable({ + include = function(name) + if fs.access(viewdir .. "/" .. name .. ".htm") then + Template(name):render(getfenv(2)) + else + L.include(name, getfenv(2)) + end + end; + translate = i18n.translate; + translatef = i18n.translatef; + export = function(k, v) if context.viewns[k] == nil then context.viewns[k] = v end end; + striptags = xml.striptags; + pcdata = xml.pcdata; + ifattr = function(...) return _ifattr(...) end; + attr = function(...) return _ifattr(true, ...) end; + url = disp.build_url; +}, {__index=function(tbl, key) + if key == "controller" then + return disp.build_url() + elseif key == "REQUEST_URI" then + return disp.build_url(unpack(disp.context.requestpath)) + elseif key == "FULL_REQUEST_URI" then + local url = { http:getenv("SCRIPT_NAME") or "", http:getenv("PATH_INFO") } + local query = http:getenv("QUERY_STRING") + if query and #query > 0 then + url[#url+1] = "?" + url[#url+1] = query + end + return table.concat(url, "") + elseif key == "token" then + return disp.context.authtoken + elseif key == "theme" then + return L.media and fs.basename(L.media) or tostring(L) + elseif key == "resource" then + return L.config.main.resourcebase + else + return rawget(tbl, key) or _G[key] or L[key] + end +end}) + + +-- Constructor - Reads and compiles the template on-demand +function Template.__init__(self, name, template) + if name then + self.template = self.cache[name] + self.name = name + else + self.name = "[string]" + end + + -- Create a new namespace for this template + self.viewns = context.viewns + + -- If we have a cached template, skip compiling and loading + if not self.template then + + -- Compile template + local err + local sourcefile + + if name then + sourcefile = viewdir .. "/" .. name .. ".htm" + self.template, _, err = tparser.parse(sourcefile) + else + sourcefile = "[string]" + self.template, _, err = tparser.parse_string(template) + end + + -- If we have no valid template throw error, otherwise cache the template + if not self.template then + error("Failed to load template '" .. self.name .. "'.\n" .. + "Error while parsing template '" .. sourcefile .. "':\n" .. + (err or "Unknown syntax error")) + elseif name then + self.cache[name] = self.template + end + end +end + + +-- Renders a template +function Template.render(self, scope) + scope = scope or getfenv(2) + + -- Put our predefined objects in the scope of the template + setfenv(self.template, setmetatable({}, {__index = + function(tbl, key) + return rawget(tbl, key) or self.viewns[key] or scope[key] + end})) + + -- Now finally render the thing + local stat, err = util.copcall(self.template) + if not stat then + error("Failed to execute template '" .. self.name .. "'.\n" .. + "A runtime error occurred: " .. tostring(err or "(nil)")) + end +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template/parser.so b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/template/parser.so new file mode 100755 index 0000000000000000000000000000000000000000..c96a60d5f58f046213441c2d2db3dcd51c78fd85 GIT binary patch literal 65666 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 mG`so#1OfSm +-- Licensed to the public under the Apache License 2.0. + +local coroutine, assert, error, type, require = coroutine, assert, error, type, require +local tmpl = require "luci.template" +local util = require "luci.util" +local http = require "luci.http" +local sys = require "luci.sys" +local ltn12 = require "luci.ltn12" + + +--- LuCI ucode bridge library. +module "luci.ucodebridge" + +local function run(fn, ...) + local co = coroutine.create(fn) + local ok, ret + + while coroutine.status(co) ~= "dead" do + ok, ret = coroutine.resume(co, ...) + + if not ok then + error(ret) + end + end + + return ret +end + +function compile(path) + run(function(path) + return tmpl.Template(path) + end, path) +end + +function render(path, scope) + run(tmpl.render, path, scope) +end + +function call(modname, method, ...) + return run(function(module, method, ...) + local mod = require(modname) + local func = mod[method] + + assert(func ~= nil, + 'Cannot resolve function "' .. method .. '". Is it misspelled or local?') + + assert(type(func) == "function", + 'The symbol "' .. method .. '" does not refer to a function but data ' .. + 'of type "' .. type(func) .. '".') + + return func(...) + end, modname, method, ...) +end diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/version.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/version.lua new file mode 100644 index 0000000..f0b73d1 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/version.lua @@ -0,0 +1,20 @@ +local pcall, dofile, _G = pcall, dofile, _G + +module "luci.version" + +if pcall(dofile, "/etc/openwrt_release") and _G.DISTRIB_DESCRIPTION then + distname = "" + distversion = _G.DISTRIB_DESCRIPTION + if _G.DISTRIB_REVISION then + distrevision = _G.DISTRIB_REVISION + if not distversion:find(distrevision,1,true) then + distversion = distversion .. " " .. distrevision + end + end +else + distname = "OpenWrt" + distversion = "Development Snapshot" +end + +luciname = "LuCI openwrt-24.10 branch" +luciversion = "25.034.70690~7b0663a" diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/admin_status/luaindex.htm b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/admin_status/luaindex.htm new file mode 100644 index 0000000..ef664ed --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/admin_status/luaindex.htm @@ -0,0 +1,18 @@ +<%- + local util = require "luci.util" + local fs = require "nixio.fs" + + local incdir = util.libpath() .. "/view/admin_status/index/" + if fs.access(incdir) then + local _, inc + local includes = {} + for inc in fs.dir(incdir) do + if inc:match("%.htm$") then + includes[#includes + 1] = inc:gsub("%.htm$", "") + end + end + for _, inc in luci.util.vspairs(includes) do + include("admin_status/index/" .. inc) + end + end +-%> diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/empty_node_placeholder.htm b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/empty_node_placeholder.htm new file mode 100644 index 0000000..b7e276b --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/empty_node_placeholder.htm @@ -0,0 +1,11 @@ +<%# + Copyright 2010 Jo-Philipp Wich + Copyright 2018 Daniel F. Dickinson + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +

Component not present.

+ +<%+footer%> diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/indexer.htm b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/indexer.htm new file mode 100644 index 0000000..28fc3de --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/view/indexer.htm @@ -0,0 +1,7 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<% include("themes/" .. theme .. "/indexer") %> \ No newline at end of file diff --git a/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/xml.lua b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/xml.lua new file mode 100644 index 0000000..30b3721 --- /dev/null +++ b/ipk-source/luci-lua-runtime_aarch64_cortex-a53/root/usr/lib/lua/luci/xml.lua @@ -0,0 +1,26 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local tparser = require "luci.template.parser" +local string = require "string" + +local tostring = tostring + +module "luci.xml" + +-- +-- String and data manipulation routines +-- + +function pcdata(value) + return value and tparser.pcdata(tostring(value)) +end + +function striptags(value) + return value and tparser.striptags(tostring(value)) +end + + +-- also register functions above in the central string class for convenience +string.pcdata = pcdata +string.striptags = striptags diff --git a/ipk-source/luci-theme-argon/CONTROL/control b/ipk-source/luci-theme-argon/CONTROL/control new file mode 100644 index 0000000..7fb86a4 --- /dev/null +++ b/ipk-source/luci-theme-argon/CONTROL/control @@ -0,0 +1,12 @@ +Package: luci-theme-argon +Version: 2.3.2-r20250207 +Depends: libc, curl, jsonfilter, luci-lua-runtime +Source: feeds/base/downloads/luci-theme-argon +SourceName: luci-theme-argon +Section: luci +SourceDateEpoch: 1739087731 +URL: https://github.com/openwrt/luci +Maintainer: OpenWrt LuCI community +Architecture: all +Installed-Size: 768000 +Description: Argon Theme diff --git a/ipk-source/luci-theme-argon/CONTROL/postinst b/ipk-source/luci-theme-argon/CONTROL/postinst new file mode 100755 index 0000000..3bba77c --- /dev/null +++ b/ipk-source/luci-theme-argon/CONTROL/postinst @@ -0,0 +1,5 @@ +#!/bin/sh +[ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0 +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_postinst $0 $@ diff --git a/ipk-source/luci-theme-argon/CONTROL/postinst-pkg b/ipk-source/luci-theme-argon/CONTROL/postinst-pkg new file mode 100755 index 0000000..2e52d45 --- /dev/null +++ b/ipk-source/luci-theme-argon/CONTROL/postinst-pkg @@ -0,0 +1,5 @@ +[ -n "${IPKG_INSTROOT}" ] || { rm -f /tmp/luci-indexcache.* + rm -rf /tmp/luci-modulecache/ + killall -HUP rpcd 2>/dev/null + exit 0 +} diff --git a/ipk-source/luci-theme-argon/CONTROL/prerm b/ipk-source/luci-theme-argon/CONTROL/prerm new file mode 100755 index 0000000..12d06ec --- /dev/null +++ b/ipk-source/luci-theme-argon/CONTROL/prerm @@ -0,0 +1,4 @@ +#!/bin/sh +[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0 +. ${IPKG_INSTROOT}/lib/functions.sh +default_prerm $0 $@ diff --git a/ipk-source/luci-theme-argon/build-ipk b/ipk-source/luci-theme-argon/build-ipk new file mode 100755 index 0000000..eb83cf6 --- /dev/null +++ b/ipk-source/luci-theme-argon/build-ipk @@ -0,0 +1,74 @@ +#!/bin/sh + +# Script for building OpenWRT .ipk packages using tar by iamromulan +# Works with SDXPPINN OpenWRT - iamromulan +# This script accepts an optional path to the directory containing the `CONTROL` and `root` directories. +# Usage: ./build-ipk.sh [path] +# If no path is provided, the script will look in the current directory for `CONTROL` and `root` directories. +# This will spit out an ipk in the current directory + +# Check if the script is run as root. If not, rerun with sudo. +if [ "$(id -u)" -ne 0 ]; then + echo "Script is not running as root. Re-executing with sudo..." + exec sudo "$0" "$@" +fi + +# Set the default build path to the current directory +build_path="." + +# Check if a path is provided as the first argument +if [ "$1" ]; then + build_path="$1" +fi + +# Check if the required directories are present in the specified path +if [ ! -d "${build_path}/CONTROL" ] || [ ! -d "${build_path}/root" ]; then + echo "Error: CONTROL and root directories must be present in the specified path (${build_path})." + exit 1 +fi + +# Extract values from the CONTROL/control file in the specified path +pkgname=$(grep -i '^Package:' "${build_path}/CONTROL/control" | awk '{print $2}') +version=$(grep -i '^Version:' "${build_path}/CONTROL/control" | awk '{print $2}') +architecture=$(grep -i '^Architecture:' "${build_path}/CONTROL/control" | awk '{print $2}') + +# Check if values are extracted correctly +if [ -z "$pkgname" ] || [ -z "$version" ] || [ -z "$architecture" ]; then + echo "Error: Failed to extract Package, Version, or Architecture from ${build_path}/CONTROL/control." + exit 1 +fi + +# Set the final IPK name based on the extracted values +ipkname="${pkgname}_${version}_${architecture}.ipk" + +# Ensure all CONTROL scripts are executable +echo "Setting permissions for CONTROL scripts..." +chmod +x "${build_path}/CONTROL"/* + +# Set ownership for CONTROL and root files +echo "Setting ownership for all package files..." +chown -R root:root "${build_path}/CONTROL"/* +chown -R root:root "${build_path}/root"/* + +# Create control.tar.gz from the CONTROL directory +echo "Creating control.tar.gz..." +tar -czvf control.tar.gz -C "${build_path}/CONTROL" . + +# Create data.tar.gz from the root directory +echo "Creating data.tar.gz..." +tar -czvf data.tar.gz -C "${build_path}/root" . + +# Create debian-binary file (must contain exactly "2.0" without a newline) +echo -n "2.0" > debian-binary +chown -R root:root debian-binary + +# Combine the components into the final .ipk file using tar +echo "Packaging ${ipkname}..." +tar -czvf "$ipkname" debian-binary control.tar.gz data.tar.gz + +# Clean up intermediate files +echo "Cleaning up temporary files..." +rm -f control.tar.gz data.tar.gz debian-binary + +echo "IPK package ${ipkname} created successfully using tar." + diff --git a/ipk-source/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon b/ipk-source/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon new file mode 100644 index 0000000..6820d25 --- /dev/null +++ b/ipk-source/luci-theme-argon/root/etc/uci-defaults/30_luci-theme-argon @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "$PKG_UPGRADE" != 1 ]; then + uci get luci.themes.Argon >/dev/null 2>&1 || \ + uci batch <<-EOF + set luci.themes.Argon=/luci-static/argon + set luci.main.mediaurlbase=/luci-static/argon + commit luci + EOF +fi + +exit 0 diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer.htm new file mode 100644 index 0000000..6b3d3fe --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer.htm @@ -0,0 +1,46 @@ +<%# + Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material Argon Template + + luci-theme-argon + Copyright 2020 Jerrykuku + + Have a bug? Please create an issue here on GitHub! + https://github.com/jerrykuku/luci-theme-argon/issues + + luci-theme-material: + Copyright 2015 Lutty Yang + + Agron Theme + https://demos.creative-tim.com/argon-dashboard/index.html + + Licensed to the public under the Apache License 2.0 +-%> + +<% local ver = require "luci.version" %> + +
+ + + + + + diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer_login.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer_login.htm new file mode 100644 index 0000000..e7092ac --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/footer_login.htm @@ -0,0 +1,44 @@ +<%# + Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material Argon Template + + luci-theme-argon + Copyright 2020 Jerrykuku + + Have a bug? Please create an issue here on GitHub! + https://github.com/jerrykuku/luci-theme-argon/issues + + luci-theme-material: + Copyright 2015 Lutty Yang + + Agron Theme + https://demos.creative-tim.com/argon-dashboard/index.html + + Licensed to the public under the Apache License 2.0 +-%> + +<% local ver = require "luci.version" %> + + + + + + + diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header.htm new file mode 100644 index 0000000..3d3511e --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header.htm @@ -0,0 +1,180 @@ +<%# + Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material Argon Template + + luci-theme-argon + Copyright 2020 Jerrykuku + + Have a bug? Please create an issue here on GitHub! + https://github.com/jerrykuku/luci-theme-argon/issues + + luci-theme-material: + Copyright 2015 Lutty Yang + + Argon Theme + https://demos.creative-tim.com/argon-dashboard/index.html + + Licensed to the public under the Apache License 2.0 +-%> + +<% + local sys = require "luci.sys" + local util = require "luci.util" + local http = require "luci.http" + local disp = require "luci.dispatcher" + local ver = require "luci.version" + + local boardinfo = util.ubus("system", "board") + + local node = disp.context.dispatched + + local fs = require "nixio.fs" + local nutil = require "nixio.util" + local uci = require 'luci.model.uci'.cursor() + + -- send as HTML5 + http.prepare_content("text/html") + + math.randomseed(os.time()) + + -- Custom settings + local mode = 'normal' + local dark_css = fs.readfile('/www/luci-static/argon/css/dark.css') + local bar_color = '#5e72e4' + local primary, dark_primary, blur_radius, blur_radius_dark, blur_opacity + if fs.access('/etc/config/argon') then + primary = uci:get_first('argon', 'global', 'primary') + dark_primary = uci:get_first('argon', 'global', 'dark_primary') + blur_radius = uci:get_first('argon', 'global', 'blur') + blur_radius_dark = uci:get_first('argon', 'global', 'blur_dark') + blur_opacity = uci:get_first('argon', 'global', 'transparency') + blur_opacity_dark = uci:get_first('argon', 'global', 'transparency_dark') + mode = uci:get_first('argon', 'global', 'mode') + bar_color = mode == 'dark' and dark_primary or primary + end + + -- Brand name + local brand_name = boardinfo.hostname or "?" +-%> + + + + + + + <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> + - LuCI + + + + + + + + + + + - LuCI"> + - LuCI"> + + + + + + + + + + + + + + + <% if node and node.css then %> + + <% end -%> + <% if css then %> + + <% end -%> + + + + + + + +"> + +
+ +
+
+
+
+ +
+
+
+
+
+
+
+ <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> +
+

<%:No password set!%>

+

<%:There is no password set on this router. Please configure a root password to protect the web interface.%> +

+ <% if disp.lookup("admin/system/admin") then %> + + <% end %> +
+ <%- end -%> + + + + diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header_login.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header_login.htm new file mode 100644 index 0000000..6fb30e5 --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/header_login.htm @@ -0,0 +1,119 @@ +<%# + Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material Argon Template + + luci-theme-argon + Copyright 2020 Jerrykuku + + Have a bug? Please create an issue here on GitHub! + https://github.com/jerrykuku/luci-theme-argon/issues + + luci-theme-material: + Copyright 2015 Lutty Yang + + Argon Theme + https://demos.creative-tim.com/argon-dashboard/index.html + + Licensed to the public under the Apache License 2.0 +-%> + +<% + local sys = require "luci.sys" + local util = require "luci.util" + local http = require "luci.http" + local disp = require "luci.dispatcher" + local ver = require "luci.version" + + local boardinfo = util.ubus("system", "board") + + local node = disp.context.dispatched + + local fs = require "nixio.fs" + local nutil = require "nixio.util" + local uci = require 'luci.model.uci'.cursor() + + -- send as HTML5 + http.prepare_content("text/html") + + math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 9))) + + -- Custom settings + local mode = 'normal' + local dark_css = fs.readfile('/www/luci-static/argon/css/dark.css') + local bar_color = '#5e72e4' + local primary, dark_primary, blur_radius, blur_radius_dark, blur_opacity + if fs.access('/etc/config/argon') then + primary = uci:get_first('argon', 'global', 'primary') + dark_primary = uci:get_first('argon', 'global', 'dark_primary') + blur_radius = uci:get_first('argon', 'global', 'blur') + blur_radius_dark = uci:get_first('argon', 'global', 'blur_dark') + blur_opacity = uci:get_first('argon', 'global', 'transparency') + blur_opacity_dark = uci:get_first('argon', 'global', 'transparency_dark') + mode = uci:get_first('argon', 'global', 'mode') + bar_color = mode == 'dark' and dark_primary or primary + end +-%> + + + + + + + <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> + - LuCI + + + + + + + + + + + - LuCI"> + - LuCI"> + + + + + + + + + + + + + + + <% if node and node.css then %> + + <% end -%> + <% if css then %> + + <% end -%> + + + + + diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/out_header_login.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/out_header_login.htm new file mode 100644 index 0000000..35e73ec --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/out_header_login.htm @@ -0,0 +1,14 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008-2019 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<% + local ver = require "luci.version" + + if not luci.dispatcher.context.template_header_sent then + include("themes/" .. theme .. "/header_login") + luci.dispatcher.context.template_header_sent = true + end +%> diff --git a/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/sysauth.htm b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/sysauth.htm new file mode 100644 index 0000000..1fb399b --- /dev/null +++ b/ipk-source/luci-theme-argon/root/usr/lib/lua/luci/view/themes/argon/sysauth.htm @@ -0,0 +1,163 @@ +<%# + Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-bootstrap and MUI and Argon Template + + luci-theme-argon + Copyright 2020 Jerryk + + Have a bug? Please create an issue here on GitHub! + https://github.com/jerrykuku/luci-theme-argon/issues + + luci-theme-bootstrap: + Copyright 2008 Steven Barth + Copyright 2008-2016 Jo-Philipp Wich + Copyright 2012 David Menting + + MUI: + https://github.com/muicss/mui + + Argon Theme + https://demos.creative-tim.com/argon-dashboard/index.html + + Licensed to the public under the Apache License 2.0 +-%> + +<%+themes/argon/out_header_login%> +<% + local util = require "luci.util" + local fs = require "nixio.fs" + local nutil = require "nixio.util" + local json = require "luci.jsonc" + local sys = require "luci.sys" + local uci = require 'luci.model.uci'.cursor() + + -- Fetch Local Background Media + + local function glob(...) + local iter, code, msg = fs.glob(...) + if iter then + return nutil.consume(iter) + else + return nil, code, msg + end + end + + + local imageTypes = " jpg png gif webp " + local videoTypes = " mp4 webm " + local allTypes = imageTypes .. videoTypes + local function fetchMedia(path, themeDir) + local backgroundTable = {} + local backgroundCount = 0 + for i, f in ipairs(glob(path)) do + attr = fs.stat(f) + if attr then + local ext = fs.basename(f):match(".+%.(%w+)$") + if ext ~= nil then + ext = ext:lower() + end + if ext ~= nil and string.match(allTypes, " "..ext.." ") ~= nil then + local bg = {} + bg.type = ext + bg.url = themeDir .. fs.basename(f) + table.insert(backgroundTable, bg) + backgroundCount = backgroundCount + 1 + end + end + end + return backgroundTable, backgroundCount + end + local function selectBackground(themeDir) + local bgUrl = media .. "/img/bg1.jpg" + local backgroundType = "Image" + local mimeType = "" + + if fs.access("/etc/config/argon") then + local online_wallpaper = uci:get_first('argon', 'global', 'online_wallpaper') or (uci:get_first('argon', 'global', 'bing_background') == '1' and 'bing') + if (online_wallpaper and online_wallpaper ~= "none") then + local picurl = sys.exec("/usr/libexec/argon/online_wallpaper") + if (picurl and picurl ~= '') then + return picurl, "Image", "" + end + end + end + + local backgroundTable, backgroundCount = fetchMedia("/www" .. themeDir .. "*", themeDir) + if ( backgroundCount > 0 ) then + local currentBg = backgroundTable[math.random(1, backgroundCount)] + bgUrl = currentBg.url + if (string.match(videoTypes, " "..currentBg.type.." ") ~= nil) then + backgroundType = "Video" + mimeType = "video/" .. currentBg.type + end + end + + return bgUrl, backgroundType, mimeType + end + + local boardinfo = util.ubus("system", "board") + local themeDir = media .. "/background/" + local bgUrl, backgroundType, mimeType = selectBackground(themeDir) +%> + +