From 293173f1a864b20e7156c129bca536b43f2bc77c Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 23 Dec 2008 21:57:11 +0000 Subject: [PATCH] branches/luci-0.8: remove bitrot --- applications/community-augsburg/ipkg/postinst | 4 - .../etc/uci-defaults/luci-community-augsburg | 16 - applications/community-berlin/ipkg/postinst | 4 - .../etc/uci-defaults/luci-community-berlin | 16 - applications/community-halle/ipkg/postinst | 4 - .../etc/uci-defaults/luci-community-halle | 19 - applications/community-hannover/ipkg/postinst | 4 - .../etc/uci-defaults/luci-community-hannover | 16 - applications/community-leipzig/ipkg/postinst | 4 - .../etc/uci-defaults/luci-community-leipzig | 19 - .../Makefile | 0 .../htdocs/cgi-bin-nodes.html | 10 + .../htdocs/cgi-bin-status.html | 10 + applications/freifunk-community/ipkg/postinst | 4 + .../etc/uci-defaults/luci-freifunk-community | 7 + .../Makefile | 0 .../luasrc/controller/asterisk.lua | 42 + .../luci-asterisk/luasrc/i18n/asterisk.en.lua | 251 ++ .../luci-asterisk/luasrc/i18n/asterisk.en.xml | 257 ++ .../luasrc/model/cbi/asterisk-dialplans.lua | 102 + .../model/cbi/asterisk-iax-connections.lua | 60 + .../luasrc/model/cbi/asterisk-meetme.lua | 33 + .../luasrc/model/cbi/asterisk-mod-app.lua | 391 ++ .../luasrc/model/cbi/asterisk-mod-cdr.lua | 58 + .../luasrc/model/cbi/asterisk-mod-chan.lua | 56 + .../luasrc/model/cbi/asterisk-mod-codec.lua | 64 + .../luasrc/model/cbi/asterisk-mod-format.lua | 100 + .../luasrc/model/cbi/asterisk-mod-func.lua | 40 + .../luasrc/model/cbi/asterisk-mod-pbx.lua | 64 + .../model/cbi/asterisk-mod-res-feature.lua | 111 + .../luasrc/model/cbi/asterisk-mod-res.lua | 88 + .../model/cbi/asterisk-sip-connections.lua | 109 + .../luasrc/model/cbi/asterisk-voice.lua | 52 + .../luasrc/model/cbi/asterisk.lua | 162 + .../luci-asterisk/root/etc/config/asterisk | 228 ++ .../root/lib/uci/schema/default/asterisk | 3625 +++++++++++++++++ .../Makefile | 0 .../luasrc/controller/coovachilli.lua | 29 + .../luasrc/i18n/coovachilli.en.lua | 177 + .../luasrc/i18n/coovachilli.en.xml | 190 + .../luasrc/model/cbi/coovachilli.lua | 31 + .../luasrc/model/cbi/coovachilli_auth.lua | 76 + .../luasrc/model/cbi/coovachilli_network.lua | 67 + .../luasrc/model/cbi/coovachilli_radius.lua | 67 + .../root/etc/config/coovachilli | 243 ++ .../root/lib/uci/schema/default/coovachilli | 642 +++ .../Makefile | 0 .../luasrc/controller/openvpn.lua | 24 + .../luci-openvpn/luasrc/i18n/openvpn.en.lua | 196 + .../luasrc/model/cbi/openvpn-advanced.lua | 271 ++ .../luasrc/model/cbi/openvpn-basic.lua | 102 + .../luci-openvpn/luasrc/model/cbi/openvpn.lua | 101 + .../view/openvpn/cbi-select-input-add.htm | 11 + .../luasrc/view/openvpn/pageswitch.htm | 39 + .../luci-openvpn/root/etc/config/openvpn | 383 ++ .../root/etc/config/openvpn_recipes | 95 + .../luci-openvpn/root/etc/init.d/openvpn | 144 + .../root/lib/uci/schema/default/openvpn | 299 ++ .../Makefile | 0 .../luasrc/controller/siitwizard.lua | 21 + .../luasrc/model/cbi/siitwizard.lua | 338 ++ .../luci-siitwizard/root/etc/config/siit | 10 + contrib/axtls/Makefile | 62 + contrib/axtls/files/axtls-config | 116 + contrib/axtls/files/axtls-config.h | 117 + contrib/axtls/patches/001-ld-fix.patch | 12 + contrib/axtls/patches/002-httpd-fix.patch | 12 + contrib/axtls/patches/003-content-type.patch | 37 + contrib/axtls/patches/004-cgi-nph-mode.patch | 20 + contrib/package/xrelayd/Makefile | 59 + .../httpd/hostfiles/www/index.html | 4 +- libs/lucittpd/Makefile | 18 + .../usr/lib/lucittpd/plugins/httpd.lua | 34 + libs/lucittpd/ipkg/postinst | 6 + libs/lucittpd/luasrc/ttpd/handler/file.lua | 252 ++ libs/lucittpd/luasrc/ttpd/module.lua | 121 + libs/lucittpd/luasrc/ttpd/server.lua | 444 ++ libs/lucittpd/root/etc/config/lucittpd | 6 + libs/lucittpd/root/etc/init.d/lucittpd | 44 + .../root/usr/lib/lucittpd/plugins/httpd.lua | 35 + libs/lucittpd/src/.gitignore | 1 + libs/lucittpd/src/Makefile | 20 + libs/lucittpd/src/include/lib/list.h | 601 +++ libs/lucittpd/src/include/lib/log.h | 24 + libs/lucittpd/src/include/lib/luaplugin.h | 71 + libs/lucittpd/src/include/lib/signal.h | 25 + libs/lucittpd/src/include/lib/uci.h | 54 + libs/lucittpd/src/include/uci.h | 543 +++ libs/lucittpd/src/include/uci_config.h | 3 + libs/lucittpd/src/lib/log.c | 45 + libs/lucittpd/src/lib/luaplugin.c | 383 ++ libs/lucittpd/src/lib/signal.c | 52 + libs/lucittpd/src/lib/uci.c | 206 + libs/lucittpd/src/main.c | 333 ++ .../usr/lib/lucittpd/plugins/luci-webui.lua | 29 + libs/sgi-luci/luasrc/ttpd/handler/luci.lua | 92 + libs/sgi-luci/root/etc/init.d/luci-httpd | 22 - libs/sgi-luci/root/usr/bin/luci-httpd | 31 - .../usr/lib/lucittpd/plugins/luci-webui.lua | 17 + libs/uvldoc/Makefile | 2 + .../luasrc/uvldoc/proto/xhtml/footer.xml | 11 + .../luasrc/uvldoc/proto/xhtml/header.xml | 15 + .../luasrc/uvldoc/proto/xhtml/index.xml | 12 + .../uvldoc/luasrc/uvldoc/proto/xhtml/menu.xml | 22 + .../luasrc/uvldoc/proto/xhtml/scheme.xml | 16 + .../luasrc/uvldoc/proto/xhtml/section.xml | 198 + .../luasrc/uvldoc/proto/xhtml/uvldoc.css | 135 + libs/uvldoc/luasrc/uvldoc/renderer.lua | 124 + .../luasrc/view/public_status/index.htm | 97 - themes/freifunk-bno/Makefile | 2 + .../luci-static/freifunk-bno/cascade.css | 726 ++++ .../freifunk-bno/images/bgoption.png | Bin 0 -> 141 bytes .../freifunk-bno/images/favicon.ico | Bin 0 -> 5310 bytes .../freifunk-bno/images/header-back.gif | Bin 0 -> 127 bytes .../freifunk-bno/images/header-left.gif | Bin 0 -> 293 bytes .../freifunk-bno/images/header-right.gif | Bin 0 -> 365 bytes .../luci-static/freifunk-bno/images/logo.gif | Bin 0 -> 2415 bytes .../freifunk-bno/images/main-back.png | Bin 0 -> 404 bytes .../freifunk-bno/images/schriftzug.gif | Bin 0 -> 3606 bytes themes/freifunk-bno/ipkg/postinst | 4 + .../view/themes/freifunk-bno/footer.htm | 29 + .../view/themes/freifunk-bno/header.htm | 196 + .../etc/uci-defaults/luci-theme-freifunk-bno | 6 + themes/freifunk/Makefile | 2 + .../htdocs/luci-static/freifunk/cascade.css | 726 ++++ .../luci-static/freifunk/images/bgoption.png | Bin 0 -> 141 bytes .../luci-static/freifunk/images/favicon.ico | Bin 0 -> 4286 bytes .../freifunk/images/header-back.gif | Bin 0 -> 127 bytes .../freifunk/images/header-left.gif | Bin 0 -> 293 bytes .../freifunk/images/header-right.gif | Bin 0 -> 365 bytes .../luci-static/freifunk/images/logo.png | Bin 0 -> 6400 bytes .../luci-static/freifunk/images/main-back.png | Bin 0 -> 404 bytes .../freifunk/images/schriftzug.png | Bin 0 -> 4487 bytes themes/freifunk/ipkg/postinst | 4 + .../luasrc/view/themes/freifunk/footer.htm | 29 + .../luasrc/view/themes/freifunk/header.htm | 196 + .../root/etc/uci-defaults/luci-theme-freifunk | 6 + themes/openwrt.org-oxygen/Makefile | 2 + .../luci-static/openwrt.org-oxygen/bg.jpg | Bin 0 -> 40537 bytes .../openwrt.org-oxygen/cascade.css | 803 ++++ .../openwrt.org-oxygen/dashboard.css | 99 + .../luci-static/openwrt.org-oxygen/header.png | Bin 0 -> 33244 bytes .../openwrt.org-oxygen/icons/COPYING.oxygen | 48 + .../openwrt.org-oxygen/icons/datetime.png | Bin 0 -> 5250 bytes .../openwrt.org-oxygen/icons/default.png | Bin 0 -> 5022 bytes .../openwrt.org-oxygen/icons/desktop.png | Bin 0 -> 6487 bytes .../openwrt.org-oxygen/icons/flash.png | Bin 0 -> 5065 bytes .../openwrt.org-oxygen/icons/freifunk.png | Bin 0 -> 2404 bytes .../openwrt.org-oxygen/icons/harddisk.png | Bin 0 -> 3317 bytes .../openwrt.org-oxygen/icons/key.png | Bin 0 -> 4129 bytes .../openwrt.org-oxygen/icons/lightbulb.png | Bin 0 -> 5550 bytes .../openwrt.org-oxygen/icons/login.png | Bin 0 -> 2918 bytes .../openwrt.org-oxygen/icons/logout.png | Bin 0 -> 3577 bytes .../openwrt.org-oxygen/icons/network.png | Bin 0 -> 6602 bytes .../openwrt.org-oxygen/icons/overview.png | Bin 0 -> 4553 bytes .../openwrt.org-oxygen/icons/package.png | Bin 0 -> 4996 bytes .../openwrt.org-oxygen/icons/restart.png | Bin 0 -> 4081 bytes .../openwrt.org-oxygen/icons/services.png | Bin 0 -> 4630 bytes .../openwrt.org-oxygen/icons/shell.png | Bin 0 -> 2110 bytes .../openwrt.org-oxygen/icons/stats.png | Bin 0 -> 3102 bytes .../openwrt.org-oxygen/icons/status.png | Bin 0 -> 3192 bytes .../openwrt.org-oxygen/icons/switch.png | Bin 0 -> 3940 bytes .../openwrt.org-oxygen/icons/system.png | Bin 0 -> 6296 bytes .../openwrt.org-oxygen/icons/worker.png | Bin 0 -> 4630 bytes .../luci-static/openwrt.org-oxygen/ie6.css | 77 + .../luci-static/openwrt.org-oxygen/ie7.css | 20 + themes/openwrt.org-oxygen/ipkg/postinst | 4 + .../themes/openwrt.org-oxygen/dashboard.htm | 46 + .../view/themes/openwrt.org-oxygen/footer.htm | 21 + .../view/themes/openwrt.org-oxygen/header.htm | 166 + .../themes/openwrt.org-oxygen/indexer.htm | 17 + .../uci-defaults/luci-theme-openwrt-oxygen | 6 + themes/oxygen/Makefile | 2 + .../oxygen/htdocs/luci-static/oxygen/bg.png | Bin 0 -> 40400 bytes .../htdocs/luci-static/oxygen/cascade.css | 664 +++ .../htdocs/luci-static/oxygen/dashboard.css | 99 + .../htdocs/luci-static/oxygen/footer.png | Bin 0 -> 61400 bytes .../htdocs/luci-static/oxygen/header.png | Bin 0 -> 33244 bytes .../luci-static/oxygen/icons/COPYING.oxygen | 48 + .../luci-static/oxygen/icons/datetime.png | Bin 0 -> 5250 bytes .../luci-static/oxygen/icons/default.png | Bin 0 -> 5022 bytes .../luci-static/oxygen/icons/desktop.png | Bin 0 -> 6487 bytes .../htdocs/luci-static/oxygen/icons/flash.png | Bin 0 -> 5065 bytes .../luci-static/oxygen/icons/freifunk.png | Bin 0 -> 2404 bytes .../luci-static/oxygen/icons/harddisk.png | Bin 0 -> 3317 bytes .../htdocs/luci-static/oxygen/icons/key.png | Bin 0 -> 4129 bytes .../luci-static/oxygen/icons/lightbulb.png | Bin 0 -> 5550 bytes .../htdocs/luci-static/oxygen/icons/login.png | Bin 0 -> 2918 bytes .../luci-static/oxygen/icons/logout.png | Bin 0 -> 3577 bytes .../luci-static/oxygen/icons/network.png | Bin 0 -> 6602 bytes .../luci-static/oxygen/icons/overview.png | Bin 0 -> 4553 bytes .../luci-static/oxygen/icons/package.png | Bin 0 -> 4996 bytes .../luci-static/oxygen/icons/restart.png | Bin 0 -> 4081 bytes .../luci-static/oxygen/icons/services.png | Bin 0 -> 4630 bytes .../htdocs/luci-static/oxygen/icons/shell.png | Bin 0 -> 2110 bytes .../htdocs/luci-static/oxygen/icons/stats.png | Bin 0 -> 3102 bytes .../luci-static/oxygen/icons/status.png | Bin 0 -> 3192 bytes .../luci-static/oxygen/icons/switch.png | Bin 0 -> 3940 bytes .../luci-static/oxygen/icons/system.png | Bin 0 -> 6296 bytes .../luci-static/oxygen/icons/worker.png | Bin 0 -> 4630 bytes themes/oxygen/ipkg/postinst | 4 + .../luasrc/view/themes/oxygen/dashboard.htm | 46 + .../luasrc/view/themes/oxygen/footer.htm | 22 + .../luasrc/view/themes/oxygen/header.htm | 130 + .../luasrc/view/themes/oxygen/indexer.htm | 17 + .../root/etc/uci-defaults/luci-theme-oxygen | 6 + 206 files changed, 18184 insertions(+), 258 deletions(-) delete mode 100644 applications/community-augsburg/ipkg/postinst delete mode 100644 applications/community-augsburg/root/etc/uci-defaults/luci-community-augsburg delete mode 100755 applications/community-berlin/ipkg/postinst delete mode 100644 applications/community-berlin/root/etc/uci-defaults/luci-community-berlin delete mode 100755 applications/community-halle/ipkg/postinst delete mode 100644 applications/community-halle/root/etc/uci-defaults/luci-community-halle delete mode 100755 applications/community-hannover/ipkg/postinst delete mode 100644 applications/community-hannover/root/etc/uci-defaults/luci-community-hannover delete mode 100755 applications/community-leipzig/ipkg/postinst delete mode 100644 applications/community-leipzig/root/etc/uci-defaults/luci-community-leipzig rename applications/{community-augsburg => freifunk-community}/Makefile (100%) create mode 100644 applications/freifunk-community/htdocs/cgi-bin-nodes.html create mode 100644 applications/freifunk-community/htdocs/cgi-bin-status.html create mode 100755 applications/freifunk-community/ipkg/postinst create mode 100644 applications/freifunk-community/root/etc/uci-defaults/luci-freifunk-community rename applications/{community-berlin => luci-asterisk}/Makefile (100%) create mode 100644 applications/luci-asterisk/luasrc/controller/asterisk.lua create mode 100644 applications/luci-asterisk/luasrc/i18n/asterisk.en.lua create mode 100644 applications/luci-asterisk/luasrc/i18n/asterisk.en.xml create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-dialplans.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-iax-connections.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-meetme.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-app.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-cdr.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-chan.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-codec.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-format.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-func.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-pbx.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res-feature.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-sip-connections.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk-voice.lua create mode 100644 applications/luci-asterisk/luasrc/model/cbi/asterisk.lua create mode 100644 applications/luci-asterisk/root/etc/config/asterisk create mode 100644 applications/luci-asterisk/root/lib/uci/schema/default/asterisk rename applications/{community-halle => luci-coovachilli}/Makefile (100%) create mode 100644 applications/luci-coovachilli/luasrc/controller/coovachilli.lua create mode 100644 applications/luci-coovachilli/luasrc/i18n/coovachilli.en.lua create mode 100644 applications/luci-coovachilli/luasrc/i18n/coovachilli.en.xml create mode 100644 applications/luci-coovachilli/luasrc/model/cbi/coovachilli.lua create mode 100644 applications/luci-coovachilli/luasrc/model/cbi/coovachilli_auth.lua create mode 100644 applications/luci-coovachilli/luasrc/model/cbi/coovachilli_network.lua create mode 100644 applications/luci-coovachilli/luasrc/model/cbi/coovachilli_radius.lua create mode 100644 applications/luci-coovachilli/root/etc/config/coovachilli create mode 100644 applications/luci-coovachilli/root/lib/uci/schema/default/coovachilli rename applications/{community-hannover => luci-openvpn}/Makefile (100%) create mode 100644 applications/luci-openvpn/luasrc/controller/openvpn.lua create mode 100644 applications/luci-openvpn/luasrc/i18n/openvpn.en.lua create mode 100644 applications/luci-openvpn/luasrc/model/cbi/openvpn-advanced.lua create mode 100644 applications/luci-openvpn/luasrc/model/cbi/openvpn-basic.lua create mode 100644 applications/luci-openvpn/luasrc/model/cbi/openvpn.lua create mode 100644 applications/luci-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm create mode 100644 applications/luci-openvpn/luasrc/view/openvpn/pageswitch.htm create mode 100644 applications/luci-openvpn/root/etc/config/openvpn create mode 100644 applications/luci-openvpn/root/etc/config/openvpn_recipes create mode 100644 applications/luci-openvpn/root/etc/init.d/openvpn create mode 100644 applications/luci-openvpn/root/lib/uci/schema/default/openvpn rename applications/{community-leipzig => luci-siitwizard}/Makefile (100%) create mode 100644 applications/luci-siitwizard/luasrc/controller/siitwizard.lua create mode 100644 applications/luci-siitwizard/luasrc/model/cbi/siitwizard.lua create mode 100644 applications/luci-siitwizard/root/etc/config/siit create mode 100644 contrib/axtls/Makefile create mode 100644 contrib/axtls/files/axtls-config create mode 100644 contrib/axtls/files/axtls-config.h create mode 100644 contrib/axtls/patches/001-ld-fix.patch create mode 100644 contrib/axtls/patches/002-httpd-fix.patch create mode 100644 contrib/axtls/patches/003-content-type.patch create mode 100644 contrib/axtls/patches/004-cgi-nph-mode.patch create mode 100644 contrib/package/xrelayd/Makefile rename modules/freifunk/htdocs/cgi-bin-nodes.html => libs/httpd/hostfiles/www/index.html (60%) create mode 100644 libs/lucittpd/Makefile create mode 100644 libs/lucittpd/hostfiles/usr/lib/lucittpd/plugins/httpd.lua create mode 100755 libs/lucittpd/ipkg/postinst create mode 100644 libs/lucittpd/luasrc/ttpd/handler/file.lua create mode 100644 libs/lucittpd/luasrc/ttpd/module.lua create mode 100644 libs/lucittpd/luasrc/ttpd/server.lua create mode 100644 libs/lucittpd/root/etc/config/lucittpd create mode 100755 libs/lucittpd/root/etc/init.d/lucittpd create mode 100644 libs/lucittpd/root/usr/lib/lucittpd/plugins/httpd.lua create mode 100644 libs/lucittpd/src/.gitignore create mode 100644 libs/lucittpd/src/Makefile create mode 100644 libs/lucittpd/src/include/lib/list.h create mode 100644 libs/lucittpd/src/include/lib/log.h create mode 100644 libs/lucittpd/src/include/lib/luaplugin.h create mode 100644 libs/lucittpd/src/include/lib/signal.h create mode 100644 libs/lucittpd/src/include/lib/uci.h create mode 100644 libs/lucittpd/src/include/uci.h create mode 100644 libs/lucittpd/src/include/uci_config.h create mode 100644 libs/lucittpd/src/lib/log.c create mode 100644 libs/lucittpd/src/lib/luaplugin.c create mode 100644 libs/lucittpd/src/lib/signal.c create mode 100644 libs/lucittpd/src/lib/uci.c create mode 100644 libs/lucittpd/src/main.c create mode 100644 libs/sgi-luci/hostfiles/usr/lib/lucittpd/plugins/luci-webui.lua create mode 100644 libs/sgi-luci/luasrc/ttpd/handler/luci.lua delete mode 100755 libs/sgi-luci/root/etc/init.d/luci-httpd delete mode 100755 libs/sgi-luci/root/usr/bin/luci-httpd create mode 100644 libs/sgi-luci/root/usr/lib/lucittpd/plugins/luci-webui.lua create mode 100644 libs/uvldoc/Makefile create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/footer.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/header.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/index.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/menu.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/scheme.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/section.xml create mode 100644 libs/uvldoc/luasrc/uvldoc/proto/xhtml/uvldoc.css create mode 100644 libs/uvldoc/luasrc/uvldoc/renderer.lua delete mode 100644 modules/freifunk/luasrc/view/public_status/index.htm create mode 100644 themes/freifunk-bno/Makefile create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/cascade.css create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/bgoption.png create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/favicon.ico create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-back.gif create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-left.gif create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-right.gif create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/logo.gif create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/main-back.png create mode 100644 themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/schriftzug.gif create mode 100755 themes/freifunk-bno/ipkg/postinst create mode 100644 themes/freifunk-bno/luasrc/view/themes/freifunk-bno/footer.htm create mode 100644 themes/freifunk-bno/luasrc/view/themes/freifunk-bno/header.htm create mode 100755 themes/freifunk-bno/root/etc/uci-defaults/luci-theme-freifunk-bno create mode 100644 themes/freifunk/Makefile create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/cascade.css create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/bgoption.png create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/favicon.ico create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/header-back.gif create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/header-left.gif create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/header-right.gif create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/logo.png create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/main-back.png create mode 100644 themes/freifunk/htdocs/luci-static/freifunk/images/schriftzug.png create mode 100755 themes/freifunk/ipkg/postinst create mode 100644 themes/freifunk/luasrc/view/themes/freifunk/footer.htm create mode 100644 themes/freifunk/luasrc/view/themes/freifunk/header.htm create mode 100755 themes/freifunk/root/etc/uci-defaults/luci-theme-freifunk create mode 100644 themes/openwrt.org-oxygen/Makefile create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/bg.jpg create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/cascade.css create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/dashboard.css create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/header.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/COPYING.oxygen create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/datetime.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/default.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/desktop.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/flash.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/freifunk.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/harddisk.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/key.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/lightbulb.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/login.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/logout.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/network.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/overview.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/package.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/restart.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/services.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/shell.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/stats.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/status.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/switch.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/system.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/worker.png create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie6.css create mode 100644 themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie7.css create mode 100755 themes/openwrt.org-oxygen/ipkg/postinst create mode 100644 themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/dashboard.htm create mode 100644 themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/footer.htm create mode 100644 themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/header.htm create mode 100644 themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/indexer.htm create mode 100755 themes/openwrt.org-oxygen/root/etc/uci-defaults/luci-theme-openwrt-oxygen create mode 100644 themes/oxygen/Makefile create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/bg.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/cascade.css create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/dashboard.css create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/footer.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/header.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/COPYING.oxygen create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/datetime.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/default.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/desktop.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/flash.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/freifunk.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/harddisk.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/key.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/lightbulb.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/login.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/logout.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/network.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/overview.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/package.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/restart.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/services.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/shell.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/stats.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/status.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/switch.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/system.png create mode 100644 themes/oxygen/htdocs/luci-static/oxygen/icons/worker.png create mode 100755 themes/oxygen/ipkg/postinst create mode 100644 themes/oxygen/luasrc/view/themes/oxygen/dashboard.htm create mode 100644 themes/oxygen/luasrc/view/themes/oxygen/footer.htm create mode 100644 themes/oxygen/luasrc/view/themes/oxygen/header.htm create mode 100644 themes/oxygen/luasrc/view/themes/oxygen/indexer.htm create mode 100755 themes/oxygen/root/etc/uci-defaults/luci-theme-oxygen diff --git a/applications/community-augsburg/ipkg/postinst b/applications/community-augsburg/ipkg/postinst deleted file mode 100644 index b99b7c17c1..0000000000 --- a/applications/community-augsburg/ipkg/postinst +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -[ -n "${IPKG_INSTROOT}" ] || { - ( . /etc/uci-defaults/luci-community-augsburg ) && rm -f /etc/uci-defaults/luci-community-augsburg -} diff --git a/applications/community-augsburg/root/etc/uci-defaults/luci-community-augsburg b/applications/community-augsburg/root/etc/uci-defaults/luci-community-augsburg deleted file mode 100644 index b1efd46de4..0000000000 --- a/applications/community-augsburg/root/etc/uci-defaults/luci-community-augsburg +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set freifunk.community.name='Freifunk Augsburg' - set freifunk.community.homepage=http://augsburg.freifunk.net - set freifunk.community.essid=augsburg.freifunk.net - set freifunk.community.bssid=02:CA:FF:EE:BA:BE - set freifunk.community.channel=1 - set freifunk.community.net=191.161.0.0 - set freifunk.community.mask=255.255.0.0 - set freifunk.community.dns='88.198.178.18 141.54.1.1 212.204.49.83 208.67.220.220 208.67.222.222' - set luci.main.mediaurlbase=/luci-static/fledermaus - set luci.main.lang=de - commit freifunk - commit luci -EOF - diff --git a/applications/community-berlin/ipkg/postinst b/applications/community-berlin/ipkg/postinst deleted file mode 100755 index ad5e96c3ec..0000000000 --- a/applications/community-berlin/ipkg/postinst +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -[ -n "${IPKG_INSTROOT}" ] || { - ( . /etc/uci-defaults/luci-community-berlin ) && rm -f /etc/uci-defaults/luci-community-berlin -} diff --git a/applications/community-berlin/root/etc/uci-defaults/luci-community-berlin b/applications/community-berlin/root/etc/uci-defaults/luci-community-berlin deleted file mode 100644 index 348b0c8e93..0000000000 --- a/applications/community-berlin/root/etc/uci-defaults/luci-community-berlin +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set freifunk.community.name='Freifunk Berlin' - set freifunk.community.homepage=http://berlin.freifunk.net - set freifunk.community.essid=olsr.freifunk.net - set freifunk.community.bssid=02:CA:FF:EE:BA:BE - set freifunk.community.channel=10 - set freifunk.community.net=104.0.0.0 - set freifunk.community.mask=255.0.0.0 - set freifunk.community.dns='88.198.178.18 141.54.1.1 212.204.49.83 208.67.220.220 208.67.222.222' - set luci.main.mediaurlbase=/luci-static/fledermaus - set luci.main.lang=de - commit freifunk - commit luci -EOF - diff --git a/applications/community-halle/ipkg/postinst b/applications/community-halle/ipkg/postinst deleted file mode 100755 index 0efb5a9a75..0000000000 --- a/applications/community-halle/ipkg/postinst +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -[ -n "${IPKG_INSTROOT}" ] || { - ( . /etc/uci-defaults/luci-community-halle ) && rm -f /etc/uci-defaults/luci-community-halle -} diff --git a/applications/community-halle/root/etc/uci-defaults/luci-community-halle b/applications/community-halle/root/etc/uci-defaults/luci-community-halle deleted file mode 100644 index 86df828b7e..0000000000 --- a/applications/community-halle/root/etc/uci-defaults/luci-community-halle +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set freifunk.community.name='Freifunk Halle' - set freifunk.community.homepage=http://halle.freifunk.net - set freifunk.community.essid=halle.freifunk.net - set freifunk.community.bssid=02:CA:FF:EE:BA:BE - set freifunk.community.realm=pool.freifunk-halle.net - set freifunk.community.channel=1 - set freifunk.community.net=104.0.0.0 - set freifunk.community.mask=255.0.0.0 - set freifunk.community.dhcp=10.0.0.0 - set freifunk.community.dhcpmask=255.255.255.0 - set freifunk.community.dns='88.198.178.18 141.54.1.1 212.204.49.83 208.67.220.220 208.67.222.222' - set luci.main.mediaurlbase=/luci-static/fledermaus - set luci.main.lang=de - commit freifunk - commit luci -EOF - diff --git a/applications/community-hannover/ipkg/postinst b/applications/community-hannover/ipkg/postinst deleted file mode 100755 index b41179f72c..0000000000 --- a/applications/community-hannover/ipkg/postinst +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -[ -n "${IPKG_INSTROOT}" ] || { - ( . /etc/uci-defaults/luci-community-hannover ) && rm -f /etc/uci-defaults/luci-community-hannover -} diff --git a/applications/community-hannover/root/etc/uci-defaults/luci-community-hannover b/applications/community-hannover/root/etc/uci-defaults/luci-community-hannover deleted file mode 100644 index b9ae372922..0000000000 --- a/applications/community-hannover/root/etc/uci-defaults/luci-community-hannover +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set freifunk.community.name='Freifunk Hannover' - set freifunk.community.homepage=http://www.freifunk-hannover.de - set freifunk.community.essid=hannover.freifunk.net - set freifunk.community.bssid=CA:FF:EE:CA:FF:EE - set freifunk.community.realm=db.freifunk-hannover.de - set freifunk.community.channel=1 - set freifunk.community.net=10.2.0.0 - set freifunk.community.mask=255.255.0.0 - set luci.main.mediaurlbase=/luci-static/fledermaus - set luci.main.lang=de - commit freifunk - commit luci -EOF - diff --git a/applications/community-leipzig/ipkg/postinst b/applications/community-leipzig/ipkg/postinst deleted file mode 100755 index 5aff5db958..0000000000 --- a/applications/community-leipzig/ipkg/postinst +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -[ -n "${IPKG_INSTROOT}" ] || { - ( . /etc/uci-defaults/luci-community-leipzig ) && rm -f /etc/uci-defaults/luci-community-leipzig -} diff --git a/applications/community-leipzig/root/etc/uci-defaults/luci-community-leipzig b/applications/community-leipzig/root/etc/uci-defaults/luci-community-leipzig deleted file mode 100644 index c94dc4ace8..0000000000 --- a/applications/community-leipzig/root/etc/uci-defaults/luci-community-leipzig +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set freifunk.community.name='Freifunk Leipzig' - set freifunk.community.homepage=http://leipzig.freifunk.net - set freifunk.community.essid=leipzig.freifunk.net - set freifunk.community.bssid=02:CA:FF:EE:BA:BE - set freifunk.community.realm=db.leipzig.freifunk.net - set freifunk.community.channel=1 - set freifunk.community.net=104.0.0.0 - set freifunk.community.mask=255.0.0.0 - set freifunk.community.dhcp=10.0.0.0 - set freifunk.community.dhcpmask=255.255.255.0 - set freifunk.community.dns='88.198.178.18 141.54.1.1 212.204.49.83 208.67.220.220 208.67.222.222' - set luci.main.mediaurlbase=/luci-static/fledermaus - set luci.main.lang=de - commit freifunk - commit luci -EOF - \ No newline at end of file diff --git a/applications/community-augsburg/Makefile b/applications/freifunk-community/Makefile similarity index 100% rename from applications/community-augsburg/Makefile rename to applications/freifunk-community/Makefile diff --git a/applications/freifunk-community/htdocs/cgi-bin-nodes.html b/applications/freifunk-community/htdocs/cgi-bin-nodes.html new file mode 100644 index 0000000000..8dd86b0f99 --- /dev/null +++ b/applications/freifunk-community/htdocs/cgi-bin-nodes.html @@ -0,0 +1,10 @@ + + + + + + + +LuCI - Lua Configuration Interface + + diff --git a/applications/freifunk-community/htdocs/cgi-bin-status.html b/applications/freifunk-community/htdocs/cgi-bin-status.html new file mode 100644 index 0000000000..8dd86b0f99 --- /dev/null +++ b/applications/freifunk-community/htdocs/cgi-bin-status.html @@ -0,0 +1,10 @@ + + + + + + + +LuCI - Lua Configuration Interface + + diff --git a/applications/freifunk-community/ipkg/postinst b/applications/freifunk-community/ipkg/postinst new file mode 100755 index 0000000000..c16bc3af40 --- /dev/null +++ b/applications/freifunk-community/ipkg/postinst @@ -0,0 +1,4 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + ( . /etc/uci-defaults/luci-freifunk-community ) && rm -f /etc/uci-defaults/luci-freifunk-community +} diff --git a/applications/freifunk-community/root/etc/uci-defaults/luci-freifunk-community b/applications/freifunk-community/root/etc/uci-defaults/luci-freifunk-community new file mode 100644 index 0000000000..d6d40f0284 --- /dev/null +++ b/applications/freifunk-community/root/etc/uci-defaults/luci-freifunk-community @@ -0,0 +1,7 @@ +#!/bin/sh +uci batch <<-EOF + set luci.main.mediaurlbase=/luci-static/fledermaus + set luci.main.lang=de + commit luci +EOF + diff --git a/applications/community-berlin/Makefile b/applications/luci-asterisk/Makefile similarity index 100% rename from applications/community-berlin/Makefile rename to applications/luci-asterisk/Makefile diff --git a/applications/luci-asterisk/luasrc/controller/asterisk.lua b/applications/luci-asterisk/luasrc/controller/asterisk.lua new file mode 100644 index 0000000000..4ba3f2e8a2 --- /dev/null +++ b/applications/luci-asterisk/luasrc/controller/asterisk.lua @@ -0,0 +1,42 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +module("luci.controller.asterisk", package.seeall) + +function index() + + entry({"admin", "services", "asterisk"}, cbi("asterisk"), "Asterisk", 80).i18n = "asterisk" + + entry({"admin", "services", "asterisk", "voice"}, cbi("asterisk-voice"), "Voice Functions", 1) + entry({"admin", "services", "asterisk", "meetme"}, cbi("asterisk-meetme"), "Meetme Conferences", 2) + + entry({"admin", "services", "asterisk", "iax-conns"}, cbi("asterisk-iax-connections"), "IAX Connections", 3) + entry({"admin", "services", "asterisk", "sip-conns"}, cbi("asterisk-sip-connections"), "SIP Connections", 4) + + entry({"admin", "services", "asterisk", "dialplans"}, cbi("asterisk-dialplans"), "Dial Plans", 5) + + entry({"admin", "services", "asterisk", "mod"}, cbi("asterisk-mod-app"), "Modules", 4) + entry({"admin", "services", "asterisk", "mod", "app"}, cbi("asterisk-mod-app"), "Applications", 1) + entry({"admin", "services", "asterisk", "mod", "cdr"}, cbi("asterisk-mod-cdr"), "Call Detail Records", 2) + entry({"admin", "services", "asterisk", "mod", "chan"}, cbi("asterisk-mod-chan"), "Channels", 3) + entry({"admin", "services", "asterisk", "mod", "codec"}, cbi("asterisk-mod-codec"), "Codecs", 4) + entry({"admin", "services", "asterisk", "mod", "format"}, cbi("asterisk-mod-format"), "Format", 5) + entry({"admin", "services", "asterisk", "mod", "func"}, cbi("asterisk-mod-func"), "Functions", 6) + entry({"admin", "services", "asterisk", "mod", "pbx"}, cbi("asterisk-mod-pbx"), "PBX", 7) + entry({"admin", "services", "asterisk", "mod", "res"}, cbi("asterisk-mod-res"), "Resources", 8) + entry({"admin", "services", "asterisk", "mod", "res", "feature"}, + cbi("asterisk-mod-res-feature"), "Feature Module Configuration", 9 ) + +end diff --git a/applications/luci-asterisk/luasrc/i18n/asterisk.en.lua b/applications/luci-asterisk/luasrc/i18n/asterisk.en.lua new file mode 100644 index 0000000000..aa5796b4af --- /dev/null +++ b/applications/luci-asterisk/luasrc/i18n/asterisk.en.lua @@ -0,0 +1,251 @@ +asterisk_asterisk = 'Asterisk General Options' +asterisk_asterisk_agidir = 'AGI directory' +asterisk_asterisk_cacherecordfiles = 'Cache recorded sound files during recording' +asterisk_asterisk_debug = 'Debug Level' +asterisk_asterisk_dontwarn = 'Disable some warnings' +asterisk_asterisk_dumpcore = 'Dump core on crash' +asterisk_asterisk_highpriority = 'High Priority' +asterisk_asterisk_initcrypto = 'Initialise Crypto' +asterisk_asterisk_internaltiming = 'Use Internal Timing' +asterisk_asterisk_logdir = 'Log directory' +asterisk_asterisk_maxcalls = 'Maximum number of calls allowed' +asterisk_asterisk_maxload = 'Maximum load to stop accepting new calls' +asterisk_asterisk_nocolor = 'Disable console colors' +asterisk_asterisk_recordcachedir = 'Sound files Cache directory' +asterisk_asterisk_rungroup = 'The Group to run as' +asterisk_asterisk_runuser = 'The User to run as' +asterisk_asterisk_spooldir = 'Voicemail Spool directory' +asterisk_asterisk_systemname = 'Prefix UniquID with system name' +asterisk_asterisk_transcodeviasln = 'Build transcode paths via SLINEAR, not directly' +asterisk_asterisk_transmitsilenceduringrecord = 'Transmit SLINEAR silence while recording a channel' +asterisk_asterisk_verbose = 'Verbose Level' +asterisk_asterisk_zone = 'Time Zone' +asterisk_dialplan = 'Section dialplan' +asterisk_dialplan_include = 'include' +asterisk_dialplanexten = 'Dialplan Extension' +asterisk_dialplangeneral = 'Dialplan General Options' +asterisk_dialplangeneral_allowtransfer = 'Allow transfer' +asterisk_dialplangeneral_canreinvite = 'Reinvite/redirect media connections' +asterisk_dialplangeneral_clearglobalvars = 'Clear global vars' +asterisk_dialplangoto = 'Dialplan Goto' +asterisk_dialplanmeetme = 'Dialplan Conference' +asterisk_dialplansaytime = 'Dialplan Time' +asterisk_dialplanvoice = 'Dialplan Voicemail' +asterisk_dialzone = 'Dial Zones for Dialplan' +asterisk_dialzone_addprefix = 'Prefix to add matching dialplans' +asterisk_dialzone_international = 'Match International prefix' +asterisk_dialzone_localprefix = 'Prefix (0) to add/remove to/from international numbers' +asterisk_dialzone_localzone = 'localzone' +asterisk_dialzone_match = 'Match plan' +asterisk_dialzone_uses = 'Connection to use' +asterisk_featuremap = 'Feature Key maps' +asterisk_featuremap_atxfer = 'Attended transfer key' +asterisk_featuremap_blindxfer = 'Blind transfer key' +asterisk_featuremap_disconnect = 'Key to Disconnect call' +asterisk_featuremap_parkcall = 'Key to Park call' +asterisk_featurepark = 'Parking Feature' +asterisk_featurepark_adsipark = 'ADSI Park' +asterisk_featurepark_atxfernoanswertimeout = 'Attended transfer timeout (sec)' +asterisk_featurepark_automon = 'One touch record key' +asterisk_featurepark_context = 'Name of call context for parking' +asterisk_featurepark_courtesytone = 'Sound file to play to parked caller' +asterisk_featurepark_featuredigittimeout = 'Max time (ms) between digits for feature activation' +asterisk_featurepark_findslot = 'Method to Find Parking slot' +asterisk_featurepark_parkedmusicclass = 'parkedmusicclass' +asterisk_featurepark_parkedplay = 'Play courtesy tone to' +asterisk_featurepark_parkenabled = 'Enable Parking' +asterisk_featurepark_parkext = 'Extension to dial to park' +asterisk_featurepark_parkingtime = 'Parking time (secs)' +asterisk_featurepark_parkpos = 'Range of extensions for call parking' +asterisk_featurepark_pickupexten = 'Pickup extension' +asterisk_featurepark_transferdigittimeout = 'Seconds to wait bewteen digits when transferring' +asterisk_featurepark_xferfailsound = 'sound when attended transfer is complete' +asterisk_featurepark_xfersound = 'Sound when attended transfer fails' +asterisk_hardwarereboot = 'Reload Hardware Config' +asterisk_hardwarereboot_method = 'Reboot Method' +asterisk_hardwarereboot_param = 'Parameter' +asterisk_iax = 'SIP Connection' +asterisk_iax_alwaysinternational = 'Always Dial International' +asterisk_iax_context = 'context' +asterisk_iax_countrycode = 'Country Code for connection' +asterisk_iax_extension = 'Add as Extension' +asterisk_iax_host = 'Host name (or blank)' +asterisk_iax_internationalprefix = 'International Dial Prefix' +asterisk_iax_prefix = 'Dial Prefix (for external line)' +asterisk_iax_secret = 'Secret' +asterisk_iax_timeout = 'Dial Timeout (sec)' +asterisk_iax_type = 'Option type' +asterisk_iax_username = 'User name' +asterisk_iaxgeneral = 'IAX General Options' +asterisk_iaxgeneral_allow = 'Allow Codecs' +asterisk_iaxgeneral_canreinvite = 'Reinvite/redirect media connections' +asterisk_iaxgeneral_static = 'Static' +asterisk_iaxgeneral_writeprotect = 'Write Protect' +asterisk_meetme = 'Meetme Conference' +asterisk_meetme_adminpin = 'Admin PIN' +asterisk_meetme_pin = 'Meeting PIN' +asterisk_meetmegeneral = 'Meetme Conference General Options' +asterisk_meetmegeneral_audiobuffers = 'Number of 20ms audio buffers to be used' +asterisk_module = 'Modules' +asterisk_module_appalarmreceiver = 'Alarm Receiver Application' +asterisk_module_appauthenticate = 'Authentication Application' +asterisk_module_appcdr = 'Make sure asterisk doesnt save CDR' +asterisk_module_appchanisavail = 'Check if channel is available' +asterisk_module_appchanspy = 'Listen in on any channel' +asterisk_module_appcontrolplayback = 'Control Playback Application' +asterisk_module_appcut = 'Cuts up variables' +asterisk_module_appdb = 'Database access functions' +asterisk_module_appdial = 'Dialing Application' +asterisk_module_appdictate = 'Virtual Dictation Machine Application' +asterisk_module_appdirectedpickup = 'Directed Call Pickup Support' +asterisk_module_appdirectory = 'Extension Directory' +asterisk_module_appdisa = 'DISA (Direct Inward System Access) Application' +asterisk_module_appdumpchan = 'Dump channel variables Application' +asterisk_module_appecho = 'Simple Echo Application' +asterisk_module_appenumlookup = 'ENUM Lookup' +asterisk_module_appeval = 'Reevaluates strings' +asterisk_module_appexec = 'Executes applications' +asterisk_module_appexternalivr = 'External IVR application interface' +asterisk_module_appforkcdr = 'Fork The CDR into 2 seperate entities' +asterisk_module_appgetcpeid = 'Get ADSI CPE ID' +asterisk_module_appgroupcount = 'Group Management Routines' +asterisk_module_appices = 'Encode and Stream via icecast and ices' +asterisk_module_appimage = 'Image Transmission Application' +asterisk_module_applookupblacklist = 'Look up Caller*ID name/number from black' +asterisk_module_applookupcidname = 'Look up CallerID Name from local databas' +asterisk_module_appmacro = 'Extension Macros' +asterisk_module_appmath = 'A simple math Application' +asterisk_module_appmd5 = 'MD5 checksum Application' +asterisk_module_appmilliwatt = 'Digital Milliwatt (mu-law) Test Application' +asterisk_module_appmixmonitor = 'Record a call and mix the audio during the recording' +asterisk_module_appparkandannounce = 'Call Parking and Announce Application' +asterisk_module_appplayback = 'Trivial Playback Application' +asterisk_module_appprivacy = 'Require phone number to be entered' +asterisk_module_appqueue = 'True Call Queueing' +asterisk_module_apprandom = 'Random goto' +asterisk_module_appread = 'Read Variable Application' +asterisk_module_appreadfile = 'Read in a file' +asterisk_module_apprealtime = 'Realtime Data Lookup/Rewrite' +asterisk_module_apprecord = 'Trivial Record Application' +asterisk_module_appsayunixtime = 'Say time' +asterisk_module_appsenddtmf = 'Send DTMF digits Application' +asterisk_module_appsendtext = 'Send Text Applications' +asterisk_module_appsetcallerid = 'Set CallerID Application' +asterisk_module_appsetcdruserfield = 'CDR user field apps' +asterisk_module_appsetcidname = 'load => .so ; Set CallerID Name' +asterisk_module_appsetcidnum = 'load => .so ; Set CallerID Number' +asterisk_module_appsetrdnis = 'Set RDNIS Number' +asterisk_module_appsettransfercapability = 'Set ISDN Transfer Capability' +asterisk_module_appsms = 'SMS/PSTN handler' +asterisk_module_appsofthangup = 'Hangs up the requested channel' +asterisk_module_appstack = 'Stack Routines' +asterisk_module_appsystem = 'Generic System() application' +asterisk_module_apptalkdetect = 'Playback with Talk Detection' +asterisk_module_apptest = 'Interface Test Application' +asterisk_module_apptransfer = 'Transfer' +asterisk_module_apptxtcidname = 'TXTCIDName' +asterisk_module_appurl = 'Send URL Applications' +asterisk_module_appuserevent = 'Custom User Event Application' +asterisk_module_appverbose = 'Send verbose output' +asterisk_module_appvoicemail = 'Voicemail' +asterisk_module_appwaitforring = 'Waits until first ring after time' +asterisk_module_appwaitforsilence = 'Wait For Silence Application' +asterisk_module_appwhile = 'While Loops and Conditional Execution' +asterisk_module_cdrcsv = 'Comma Separated Values CDR Backend' +asterisk_module_cdrcustom = 'Customizable Comma Separated Values CDR Backend' +asterisk_module_cdrmanager = 'Asterisk Call Manager CDR Backend' +asterisk_module_cdrmysql = 'MySQL CDR Backend' +asterisk_module_cdrpgsql = 'PostgreSQL CDR Backend' +asterisk_module_cdrsqlite = 'SQLite CDR Backend' +asterisk_module_chanagent = 'Agent Proxy Channel' +asterisk_module_chanalsa = 'Channel driver for GTalk' +asterisk_module_changtalk = 'Channel driver for GTalk' +asterisk_module_chaniax2 = 'Option chan_iax2' +asterisk_module_chanlocal = 'Local Proxy Channel' +asterisk_module_chansip = 'Session Initiation Protocol (SIP)' +asterisk_module_codecadpcm = 'Adaptive Differential PCM Coder/Decoder' +asterisk_module_codecalaw = 'A-law Coder/Decoder' +asterisk_module_codecamu = 'A-law and Mulaw direct Coder/Decoder' +asterisk_module_codecg726 = 'ITU G.726-32kbps G726 Transcoder' +asterisk_module_codecgsm = 'GSM/PCM16 (signed linear) Codec Translation' +asterisk_module_codecspeex = 'Speex/PCM16 (signed linear) Codec Translator' +asterisk_module_codeculaw = 'Mu-law Coder/Decoder' +asterisk_module_formatau = 'Sun Microsystems AU format (signed linear)' +asterisk_module_formatg723 = 'G.723.1 Simple Timestamp File Format' +asterisk_module_formatg726 = 'Raw G.726 (16/24/32/40kbps) data' +asterisk_module_formatg729 = 'Raw G729 data' +asterisk_module_formatgsm = 'Raw GSM data' +asterisk_module_formath263 = 'Raw h263 data' +asterisk_module_formatjpeg = 'JPEG (Joint Picture Experts Group) Image' +asterisk_module_formatpcm = 'Raw uLaw 8khz Audio support (PCM)' +asterisk_module_formatpcmalaw = 'load => .so ; Raw aLaw 8khz PCM Audio support' +asterisk_module_formatsln = 'Raw Signed Linear Audio support (SLN)' +asterisk_module_formatvox = 'Dialogic VOX (ADPCM) File Format' +asterisk_module_formatwav = 'Microsoft WAV format (8000hz Signed Line' +asterisk_module_formatwavgsm = 'Microsoft WAV format (Proprietary GSM)' +asterisk_module_funccallerid = 'Caller ID related dialplan functions' +asterisk_module_funcenum = 'ENUM Functions' +asterisk_module_funcuri = 'URI encoding / decoding functions' +asterisk_module_pbxael = 'Asterisk Extension Language Compiler' +asterisk_module_pbxconfig = 'Text Extension Configuration' +asterisk_module_pbxfunctions = 'load => .so ; Builtin dialplan functions' +asterisk_module_pbxloopback = 'Loopback Switch' +asterisk_module_pbxrealtime = 'Realtime Switch' +asterisk_module_pbxspool = 'Outgoing Spool Support' +asterisk_module_pbxwilcalu = 'Wil Cal U (Auto Dialer)' +asterisk_module_resconfigmysql = 'MySQL Config Resource' +asterisk_module_resconfigodbc = 'ODBC Config Resource' +asterisk_module_resconfigpgsql = 'PGSQL Module' +asterisk_module_rescrypto = 'Cryptographic Digital Signatures' +asterisk_module_resfeatures = 'Call Parking Resource' +asterisk_module_resindications = 'Indications Configuration' +asterisk_module_resmonitor = 'Call Monitoring Resource' +asterisk_module_resmusiconhold = 'Music On Hold Resource' +asterisk_module_resodbc = 'ODBC Resource' +asterisk_module_ressmdi = 'SMDI Module' +asterisk_module_ressnmp = 'SNMP Module' +asterisk_moh = 'Music On Hold' +asterisk_moh_application = 'Application' +asterisk_moh_directory = 'Directory of Music' +asterisk_moh_mode = 'Option mode' +asterisk_moh_random = 'Random Play' +asterisk_sip = 'SIP Connection' +asterisk_sip_alwaysinternational = 'Always Dial International' +asterisk_sip_canreinvite = 'Reinvite/redirect media connections' +asterisk_sip_context = 'context' +asterisk_sip_countrycode = 'Country Code for connection' +asterisk_sip_dtmfmode = 'DTMF mode' +asterisk_sip_extension = 'Add as Extension' +asterisk_sip_fromdomain = 'Primary domain identity for From: headers' +asterisk_sip_fromuser = 'From user (required by many SIP providers)' +asterisk_sip_host = 'Host name (or blank)' +asterisk_sip_incoming = 'Ring on incoming dialplan contexts' +asterisk_sip_insecure = 'Allow Insecure for' +asterisk_sip_internationalprefix = 'International Dial Prefix' +asterisk_sip_mailbox = 'Mailbox for MWI' +asterisk_sip_nat = 'NAT between phone and Asterisk' +asterisk_sip_pedantic = 'Check tags in headers' +asterisk_sip_port = 'SIP Port' +asterisk_sip_prefix = 'Dial Prefix (for external line)' +asterisk_sip_qualify = 'Reply Timeout (ms) for down connection' +asterisk_sip_register = 'Register connection' +asterisk_sip_secret = 'Secret' +asterisk_sip_selfmailbox = 'Dial own extension for mailbox' +asterisk_sip_timeout = 'Dial Timeout (sec)' +asterisk_sip_type = 'Client Type' +asterisk_sip_username = 'Username' +asterisk_sipgeneral = 'Section sipgeneral' +asterisk_sipgeneral_allow = 'Allow codecs' +asterisk_sipgeneral_port = 'SIP Port' +asterisk_sipgeneral_realm = 'SIP realm' +asterisk_voicegeneral = 'Voicemail general options' +asterisk_voicegeneral_serveremail = 'From Email address of server' +asterisk_voicemail = 'Voice Mail boxes' +asterisk_voicemail_attach = 'Email contains attachment' +asterisk_voicemail_email = 'Email' +asterisk_voicemail_name = 'Display Name' +asterisk_voicemail_password = 'Password' +asterisk_voicemail_zone = 'zone' +asterisk_voicezone = 'Voice Zone settings' +asterisk_voicezone_message = 'Message Format' +asterisk_voicezone_zone = 'Time Zone' diff --git a/applications/luci-asterisk/luasrc/i18n/asterisk.en.xml b/applications/luci-asterisk/luasrc/i18n/asterisk.en.xml new file mode 100644 index 0000000000..13cba13e5a --- /dev/null +++ b/applications/luci-asterisk/luasrc/i18n/asterisk.en.xml @@ -0,0 +1,257 @@ + + + + +Asterisk General Options +AGI directory +Cache recorded sound files during recording +Debug Level +Disable some warnings +Dump core on crash +High Priority +Initialise Crypto +Use Internal Timing +Log directory +Maximum number of calls allowed +Maximum load to stop accepting new calls +Disable console colors +Sound files Cache directory +The Group to run as +The User to run as +Voicemail Spool directory +Prefix UniquID with system name +Build transcode paths via SLINEAR, not directly +Transmit SLINEAR silence while recording a channel +Verbose Level +Time Zone +Section dialplan +include +Dialplan Extension +Dialplan General Options +Allow transfer +Reinvite/redirect media connections +Clear global vars +Dialplan Goto +Dialplan Conference +Dialplan Time +Dialplan Voicemail +Dial Zones for Dialplan +Prefix to add matching dialplans +Match International prefix +Prefix (0) to add/remove to/from international numbers +localzone +Match plan +Connection to use +Feature Key maps +Attended transfer key +Blind transfer key +Key to Disconnect call +Key to Park call +Parking Feature +ADSI Park +Attended transfer timeout (sec) +One touch record key +Name of call context for parking +Sound file to play to parked caller +Max time (ms) between digits for feature activation +Method to Find Parking slot +parkedmusicclass +Play courtesy tone to +Enable Parking +Extension to dial to park +Parking time (secs) +Range of extensions for call parking +Pickup extension +Seconds to wait bewteen digits when transferring +sound when attended transfer is complete +Sound when attended transfer fails +Reload Hardware Config +Reboot Method +Parameter +SIP Connection +Always Dial International +context +Country Code for connection +Add as Extension +Host name (or blank) +International Dial Prefix +Dial Prefix (for external line) +Secret +Dial Timeout (sec) +Option type +User name +IAX General Options +Allow Codecs +Reinvite/redirect media connections +Static +Write Protect +Meetme Conference +Admin PIN +Meeting PIN +Meetme Conference General Options +Number of 20ms audio buffers to be used +Modules +Alarm Receiver Application +Authentication Application +Make sure asterisk doesnt save CDR +Check if channel is available +Listen in on any channel +Control Playback Application +Cuts up variables +Database access functions +Dialing Application +Virtual Dictation Machine Application +Directed Call Pickup Support +Extension Directory +DISA (Direct Inward System Access) Application +Dump channel variables Application +Simple Echo Application +ENUM Lookup +Reevaluates strings +Executes applications +External IVR application interface +Fork The CDR into 2 seperate entities +Get ADSI CPE ID +Group Management Routines +Encode and Stream via icecast and ices +Image Transmission Application +Look up Caller*ID name/number from black +Look up CallerID Name from local databas +Extension Macros +A simple math Application +MD5 checksum Application +Digital Milliwatt (mu-law) Test Application +Record a call and mix the audio during the recording +Call Parking and Announce Application +Trivial Playback Application +Require phone number to be entered +True Call Queueing +Random goto +Read Variable Application +Read in a file +Realtime Data Lookup/Rewrite +Trivial Record Application +Say time +Send DTMF digits Application +Send Text Applications +Set CallerID Application +CDR user field apps +load => .so ; Set CallerID Name +load => .so ; Set CallerID Number +Set RDNIS Number +Set ISDN Transfer Capability +SMS/PSTN handler +Hangs up the requested channel +Stack Routines +Generic System() application +Playback with Talk Detection +Interface Test Application +Transfer +TXTCIDName +Send URL Applications +Custom User Event Application +Send verbose output +Voicemail +Waits until first ring after time +Wait For Silence Application +While Loops and Conditional Execution +Comma Separated Values CDR Backend +Customizable Comma Separated Values CDR Backend +Asterisk Call Manager CDR Backend +MySQL CDR Backend +PostgreSQL CDR Backend +SQLite CDR Backend +Agent Proxy Channel +Channel driver for GTalk +Channel driver for GTalk +Option chan_iax2 +Local Proxy Channel +Session Initiation Protocol (SIP) +Adaptive Differential PCM Coder/Decoder +A-law Coder/Decoder +A-law and Mulaw direct Coder/Decoder +ITU G.726-32kbps G726 Transcoder +GSM/PCM16 (signed linear) Codec Translation +Speex/PCM16 (signed linear) Codec Translator +Mu-law Coder/Decoder +Sun Microsystems AU format (signed linear) +G.723.1 Simple Timestamp File Format +Raw G.726 (16/24/32/40kbps) data +Raw G729 data +Raw GSM data +Raw h263 data +JPEG (Joint Picture Experts Group) Image +Raw uLaw 8khz Audio support (PCM) +load => .so ; Raw aLaw 8khz PCM Audio support +Raw Signed Linear Audio support (SLN) +Dialogic VOX (ADPCM) File Format +Microsoft WAV format (8000hz Signed Line +Microsoft WAV format (Proprietary GSM) +Caller ID related dialplan functions +ENUM Functions +URI encoding / decoding functions +Asterisk Extension Language Compiler +Text Extension Configuration +load => .so ; Builtin dialplan functions +Loopback Switch +Realtime Switch +Outgoing Spool Support +Wil Cal U (Auto Dialer) +MySQL Config Resource +ODBC Config Resource +PGSQL Module +Cryptographic Digital Signatures +Call Parking Resource +Indications Configuration +Call Monitoring Resource +Music On Hold Resource +ODBC Resource +SMDI Module +SNMP Module +Music On Hold +Application +Directory of Music +Option mode +Random Play +SIP Connection +Always Dial International +Reinvite/redirect media connections +context +Country Code for connection +DTMF mode +Add as Extension +Primary domain identity for From: headers +From user (required by many SIP providers) +Host name (or blank) +Ring on incoming dialplan contexts +Allow Insecure for +International Dial Prefix +Mailbox for MWI +NAT between phone and Asterisk +Check tags in headers +SIP Port +Dial Prefix (for external line) +Reply Timeout (ms) for down connection +Register connection +Secret +Dial own extension for mailbox +Dial Timeout (sec) +Client Type +Username +Section sipgeneral +Allow codecs +SIP Port +SIP realm +Voicemail general options +From Email address of server +Voice Mail boxes +Email contains attachment +Email +Display Name +Password +zone +Voice Zone settings +Message Format +Time Zone + + diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-dialplans.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-dialplans.lua new file mode 100644 index 0000000000..c13109c2de --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-dialplans.lua @@ -0,0 +1,102 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-dialplans.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +dialplan = cbimap:section(TypedSection, "dialplan", "Section dialplan", "") +dialplan.addremove = true +dialplan.dynamic = true + +include = dialplan:option(MultiValue, "include", "Include zones and plans", "") +cbimap.uci:foreach( "asterisk", "dialplan", function(s) include:value(s['.name']) end ) +cbimap.uci:foreach( "asterisk", "dialzone", function(s) include:value(s['.name']) end ) + +dialplanexten = cbimap:section(TypedSection, "dialplanexten", "Dialplan Extension", "") +dialplanexten.anonymous = true +dialplanexten.addremove = true +dialplanexten.dynamic = true + + +dialplangeneral = cbimap:section(TypedSection, "dialplangeneral", "Dialplan General Options", "") +dialplangeneral.anonymous = true +dialplangeneral.addremove = true + +allowtransfer = dialplangeneral:option(Flag, "allowtransfer", "Allow transfer", "") +allowtransfer.rmempty = true + +canreinvite = dialplangeneral:option(ListValue, "canreinvite", "Reinvite/redirect media connections", "") +canreinvite:value("yes", "Yes") +canreinvite:value("nonat", "Yes when not behind NAT") +canreinvite:value("update", "Use UPDATE rather than INVITE for path redirection") +canreinvite:value("no", "No") +canreinvite.rmempty = true + +clearglobalvars = dialplangeneral:option(Flag, "clearglobalvars", "Clear global vars", "") +clearglobalvars.rmempty = true + + +dialplangoto = cbimap:section(TypedSection, "dialplangoto", "Dialplan Goto", "") +dialplangoto.anonymous = true +dialplangoto.addremove = true +dialplangoto.dynamic = true + + +dialplanmeetme = cbimap:section(TypedSection, "dialplanmeetme", "Dialplan Conference", "") +dialplanmeetme.anonymous = true +dialplanmeetme.addremove = true +dialplanmeetme.dynamic = true + + +dialplansaytime = cbimap:section(TypedSection, "dialplansaytime", "Dialplan Time", "") +dialplansaytime.anonymous = true +dialplansaytime.addremove = true +dialplansaytime.dynamic = true + + +dialplanvoice = cbimap:section(TypedSection, "dialplanvoice", "Dialplan Voicemail", "") +dialplanvoice.anonymous = true +dialplanvoice.addremove = true +dialplanvoice.dynamic = true + + +dialzone = cbimap:section(TypedSection, "dialzone", "Dial Zones for Dialplan", "") +dialzone.addremove = true +dialzone.template = "cbi/tblsection" + +addprefix = dialzone:option(Value, "addprefix", "Prefix to add matching dialplans", "") +addprefix.rmempty = true + +--international = dialzone:option(DynamicList, "international", "Match International prefix", "") +international = dialzone:option(Value, "international", "Match International prefix", "") +international.rmempty = true + +localprefix = dialzone:option(Value, "localprefix", "Prefix (0) to add/remove to/from intl. numbers", "") +localprefix.rmempty = true + +localzone = dialzone:option(Value, "localzone", "Dialzone for intl. numbers matched as local", "") +localzone.titleref = luci.dispatcher.build_url( "admin", "services", "asterisk", "dialplans" ) +cbimap.uci:foreach( "asterisk", "dialplan", function(s) localzone:value(s['.name']) end ) +cbimap.uci:foreach( "asterisk", "dialzone", function(s) localzone:value(s['.name']) end ) + +match = dialzone:option(Value, "match", "Match plan", "") +match.rmempty = true + +uses = dialzone:option(ListValue, "uses", "Connection to use", "") +uses.titleref = luci.dispatcher.build_url( "admin", "services", "asterisk", "sip-conns" ) +cbimap.uci:foreach( "asterisk", "sip", function(s) uses:value('SIP/'..s['.name']) end ) +cbimap.uci:foreach( "asterisk", "iax", function(s) uses:value('IAX/'..s['.name']) end ) + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-iax-connections.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-iax-connections.lua new file mode 100644 index 0000000000..e9d2a1efe9 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-iax-connections.lua @@ -0,0 +1,60 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-iax-connections.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +iax = cbimap:section(TypedSection, "iax", "IAX Connection", "") +iax.addremove = true + +alwaysinternational = iax:option(Flag, "alwaysinternational", "Always Dial International", "") +alwaysinternational.optional = true + +context = iax:option(ListValue, "context", "Context to use", "") +context.titleref = luci.dispatcher.build_url( "admin", "services", "asterisk", "dialplans" ) +cbimap.uci:foreach( "asterisk", "dialplan", function(s) context:value(s['.name']) end ) +cbimap.uci:foreach( "asterisk", "dialzone", function(s) context:value(s['.name']) end ) + +countrycode = iax:option(Value, "countrycode", "Country Code for connection", "") +countrycode.optional = true + +extension = iax:option(Value, "extension", "Add as Extension", "") +extension.optional = true + +host = iax:option(Value, "host", "Host name (or blank)", "") +host.optional = true + +internationalprefix = iax:option(Value, "internationalprefix", "International Dial Prefix", "") +internationalprefix.optional = true + +prefix = iax:option(Value, "prefix", "Dial Prefix (for external line)", "") +prefix.optional = true + +secret = iax:option(Value, "secret", "Secret", "") +secret.optional = true + +timeout = iax:option(Value, "timeout", "Dial Timeout (sec)", "") +timeout.optional = true + +type = iax:option(ListValue, "type", "Option type", "") +type:value("friend", "Friend (outbound/inbound)") +type:value("user", "User (inbound - authenticate by \"from\")") +type:value("peer", "Peer (outbound - match by host)") +type.optional = true + +username = iax:option(Value, "username", "User name", "") +username.optional = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-meetme.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-meetme.lua new file mode 100644 index 0000000000..bd44568fac --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-meetme.lua @@ -0,0 +1,33 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-meetme.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +meetmegeneral = cbimap:section(TypedSection, "meetmegeneral", "Meetme Conference General Options", "") + +audiobuffers = meetmegeneral:option(Value, "audiobuffers", "Number of 20ms audio buffers to be used", "") + + +meetme = cbimap:section(TypedSection, "meetme", "Meetme Conference", "") +meetme.addremove = true + +adminpin = meetme:option(Value, "adminpin", "Admin PIN", "") +adminpin.password = true + +pin = meetme:option(Value, "pin", "Meeting PIN", "") +pin.password = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-app.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-app.lua new file mode 100644 index 0000000000..0a0a2d512e --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-app.lua @@ -0,0 +1,391 @@ +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +app_alarmreceiver = module:option(ListValue, "app_alarmreceiver", "Alarm Receiver Application", "") +app_alarmreceiver:value("yes", "Load") +app_alarmreceiver:value("no", "Do Not Load") +app_alarmreceiver:value("auto", "Load as Required") +app_alarmreceiver.rmempty = true + +app_authenticate = module:option(ListValue, "app_authenticate", "Authentication Application", "") +app_authenticate:value("yes", "Load") +app_authenticate:value("no", "Do Not Load") +app_authenticate:value("auto", "Load as Required") +app_authenticate.rmempty = true + +app_cdr = module:option(ListValue, "app_cdr", "Make sure asterisk doesnt save CDR", "") +app_cdr:value("yes", "Load") +app_cdr:value("no", "Do Not Load") +app_cdr:value("auto", "Load as Required") +app_cdr.rmempty = true + +app_chanisavail = module:option(ListValue, "app_chanisavail", "Check if channel is available", "") +app_chanisavail:value("yes", "Load") +app_chanisavail:value("no", "Do Not Load") +app_chanisavail:value("auto", "Load as Required") +app_chanisavail.rmempty = true + +app_chanspy = module:option(ListValue, "app_chanspy", "Listen in on any channel", "") +app_chanspy:value("yes", "Load") +app_chanspy:value("no", "Do Not Load") +app_chanspy:value("auto", "Load as Required") +app_chanspy.rmempty = true + +app_controlplayback = module:option(ListValue, "app_controlplayback", "Control Playback Application", "") +app_controlplayback:value("yes", "Load") +app_controlplayback:value("no", "Do Not Load") +app_controlplayback:value("auto", "Load as Required") +app_controlplayback.rmempty = true + +app_cut = module:option(ListValue, "app_cut", "Cuts up variables", "") +app_cut:value("yes", "Load") +app_cut:value("no", "Do Not Load") +app_cut:value("auto", "Load as Required") +app_cut.rmempty = true + +app_db = module:option(ListValue, "app_db", "Database access functions", "") +app_db:value("yes", "Load") +app_db:value("no", "Do Not Load") +app_db:value("auto", "Load as Required") +app_db.rmempty = true + +app_dial = module:option(ListValue, "app_dial", "Dialing Application", "") +app_dial:value("yes", "Load") +app_dial:value("no", "Do Not Load") +app_dial:value("auto", "Load as Required") +app_dial.rmempty = true + +app_dictate = module:option(ListValue, "app_dictate", "Virtual Dictation Machine Application", "") +app_dictate:value("yes", "Load") +app_dictate:value("no", "Do Not Load") +app_dictate:value("auto", "Load as Required") +app_dictate.rmempty = true + +app_directed_pickup = module:option(ListValue, "app_directed_pickup", "Directed Call Pickup Support", "") +app_directed_pickup:value("yes", "Load") +app_directed_pickup:value("no", "Do Not Load") +app_directed_pickup:value("auto", "Load as Required") +app_directed_pickup.rmempty = true + +app_directory = module:option(ListValue, "app_directory", "Extension Directory", "") +app_directory:value("yes", "Load") +app_directory:value("no", "Do Not Load") +app_directory:value("auto", "Load as Required") +app_directory.rmempty = true + +app_disa = module:option(ListValue, "app_disa", "DISA (Direct Inward System Access) Application", "") +app_disa:value("yes", "Load") +app_disa:value("no", "Do Not Load") +app_disa:value("auto", "Load as Required") +app_disa.rmempty = true + +app_dumpchan = module:option(ListValue, "app_dumpchan", "Dump channel variables Application", "") +app_dumpchan:value("yes", "Load") +app_dumpchan:value("no", "Do Not Load") +app_dumpchan:value("auto", "Load as Required") +app_dumpchan.rmempty = true + +app_echo = module:option(ListValue, "app_echo", "Simple Echo Application", "") +app_echo:value("yes", "Load") +app_echo:value("no", "Do Not Load") +app_echo:value("auto", "Load as Required") +app_echo.rmempty = true + +app_enumlookup = module:option(ListValue, "app_enumlookup", "ENUM Lookup", "") +app_enumlookup:value("yes", "Load") +app_enumlookup:value("no", "Do Not Load") +app_enumlookup:value("auto", "Load as Required") +app_enumlookup.rmempty = true + +app_eval = module:option(ListValue, "app_eval", "Reevaluates strings", "") +app_eval:value("yes", "Load") +app_eval:value("no", "Do Not Load") +app_eval:value("auto", "Load as Required") +app_eval.rmempty = true + +app_exec = module:option(ListValue, "app_exec", "Executes applications", "") +app_exec:value("yes", "Load") +app_exec:value("no", "Do Not Load") +app_exec:value("auto", "Load as Required") +app_exec.rmempty = true + +app_externalivr = module:option(ListValue, "app_externalivr", "External IVR application interface", "") +app_externalivr:value("yes", "Load") +app_externalivr:value("no", "Do Not Load") +app_externalivr:value("auto", "Load as Required") +app_externalivr.rmempty = true + +app_forkcdr = module:option(ListValue, "app_forkcdr", "Fork The CDR into 2 seperate entities", "") +app_forkcdr:value("yes", "Load") +app_forkcdr:value("no", "Do Not Load") +app_forkcdr:value("auto", "Load as Required") +app_forkcdr.rmempty = true + +app_getcpeid = module:option(ListValue, "app_getcpeid", "Get ADSI CPE ID", "") +app_getcpeid:value("yes", "Load") +app_getcpeid:value("no", "Do Not Load") +app_getcpeid:value("auto", "Load as Required") +app_getcpeid.rmempty = true + +app_groupcount = module:option(ListValue, "app_groupcount", "Group Management Routines", "") +app_groupcount:value("yes", "Load") +app_groupcount:value("no", "Do Not Load") +app_groupcount:value("auto", "Load as Required") +app_groupcount.rmempty = true + +app_ices = module:option(ListValue, "app_ices", "Encode and Stream via icecast and ices", "") +app_ices:value("yes", "Load") +app_ices:value("no", "Do Not Load") +app_ices:value("auto", "Load as Required") +app_ices.rmempty = true + +app_image = module:option(ListValue, "app_image", "Image Transmission Application", "") +app_image:value("yes", "Load") +app_image:value("no", "Do Not Load") +app_image:value("auto", "Load as Required") +app_image.rmempty = true + +app_lookupblacklist = module:option(ListValue, "app_lookupblacklist", "Look up Caller*ID name/number from black", "") +app_lookupblacklist:value("yes", "Load") +app_lookupblacklist:value("no", "Do Not Load") +app_lookupblacklist:value("auto", "Load as Required") +app_lookupblacklist.rmempty = true + +app_lookupcidname = module:option(ListValue, "app_lookupcidname", "Look up CallerID Name from local databas", "") +app_lookupcidname:value("yes", "Load") +app_lookupcidname:value("no", "Do Not Load") +app_lookupcidname:value("auto", "Load as Required") +app_lookupcidname.rmempty = true + +app_macro = module:option(ListValue, "app_macro", "Extension Macros", "") +app_macro:value("yes", "Load") +app_macro:value("no", "Do Not Load") +app_macro:value("auto", "Load as Required") +app_macro.rmempty = true + +app_math = module:option(ListValue, "app_math", "A simple math Application", "") +app_math:value("yes", "Load") +app_math:value("no", "Do Not Load") +app_math:value("auto", "Load as Required") +app_math.rmempty = true + +app_md5 = module:option(ListValue, "app_md5", "MD5 checksum Application", "") +app_md5:value("yes", "Load") +app_md5:value("no", "Do Not Load") +app_md5:value("auto", "Load as Required") +app_md5.rmempty = true + +app_milliwatt = module:option(ListValue, "app_milliwatt", "Digital Milliwatt (mu-law) Test Application", "") +app_milliwatt:value("yes", "Load") +app_milliwatt:value("no", "Do Not Load") +app_milliwatt:value("auto", "Load as Required") +app_milliwatt.rmempty = true + +app_mixmonitor = module:option(ListValue, "app_mixmonitor", "Record a call and mix the audio during the recording", "") +app_mixmonitor:value("yes", "Load") +app_mixmonitor:value("no", "Do Not Load") +app_mixmonitor:value("auto", "Load as Required") +app_mixmonitor.rmempty = true + +app_parkandannounce = module:option(ListValue, "app_parkandannounce", "Call Parking and Announce Application", "") +app_parkandannounce:value("yes", "Load") +app_parkandannounce:value("no", "Do Not Load") +app_parkandannounce:value("auto", "Load as Required") +app_parkandannounce.rmempty = true + +app_playback = module:option(ListValue, "app_playback", "Trivial Playback Application", "") +app_playback:value("yes", "Load") +app_playback:value("no", "Do Not Load") +app_playback:value("auto", "Load as Required") +app_playback.rmempty = true + +app_privacy = module:option(ListValue, "app_privacy", "Require phone number to be entered", "") +app_privacy:value("yes", "Load") +app_privacy:value("no", "Do Not Load") +app_privacy:value("auto", "Load as Required") +app_privacy.rmempty = true + +app_queue = module:option(ListValue, "app_queue", "True Call Queueing", "") +app_queue:value("yes", "Load") +app_queue:value("no", "Do Not Load") +app_queue:value("auto", "Load as Required") +app_queue.rmempty = true + +app_random = module:option(ListValue, "app_random", "Random goto", "") +app_random:value("yes", "Load") +app_random:value("no", "Do Not Load") +app_random:value("auto", "Load as Required") +app_random.rmempty = true + +app_read = module:option(ListValue, "app_read", "Read Variable Application", "") +app_read:value("yes", "Load") +app_read:value("no", "Do Not Load") +app_read:value("auto", "Load as Required") +app_read.rmempty = true + +app_readfile = module:option(ListValue, "app_readfile", "Read in a file", "") +app_readfile:value("yes", "Load") +app_readfile:value("no", "Do Not Load") +app_readfile:value("auto", "Load as Required") +app_readfile.rmempty = true + +app_realtime = module:option(ListValue, "app_realtime", "Realtime Data Lookup/Rewrite", "") +app_realtime:value("yes", "Load") +app_realtime:value("no", "Do Not Load") +app_realtime:value("auto", "Load as Required") +app_realtime.rmempty = true + +app_record = module:option(ListValue, "app_record", "Trivial Record Application", "") +app_record:value("yes", "Load") +app_record:value("no", "Do Not Load") +app_record:value("auto", "Load as Required") +app_record.rmempty = true + +app_sayunixtime = module:option(ListValue, "app_sayunixtime", "Say time", "") +app_sayunixtime:value("yes", "Load") +app_sayunixtime:value("no", "Do Not Load") +app_sayunixtime:value("auto", "Load as Required") +app_sayunixtime.rmempty = true + +app_senddtmf = module:option(ListValue, "app_senddtmf", "Send DTMF digits Application", "") +app_senddtmf:value("yes", "Load") +app_senddtmf:value("no", "Do Not Load") +app_senddtmf:value("auto", "Load as Required") +app_senddtmf.rmempty = true + +app_sendtext = module:option(ListValue, "app_sendtext", "Send Text Applications", "") +app_sendtext:value("yes", "Load") +app_sendtext:value("no", "Do Not Load") +app_sendtext:value("auto", "Load as Required") +app_sendtext.rmempty = true + +app_setcallerid = module:option(ListValue, "app_setcallerid", "Set CallerID Application", "") +app_setcallerid:value("yes", "Load") +app_setcallerid:value("no", "Do Not Load") +app_setcallerid:value("auto", "Load as Required") +app_setcallerid.rmempty = true + +app_setcdruserfield = module:option(ListValue, "app_setcdruserfield", "CDR user field apps", "") +app_setcdruserfield:value("yes", "Load") +app_setcdruserfield:value("no", "Do Not Load") +app_setcdruserfield:value("auto", "Load as Required") +app_setcdruserfield.rmempty = true + +app_setcidname = module:option(ListValue, "app_setcidname", "load => .so ; Set CallerID Name", "") +app_setcidname:value("yes", "Load") +app_setcidname:value("no", "Do Not Load") +app_setcidname:value("auto", "Load as Required") +app_setcidname.rmempty = true + +app_setcidnum = module:option(ListValue, "app_setcidnum", "load => .so ; Set CallerID Number", "") +app_setcidnum:value("yes", "Load") +app_setcidnum:value("no", "Do Not Load") +app_setcidnum:value("auto", "Load as Required") +app_setcidnum.rmempty = true + +app_setrdnis = module:option(ListValue, "app_setrdnis", "Set RDNIS Number", "") +app_setrdnis:value("yes", "Load") +app_setrdnis:value("no", "Do Not Load") +app_setrdnis:value("auto", "Load as Required") +app_setrdnis.rmempty = true + +app_settransfercapability = module:option(ListValue, "app_settransfercapability", "Set ISDN Transfer Capability", "") +app_settransfercapability:value("yes", "Load") +app_settransfercapability:value("no", "Do Not Load") +app_settransfercapability:value("auto", "Load as Required") +app_settransfercapability.rmempty = true + +app_sms = module:option(ListValue, "app_sms", "SMS/PSTN handler", "") +app_sms:value("yes", "Load") +app_sms:value("no", "Do Not Load") +app_sms:value("auto", "Load as Required") +app_sms.rmempty = true + +app_softhangup = module:option(ListValue, "app_softhangup", "Hangs up the requested channel", "") +app_softhangup:value("yes", "Load") +app_softhangup:value("no", "Do Not Load") +app_softhangup:value("auto", "Load as Required") +app_softhangup.rmempty = true + +app_stack = module:option(ListValue, "app_stack", "Stack Routines", "") +app_stack:value("yes", "Load") +app_stack:value("no", "Do Not Load") +app_stack:value("auto", "Load as Required") +app_stack.rmempty = true + +app_system = module:option(ListValue, "app_system", "Generic System() application", "") +app_system:value("yes", "Load") +app_system:value("no", "Do Not Load") +app_system:value("auto", "Load as Required") +app_system.rmempty = true + +app_talkdetect = module:option(ListValue, "app_talkdetect", "Playback with Talk Detection", "") +app_talkdetect:value("yes", "Load") +app_talkdetect:value("no", "Do Not Load") +app_talkdetect:value("auto", "Load as Required") +app_talkdetect.rmempty = true + +app_test = module:option(ListValue, "app_test", "Interface Test Application", "") +app_test:value("yes", "Load") +app_test:value("no", "Do Not Load") +app_test:value("auto", "Load as Required") +app_test.rmempty = true + +app_transfer = module:option(ListValue, "app_transfer", "Transfer", "") +app_transfer:value("yes", "Load") +app_transfer:value("no", "Do Not Load") +app_transfer:value("auto", "Load as Required") +app_transfer.rmempty = true + +app_txtcidname = module:option(ListValue, "app_txtcidname", "TXTCIDName", "") +app_txtcidname:value("yes", "Load") +app_txtcidname:value("no", "Do Not Load") +app_txtcidname:value("auto", "Load as Required") +app_txtcidname.rmempty = true + +app_url = module:option(ListValue, "app_url", "Send URL Applications", "") +app_url:value("yes", "Load") +app_url:value("no", "Do Not Load") +app_url:value("auto", "Load as Required") +app_url.rmempty = true + +app_userevent = module:option(ListValue, "app_userevent", "Custom User Event Application", "") +app_userevent:value("yes", "Load") +app_userevent:value("no", "Do Not Load") +app_userevent:value("auto", "Load as Required") +app_userevent.rmempty = true + +app_verbose = module:option(ListValue, "app_verbose", "Send verbose output", "") +app_verbose:value("yes", "Load") +app_verbose:value("no", "Do Not Load") +app_verbose:value("auto", "Load as Required") +app_verbose.rmempty = true + +app_voicemail = module:option(ListValue, "app_voicemail", "Voicemail", "") +app_voicemail:value("yes", "Load") +app_voicemail:value("no", "Do Not Load") +app_voicemail:value("auto", "Load as Required") +app_voicemail.rmempty = true + +app_waitforring = module:option(ListValue, "app_waitforring", "Waits until first ring after time", "") +app_waitforring:value("yes", "Load") +app_waitforring:value("no", "Do Not Load") +app_waitforring:value("auto", "Load as Required") +app_waitforring.rmempty = true + +app_waitforsilence = module:option(ListValue, "app_waitforsilence", "Wait For Silence Application", "") +app_waitforsilence:value("yes", "Load") +app_waitforsilence:value("no", "Do Not Load") +app_waitforsilence:value("auto", "Load as Required") +app_waitforsilence.rmempty = true + +app_while = module:option(ListValue, "app_while", "While Loops and Conditional Execution", "") +app_while:value("yes", "Load") +app_while:value("no", "Do Not Load") +app_while:value("auto", "Load as Required") +app_while.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-cdr.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-cdr.lua new file mode 100644 index 0000000000..04db69d72d --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-cdr.lua @@ -0,0 +1,58 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-cdr.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +cdr_csv = module:option(ListValue, "cdr_csv", "Comma Separated Values CDR Backend", "") +cdr_csv:value("yes", "Load") +cdr_csv:value("no", "Do Not Load") +cdr_csv:value("auto", "Load as Required") +cdr_csv.rmempty = true + +cdr_custom = module:option(ListValue, "cdr_custom", "Customizable Comma Separated Values CDR Backend", "") +cdr_custom:value("yes", "Load") +cdr_custom:value("no", "Do Not Load") +cdr_custom:value("auto", "Load as Required") +cdr_custom.rmempty = true + +cdr_manager = module:option(ListValue, "cdr_manager", "Asterisk Call Manager CDR Backend", "") +cdr_manager:value("yes", "Load") +cdr_manager:value("no", "Do Not Load") +cdr_manager:value("auto", "Load as Required") +cdr_manager.rmempty = true + +cdr_mysql = module:option(ListValue, "cdr_mysql", "MySQL CDR Backend", "") +cdr_mysql:value("yes", "Load") +cdr_mysql:value("no", "Do Not Load") +cdr_mysql:value("auto", "Load as Required") +cdr_mysql.rmempty = true + +cdr_pgsql = module:option(ListValue, "cdr_pgsql", "PostgreSQL CDR Backend", "") +cdr_pgsql:value("yes", "Load") +cdr_pgsql:value("no", "Do Not Load") +cdr_pgsql:value("auto", "Load as Required") +cdr_pgsql.rmempty = true + +cdr_sqlite = module:option(ListValue, "cdr_sqlite", "SQLite CDR Backend", "") +cdr_sqlite:value("yes", "Load") +cdr_sqlite:value("no", "Do Not Load") +cdr_sqlite:value("auto", "Load as Required") +cdr_sqlite.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-chan.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-chan.lua new file mode 100644 index 0000000000..21818e58eb --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-chan.lua @@ -0,0 +1,56 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-chan.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +chan_agent = module:option(ListValue, "chan_agent", "Agent Proxy Channel", "") +chan_agent:value("yes", "Load") +chan_agent:value("no", "Do Not Load") +chan_agent:value("auto", "Load as Required") +chan_agent.rmempty = true + +chan_alsa = module:option(ListValue, "chan_alsa", "Channel driver for GTalk", "") +chan_alsa:value("yes", "Load") +chan_alsa:value("no", "Do Not Load") +chan_alsa:value("auto", "Load as Required") +chan_alsa.rmempty = true + +chan_gtalk = module:option(ListValue, "chan_gtalk", "Channel driver for GTalk", "") +chan_gtalk:value("yes", "Load") +chan_gtalk:value("no", "Do Not Load") +chan_gtalk:value("auto", "Load as Required") +chan_gtalk.rmempty = true + +chan_iax2 = module:option(Flag, "chan_iax2", "Option chan_iax2", "") +chan_iax2.rmempty = true + +chan_local = module:option(ListValue, "chan_local", "Local Proxy Channel", "") +chan_local:value("yes", "Load") +chan_local:value("no", "Do Not Load") +chan_local:value("auto", "Load as Required") +chan_local.rmempty = true + +chan_sip = module:option(ListValue, "chan_sip", "Session Initiation Protocol (SIP)", "") +chan_sip:value("yes", "Load") +chan_sip:value("no", "Do Not Load") +chan_sip:value("auto", "Load as Required") +chan_sip.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-codec.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-codec.lua new file mode 100644 index 0000000000..9a31bccd94 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-codec.lua @@ -0,0 +1,64 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-codec.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +codec_a_mu = module:option(ListValue, "codec_a_mu", "A-law and Mulaw direct Coder/Decoder", "") +codec_a_mu:value("yes", "Load") +codec_a_mu:value("no", "Do Not Load") +codec_a_mu:value("auto", "Load as Required") +codec_a_mu.rmempty = true + +codec_adpcm = module:option(ListValue, "codec_adpcm", "Adaptive Differential PCM Coder/Decoder", "") +codec_adpcm:value("yes", "Load") +codec_adpcm:value("no", "Do Not Load") +codec_adpcm:value("auto", "Load as Required") +codec_adpcm.rmempty = true + +codec_alaw = module:option(ListValue, "codec_alaw", "A-law Coder/Decoder", "") +codec_alaw:value("yes", "Load") +codec_alaw:value("no", "Do Not Load") +codec_alaw:value("auto", "Load as Required") +codec_alaw.rmempty = true + +codec_g726 = module:option(ListValue, "codec_g726", "ITU G.726-32kbps G726 Transcoder", "") +codec_g726:value("yes", "Load") +codec_g726:value("no", "Do Not Load") +codec_g726:value("auto", "Load as Required") +codec_g726.rmempty = true + +codec_gsm = module:option(ListValue, "codec_gsm", "GSM/PCM16 (signed linear) Codec Translation", "") +codec_gsm:value("yes", "Load") +codec_gsm:value("no", "Do Not Load") +codec_gsm:value("auto", "Load as Required") +codec_gsm.rmempty = true + +codec_speex = module:option(ListValue, "codec_speex", "Speex/PCM16 (signed linear) Codec Translator", "") +codec_speex:value("yes", "Load") +codec_speex:value("no", "Do Not Load") +codec_speex:value("auto", "Load as Required") +codec_speex.rmempty = true + +codec_ulaw = module:option(ListValue, "codec_ulaw", "Mu-law Coder/Decoder", "") +codec_ulaw:value("yes", "Load") +codec_ulaw:value("no", "Do Not Load") +codec_ulaw:value("auto", "Load as Required") +codec_ulaw.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-format.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-format.lua new file mode 100644 index 0000000000..4eb235e762 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-format.lua @@ -0,0 +1,100 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-format.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +format_au = module:option(ListValue, "format_au", "Sun Microsystems AU format (signed linear)", "") +format_au:value("yes", "Load") +format_au:value("no", "Do Not Load") +format_au:value("auto", "Load as Required") +format_au.rmempty = true + +format_g723 = module:option(ListValue, "format_g723", "G.723.1 Simple Timestamp File Format", "") +format_g723:value("yes", "Load") +format_g723:value("no", "Do Not Load") +format_g723:value("auto", "Load as Required") +format_g723.rmempty = true + +format_g726 = module:option(ListValue, "format_g726", "Raw G.726 (16/24/32/40kbps) data", "") +format_g726:value("yes", "Load") +format_g726:value("no", "Do Not Load") +format_g726:value("auto", "Load as Required") +format_g726.rmempty = true + +format_g729 = module:option(ListValue, "format_g729", "Raw G729 data", "") +format_g729:value("yes", "Load") +format_g729:value("no", "Do Not Load") +format_g729:value("auto", "Load as Required") +format_g729.rmempty = true + +format_gsm = module:option(ListValue, "format_gsm", "Raw GSM data", "") +format_gsm:value("yes", "Load") +format_gsm:value("no", "Do Not Load") +format_gsm:value("auto", "Load as Required") +format_gsm.rmempty = true + +format_h263 = module:option(ListValue, "format_h263", "Raw h263 data", "") +format_h263:value("yes", "Load") +format_h263:value("no", "Do Not Load") +format_h263:value("auto", "Load as Required") +format_h263.rmempty = true + +format_jpeg = module:option(ListValue, "format_jpeg", "JPEG (Joint Picture Experts Group) Image", "") +format_jpeg:value("yes", "Load") +format_jpeg:value("no", "Do Not Load") +format_jpeg:value("auto", "Load as Required") +format_jpeg.rmempty = true + +format_pcm = module:option(ListValue, "format_pcm", "Raw uLaw 8khz Audio support (PCM)", "") +format_pcm:value("yes", "Load") +format_pcm:value("no", "Do Not Load") +format_pcm:value("auto", "Load as Required") +format_pcm.rmempty = true + +format_pcm_alaw = module:option(ListValue, "format_pcm_alaw", "load => .so ; Raw aLaw 8khz PCM Audio support", "") +format_pcm_alaw:value("yes", "Load") +format_pcm_alaw:value("no", "Do Not Load") +format_pcm_alaw:value("auto", "Load as Required") +format_pcm_alaw.rmempty = true + +format_sln = module:option(ListValue, "format_sln", "Raw Signed Linear Audio support (SLN)", "") +format_sln:value("yes", "Load") +format_sln:value("no", "Do Not Load") +format_sln:value("auto", "Load as Required") +format_sln.rmempty = true + +format_vox = module:option(ListValue, "format_vox", "Dialogic VOX (ADPCM) File Format", "") +format_vox:value("yes", "Load") +format_vox:value("no", "Do Not Load") +format_vox:value("auto", "Load as Required") +format_vox.rmempty = true + +format_wav = module:option(ListValue, "format_wav", "Microsoft WAV format (8000hz Signed Line", "") +format_wav:value("yes", "Load") +format_wav:value("no", "Do Not Load") +format_wav:value("auto", "Load as Required") +format_wav.rmempty = true + +format_wav_gsm = module:option(ListValue, "format_wav_gsm", "Microsoft WAV format (Proprietary GSM)", "") +format_wav_gsm:value("yes", "Load") +format_wav_gsm:value("no", "Do Not Load") +format_wav_gsm:value("auto", "Load as Required") +format_wav_gsm.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-func.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-func.lua new file mode 100644 index 0000000000..ec26a5f8a5 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-func.lua @@ -0,0 +1,40 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-func.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +func_callerid = module:option(ListValue, "func_callerid", "Caller ID related dialplan functions", "") +func_callerid:value("yes", "Load") +func_callerid:value("no", "Do Not Load") +func_callerid:value("auto", "Load as Required") +func_callerid.rmempty = true + +func_enum = module:option(ListValue, "func_enum", "ENUM Functions", "") +func_enum:value("yes", "Load") +func_enum:value("no", "Do Not Load") +func_enum:value("auto", "Load as Required") +func_enum.rmempty = true + +func_uri = module:option(ListValue, "func_uri", "URI encoding / decoding functions", "") +func_uri:value("yes", "Load") +func_uri:value("no", "Do Not Load") +func_uri:value("auto", "Load as Required") +func_uri.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-pbx.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-pbx.lua new file mode 100644 index 0000000000..296e58a63a --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-pbx.lua @@ -0,0 +1,64 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-pbx.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +pbx_ael = module:option(ListValue, "pbx_ael", "Asterisk Extension Language Compiler", "") +pbx_ael:value("yes", "Load") +pbx_ael:value("no", "Do Not Load") +pbx_ael:value("auto", "Load as Required") +pbx_ael.rmempty = true + +pbx_config = module:option(ListValue, "pbx_config", "Text Extension Configuration", "") +pbx_config:value("yes", "Load") +pbx_config:value("no", "Do Not Load") +pbx_config:value("auto", "Load as Required") +pbx_config.rmempty = true + +pbx_functions = module:option(ListValue, "pbx_functions", "load => .so ; Builtin dialplan functions", "") +pbx_functions:value("yes", "Load") +pbx_functions:value("no", "Do Not Load") +pbx_functions:value("auto", "Load as Required") +pbx_functions.rmempty = true + +pbx_loopback = module:option(ListValue, "pbx_loopback", "Loopback Switch", "") +pbx_loopback:value("yes", "Load") +pbx_loopback:value("no", "Do Not Load") +pbx_loopback:value("auto", "Load as Required") +pbx_loopback.rmempty = true + +pbx_realtime = module:option(ListValue, "pbx_realtime", "Realtime Switch", "") +pbx_realtime:value("yes", "Load") +pbx_realtime:value("no", "Do Not Load") +pbx_realtime:value("auto", "Load as Required") +pbx_realtime.rmempty = true + +pbx_spool = module:option(ListValue, "pbx_spool", "Outgoing Spool Support", "") +pbx_spool:value("yes", "Load") +pbx_spool:value("no", "Do Not Load") +pbx_spool:value("auto", "Load as Required") +pbx_spool.rmempty = true + +pbx_wilcalu = module:option(ListValue, "pbx_wilcalu", "Wil Cal U (Auto Dialer)", "") +pbx_wilcalu:value("yes", "Load") +pbx_wilcalu:value("no", "Do Not Load") +pbx_wilcalu:value("auto", "Load as Required") +pbx_wilcalu.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res-feature.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res-feature.lua new file mode 100644 index 0000000000..8b33559a3c --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res-feature.lua @@ -0,0 +1,111 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-res-feature.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +featuremap = cbimap:section(TypedSection, "featuremap", "Feature Key maps", "") +featuremap.anonymous = true +featuremap.addremove = true + +atxfer = featuremap:option(Value, "atxfer", "Attended transfer key", "") +atxfer.rmempty = true + +blindxfer = featuremap:option(Value, "blindxfer", "Blind transfer key", "") +blindxfer.rmempty = true + +disconnect = featuremap:option(Value, "disconnect", "Key to Disconnect call", "") +disconnect.rmempty = true + +parkcall = featuremap:option(Value, "parkcall", "Key to Park call", "") +parkcall.rmempty = true + + +featurepark = cbimap:section(TypedSection, "featurepark", "Parking Feature", "") +featurepark.anonymous = true + +parkenabled = featurepark:option(Flag, "parkenabled", "Enable Parking", "") + +adsipark = featurepark:option(Flag, "adsipark", "ADSI Park", "") +adsipark.rmempty = true +adsipark:depends({ parkenabled = "1" }) + +atxfernoanswertimeout = featurepark:option(Value, "atxfernoanswertimeout", "Attended transfer timeout (sec)", "") +atxfernoanswertimeout.rmempty = true +atxfernoanswertimeout:depends({ parkenabled = "1" }) + +automon = featurepark:option(Value, "automon", "One touch record key", "") +automon.rmempty = true +automon:depends({ parkenabled = "1" }) + +context = featurepark:option(Value, "context", "Name of call context for parking", "") +context.rmempty = true +context:depends({ parkenabled = "1" }) + +courtesytone = featurepark:option(Value, "courtesytone", "Sound file to play to parked caller", "") +courtesytone.rmempty = true +courtesytone:depends({ parkenabled = "1" }) + +featuredigittimeout = featurepark:option(Value, "featuredigittimeout", "Max time (ms) between digits for feature activation", "") +featuredigittimeout.rmempty = true +featuredigittimeout:depends({ parkenabled = "1" }) + +findslot = featurepark:option(ListValue, "findslot", "Method to Find Parking slot", "") +findslot:value("first", "First available slot") +findslot:value("next", "Next free parking space") +findslot.rmempty = true +findslot:depends({ parkenabled = "1" }) + +parkedmusicclass = featurepark:option(ListValue, "parkedmusicclass", "Music on Hold class for the parked channel", "") +parkedmusicclass.titleref = luci.dispatcher.build_url( "admin", "services", "asterisk" ) +parkedmusicclass:depends({ parkenabled = "1" }) +cbimap.uci:foreach( "asterisk", "moh", function(s) parkedmusicclass:value(s['.name']) end ) + +parkedplay = featurepark:option(ListValue, "parkedplay", "Play courtesy tone to", "") +parkedplay:value("caller", "Caller") +parkedplay:value("parked", "Parked user") +parkedplay:value("both", "Both") +parkedplay.rmempty = true +parkedplay:depends({ parkenabled = "1" }) + +parkext = featurepark:option(Value, "parkext", "Extension to dial to park", "") +parkext.rmempty = true +parkext:depends({ parkenabled = "1" }) + +parkingtime = featurepark:option(Value, "parkingtime", "Parking time (secs)", "") +parkingtime.rmempty = true +parkingtime:depends({ parkenabled = "1" }) + +parkpos = featurepark:option(Value, "parkpos", "Range of extensions for call parking", "") +parkpos.rmempty = true +parkpos:depends({ parkenabled = "1" }) + +pickupexten = featurepark:option(Value, "pickupexten", "Pickup extension", "") +pickupexten.rmempty = true +pickupexten:depends({ parkenabled = "1" }) + +transferdigittimeout = featurepark:option(Value, "transferdigittimeout", "Seconds to wait bewteen digits when transferring", "") +transferdigittimeout.rmempty = true +transferdigittimeout:depends({ parkenabled = "1" }) + +xferfailsound = featurepark:option(Value, "xferfailsound", "sound when attended transfer is complete", "") +xferfailsound.rmempty = true +xferfailsound:depends({ parkenabled = "1" }) + +xfersound = featurepark:option(Value, "xfersound", "Sound when attended transfer fails", "") +xfersound.rmempty = true +xfersound:depends({ parkenabled = "1" }) + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res.lua new file mode 100644 index 0000000000..6a2b07d81f --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-mod-res.lua @@ -0,0 +1,88 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-mod-res.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +module = cbimap:section(TypedSection, "module", "Modules", "") +module.anonymous = true + +res_config_mysql = module:option(ListValue, "res_config_mysql", "MySQL Config Resource", "") +res_config_mysql:value("yes", "Load") +res_config_mysql:value("no", "Do Not Load") +res_config_mysql:value("auto", "Load as Required") +res_config_mysql.rmempty = true + +res_config_odbc = module:option(ListValue, "res_config_odbc", "ODBC Config Resource", "") +res_config_odbc:value("yes", "Load") +res_config_odbc:value("no", "Do Not Load") +res_config_odbc:value("auto", "Load as Required") +res_config_odbc.rmempty = true + +res_config_pgsql = module:option(ListValue, "res_config_pgsql", "PGSQL Module", "") +res_config_pgsql:value("yes", "Load") +res_config_pgsql:value("no", "Do Not Load") +res_config_pgsql:value("auto", "Load as Required") +res_config_pgsql.rmempty = true + +res_crypto = module:option(ListValue, "res_crypto", "Cryptographic Digital Signatures", "") +res_crypto:value("yes", "Load") +res_crypto:value("no", "Do Not Load") +res_crypto:value("auto", "Load as Required") +res_crypto.rmempty = true + +res_features = module:option(ListValue, "res_features", "Call Parking Resource", "") +res_features:value("yes", "Load") +res_features:value("no", "Do Not Load") +res_features:value("auto", "Load as Required") +res_features.rmempty = true + +res_indications = module:option(ListValue, "res_indications", "Indications Configuration", "") +res_indications:value("yes", "Load") +res_indications:value("no", "Do Not Load") +res_indications:value("auto", "Load as Required") +res_indications.rmempty = true + +res_monitor = module:option(ListValue, "res_monitor", "Call Monitoring Resource", "") +res_monitor:value("yes", "Load") +res_monitor:value("no", "Do Not Load") +res_monitor:value("auto", "Load as Required") +res_monitor.rmempty = true + +res_musiconhold = module:option(ListValue, "res_musiconhold", "Music On Hold Resource", "") +res_musiconhold:value("yes", "Load") +res_musiconhold:value("no", "Do Not Load") +res_musiconhold:value("auto", "Load as Required") +res_musiconhold.rmempty = true + +res_odbc = module:option(ListValue, "res_odbc", "ODBC Resource", "") +res_odbc:value("yes", "Load") +res_odbc:value("no", "Do Not Load") +res_odbc:value("auto", "Load as Required") +res_odbc.rmempty = true + +res_smdi = module:option(ListValue, "res_smdi", "SMDI Module", "") +res_smdi:value("yes", "Load") +res_smdi:value("no", "Do Not Load") +res_smdi:value("auto", "Load as Required") +res_smdi.rmempty = true + +res_snmp = module:option(ListValue, "res_snmp", "SNMP Module", "") +res_snmp:value("yes", "Load") +res_snmp:value("no", "Do Not Load") +res_snmp:value("auto", "Load as Required") +res_snmp.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-sip-connections.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-sip-connections.lua new file mode 100644 index 0000000000..24d61c65a8 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-sip-connections.lua @@ -0,0 +1,109 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-sip-connections.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +sip = cbimap:section(TypedSection, "sip", "SIP Connection", "") +sip.addremove = true + +alwaysinternational = sip:option(Flag, "alwaysinternational", "Always Dial International", "") +alwaysinternational.optional = true + +canreinvite = sip:option(ListValue, "canreinvite", "Reinvite/redirect media connections", "") +canreinvite:value("yes", "Yes") +canreinvite:value("nonat", "Yes when not behind NAT") +canreinvite:value("update", "Use UPDATE rather than INVITE for path redirection") +canreinvite:value("no", "No") +canreinvite.optional = true + +context = sip:option(ListValue, "context", "Context to use", "") +context.titleref = luci.dispatcher.build_url( "admin", "services", "asterisk", "dialplans" ) +cbimap.uci:foreach( "asterisk", "dialplan", function(s) context:value(s['.name']) end ) +cbimap.uci:foreach( "asterisk", "dialzone", function(s) context:value(s['.name']) end ) + +countrycode = sip:option(Value, "countrycode", "Country Code for connection", "") +countrycode.optional = true + +dtmfmode = sip:option(ListValue, "dtmfmode", "DTMF mode", "") +dtmfmode:value("info", "Use RFC2833 or INFO for the BudgeTone") +dtmfmode:value("rfc2833", "Use RFC2833 for the BudgeTone") +dtmfmode:value("inband", "Use Inband (only with ulaw/alaw)") +dtmfmode.optional = true + +extension = sip:option(Value, "extension", "Add as Extension", "") +extension.optional = true + +fromdomain = sip:option(Value, "fromdomain", "Primary domain identity for From: headers", "") +fromdomain.optional = true + +fromuser = sip:option(Value, "fromuser", "From user (required by many SIP providers)", "") +fromuser.optional = true + +host = sip:option(Value, "host", "Host name (or blank)", "") +host.optional = true + +incoming = sip:option(DynamicList, "incoming", "Ring on incoming dialplan contexts", "") +incoming.optional = true + +insecure = sip:option(ListValue, "insecure", "Allow Insecure for", "") +insecure:value("port", "Allow mismatched port number") +insecure:value("invite", "Do not require auth of incoming INVITE") +insecure:value("port,invite", "Allow mismatched port and Do not require auth of incoming INVITE") +insecure.optional = true + +internationalprefix = sip:option(Value, "internationalprefix", "International Dial Prefix", "") +internationalprefix.optional = true + +mailbox = sip:option(Value, "mailbox", "Mailbox for MWI", "") +mailbox.optional = true + +nat = sip:option(Flag, "nat", "NAT between phone and Asterisk", "") +nat.optional = true + +pedantic = sip:option(Flag, "pedantic", "Check tags in headers", "") +pedantic.optional = true + +port = sip:option(Value, "port", "SIP Port", "") +port.optional = true + +prefix = sip:option(Value, "prefix", "Dial Prefix (for external line)", "") +prefix.optional = true + +qualify = sip:option(Value, "qualify", "Reply Timeout (ms) for down connection", "") +qualify.optional = true + +register = sip:option(Flag, "register", "Register connection", "") +register.optional = true + +secret = sip:option(Value, "secret", "Secret", "") +secret.optional = true + +selfmailbox = sip:option(Flag, "selfmailbox", "Dial own extension for mailbox", "") +selfmailbox.optional = true + +timeout = sip:option(Value, "timeout", "Dial Timeout (sec)", "") +timeout.optional = true + +type = sip:option(ListValue, "type", "Client Type", "") +type:value("friend", "Friend (outbound/inbound)") +type:value("user", "User (inbound - authenticate by \"from\")") +type:value("peer", "Peer (outbound - match by host)") +type.optional = true + +username = sip:option(Value, "username", "Username", "") +username.optional = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk-voice.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk-voice.lua new file mode 100644 index 0000000000..480cb162c1 --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk-voice.lua @@ -0,0 +1,52 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk-voice.lua 3620 2008-10-23 15:42:12Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +voicegeneral = cbimap:section(TypedSection, "voicegeneral", "Voicemail general options", "") + +serveremail = voicegeneral:option(Value, "serveremail", "From Email address of server", "") + + +voicemail = cbimap:section(TypedSection, "voicemail", "Voice Mail boxes", "") +voicemail.addremove = true + +attach = voicemail:option(Flag, "attach", "Email contains attachment", "") +attach.rmempty = true + +email = voicemail:option(Value, "email", "Email", "") +email.rmempty = true + +name = voicemail:option(Value, "name", "Display Name", "") +name.rmempty = true + +password = voicemail:option(Value, "password", "Password", "") +password.rmempty = true + +zone = voicemail:option(ListValue, "zone", "Voice Zone", "") +cbimap.uci:foreach( "asterisk", "voicezone", function(s) zone:value(s['.name']) end ) + + +voicezone = cbimap:section(TypedSection, "voicezone", "Voice Zone settings", "") +voicezone.addremove = true + +message = voicezone:option(Value, "message", "Message Format", "") +message.rmempty = true + +zone = voicezone:option(Value, "zone", "Time Zone", "") +zone.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk.lua new file mode 100644 index 0000000000..fe13c6d99c --- /dev/null +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk.lua @@ -0,0 +1,162 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: asterisk.lua 3618 2008-10-23 02:25:26Z jow $ +]]-- + +cbimap = Map("asterisk", "asterisk", "") + +asterisk = cbimap:section(TypedSection, "asterisk", "Asterisk General Options", "") +asterisk.anonymous = true + +agidir = asterisk:option(Value, "agidir", "AGI directory", "") +agidir.rmempty = true + +cache_record_files = asterisk:option(Flag, "cache_record_files", "Cache recorded sound files during recording", "") +cache_record_files.rmempty = true + +debug = asterisk:option(Value, "debug", "Debug Level", "") +debug.rmempty = true + +dontwarn = asterisk:option(Flag, "dontwarn", "Disable some warnings", "") +dontwarn.rmempty = true + +dumpcore = asterisk:option(Flag, "dumpcore", "Dump core on crash", "") +dumpcore.rmempty = true + +highpriority = asterisk:option(Flag, "highpriority", "High Priority", "") +highpriority.rmempty = true + +initcrypto = asterisk:option(Flag, "initcrypto", "Initialise Crypto", "") +initcrypto.rmempty = true + +internal_timing = asterisk:option(Flag, "internal_timing", "Use Internal Timing", "") +internal_timing.rmempty = true + +logdir = asterisk:option(Value, "logdir", "Log directory", "") +logdir.rmempty = true + +maxcalls = asterisk:option(Value, "maxcalls", "Maximum number of calls allowed", "") +maxcalls.rmempty = true + +maxload = asterisk:option(Value, "maxload", "Maximum load to stop accepting new calls", "") +maxload.rmempty = true + +nocolor = asterisk:option(Flag, "nocolor", "Disable console colors", "") +nocolor.rmempty = true + +record_cache_dir = asterisk:option(Value, "record_cache_dir", "Sound files Cache directory", "") +record_cache_dir.rmempty = true +record_cache_dir:depends({ ["cache_record_files"] = "true" }) + +rungroup = asterisk:option(Flag, "rungroup", "The Group to run as", "") +rungroup.rmempty = true + +runuser = asterisk:option(Flag, "runuser", "The User to run as", "") +runuser.rmempty = true + +spooldir = asterisk:option(Value, "spooldir", "Voicemail Spool directory", "") +spooldir.rmempty = true + +systemname = asterisk:option(Value, "systemname", "Prefix UniquID with system name", "") +systemname.rmempty = true + +transcode_via_sln = asterisk:option(Flag, "transcode_via_sln", "Build transcode paths via SLINEAR, not directly", "") +transcode_via_sln.rmempty = true + +transmit_silence_during_record = asterisk:option(Flag, "transmit_silence_during_record", "Transmit SLINEAR silence while recording a channel", "") +transmit_silence_during_record.rmempty = true + +verbose = asterisk:option(Value, "verbose", "Verbose Level", "") +verbose.rmempty = true + +zone = asterisk:option(Value, "zone", "Time Zone", "") +zone.rmempty = true + + +hardwarereboot = cbimap:section(TypedSection, "hardwarereboot", "Reload Hardware Config", "") + +method = hardwarereboot:option(ListValue, "method", "Reboot Method", "") +method:value("web", "Web URL (wget)") +method:value("system", "program to run") +method.rmempty = true + +param = hardwarereboot:option(Value, "param", "Parameter", "") +param.rmempty = true + + +iaxgeneral = cbimap:section(TypedSection, "iaxgeneral", "IAX General Options", "") +iaxgeneral.anonymous = true +iaxgeneral.addremove = true + +allow = iaxgeneral:option(MultiValue, "allow", "Allow Codecs", "") +allow:value("alaw", "alaw") +allow:value("gsm", "gsm") +allow:value("g726", "g726") +allow.rmempty = true + +canreinvite = iaxgeneral:option(ListValue, "canreinvite", "Reinvite/redirect media connections", "") +canreinvite:value("yes", "Yes") +canreinvite:value("nonat", "Yes when not behind NAT") +canreinvite:value("update", "Use UPDATE rather than INVITE for path redirection") +canreinvite:value("no", "No") +canreinvite.rmempty = true + +static = iaxgeneral:option(Flag, "static", "Static", "") +static.rmempty = true + +writeprotect = iaxgeneral:option(Flag, "writeprotect", "Write Protect", "") +writeprotect.rmempty = true + + +sipgeneral = cbimap:section(TypedSection, "sipgeneral", "Section sipgeneral", "") +sipgeneral.anonymous = true +sipgeneral.addremove = true + +allow = sipgeneral:option(MultiValue, "allow", "Allow codecs", "") +allow:value("ulaw", "ulaw") +allow:value("alaw", "alaw") +allow:value("gsm", "gsm") +allow:value("g726", "g726") +allow.rmempty = true + +port = sipgeneral:option(Value, "port", "SIP Port", "") +port.rmempty = true + +realm = sipgeneral:option(Value, "realm", "SIP realm", "") +realm.rmempty = true + + +moh = cbimap:section(TypedSection, "moh", "Music On Hold", "") + +application = moh:option(Value, "application", "Application", "") +application.rmempty = true +application:depends({ ["asterisk.moh.mode"] = "custom" }) + +directory = moh:option(Value, "directory", "Directory of Music", "") +directory.rmempty = true + +mode = moh:option(ListValue, "mode", "Option mode", "") +mode:value("system", "program to run") +mode:value("files", "Read files from directory") +mode:value("quietmp3", "Quite MP3") +mode:value("mp3", "Loud MP3") +mode:value("mp3nb", "unbuffered MP3") +mode:value("quietmp3nb", "Quiet Unbuffered MP3") +mode:value("custom", "Run a custom application") +mode.rmempty = true + +random = moh:option(Flag, "random", "Random Play", "") +random.rmempty = true + + +return cbimap diff --git a/applications/luci-asterisk/root/etc/config/asterisk b/applications/luci-asterisk/root/etc/config/asterisk new file mode 100644 index 0000000000..b2fd9ad276 --- /dev/null +++ b/applications/luci-asterisk/root/etc/config/asterisk @@ -0,0 +1,228 @@ +config 'asterisk' + option 'verbose' 3 + option 'debug' 3 + option 'zone' 'Australia/Perth' + +config 'hardware' 'reboot' + option 'method' 'web' + option 'param' 'http://ata.lan/admin/reboot' + +config 'feature' 'park' + option 'parkenabled' 'yes' + option 'parkext' '700' + option 'parkpos' '701-720' + option 'context' 'parkedcalls' + option 'parkingtime' '45' + option 'courtesytone' 'beep' + option 'parkedplay' 'caller' + option 'adsipark' 'yes' + option 'findslot' 'first' + option 'parkedmusicclass' 'default' + option 'transferdigittimeout' '3' + option 'xfersound' 'beep' + option 'xferfailsound' 'beeperr' + option 'pickupexten' '"*8"' + option 'featuredigittimeout' '500' + option 'atxfernoanswertimeout' '15' + +config 'feature' 'map' + option 'blindxfer' '#1' + option 'disconnect' '*0' + option 'automon' '*1' + option 'atxfer' '#2' + option 'parkcall' '#30' + +config 'sipgeneral' + option 'realm' 'sip.mydomain.net' + option 'allow' 'alaw' + option 'extension' '102' + +config 'module' + option 'res_config_mysql' 'no' + option 'res_crypto' 'auto' + option 'chan_iax2' 'yes' + +config 'sip' 'PAP2T' + option 'type' 'friend' + option 'extension' '101' + option 'username' 'PAP2T' + option 'secret' 'mypass' + option 'port' '5061' + option 'host' '' + option 'dtmfmode' 'rfc2833' + option 'insecure' 'very' + option 'context' 'internal' + option 'mailbox' '1001@default' + option 'nat' 'no' + option 'canreinvite' 'nonat' + option 'selfmailbox' 'yes' + option 'incoming' 'provider_inbound' + +config 'sip' 'PAP2T2' + option 'type' 'friend' + option 'extension' '101' + option 'username' 'PAP2T2' + option 'secret' 'mysecret' + option 'port' '5060' + option 'host' '' + option 'dtmfmode' 'rfc2833' + option 'insecure' 'very' + option 'context' 'internal' + option 'mailbox' '1001@default' + option 'nat' 'no' + option 'canreinvite' 'nonat' + option 'selfmailbox' 'yes' + option 'incoming' 'provider_inbound' + +config 'sip' 'providerphone' + option 'type' 'friend' + option 'timeout' '55' + option 'internationalprefix' '0011' + option 'alwaysinternational' 'no' + option 'countrycode' '63' + option 'register' 'yes' + option 'host' '200.200.200.200' + option 'username' '0899999999' + option 'fromuser' '0899999999' + option 'secret' 'mysecret' + option 'fromdomain' 'providerphone.provider.net.au' + option 'context' 'provider_inbound' + option 'canreinvite' 'no' + option 'nat' 'yes' + option 'qualify' 'yes' + option 'insecure' 'very' + option 'pedantic' 'no' + option 'qualify' '1000' + +config 'iaxgeneral' + option 'static' 'yes' + option 'writeprotect' 'no' + option 'canreinvite' 'no' + option 'allow' 'ulaw,gsm' + +config 'iax' 'nell' + option 'type' 'friend' + option 'extension' '108' + option 'host' '' + option 'username' 'nell' + option 'secret' 'mypass' + option 'context' 'internal' + +config 'iax' 'iax_vista' + option 'extension' '106' + option 'type' 'friend' + option 'host' '' + option 'username' 'vista' + option 'secret' 'mysecret' + option 'context' 'internal' + +config 'iax' 'sam' + option 'type' 'friend' + option 'extension' '103' + option 'host' '' + option 'username' 'sam' + option 'secret' 'mysecret' + option 'context' 'internal' + +config 'voicegeneral' + option 'serveremail' 'voice@sip.mydomain.net' + +config 'voicemail' '1001' + option 'context' 'default' + option 'password' '0000' + option 'name' 'Family' + option 'email' 'us@mydomain.net' + option 'zone' 'wa' + option 'attach' 'no' + +config 'voicezone' 'wa' + option 'zone' 'Australia/Perth' + option 'message' 'Q IMp' + +config 'voicezone' 'military' + option 'zone' 'Zulu' + option 'message' '"vm-received" q "digits/at" H N "hours" "phonetic/z_p"' + +config 'incominggeneral' + option 'allowtransfer' 'no' + option 'timeout' '20' + option 'answerfirst' 'no' + option 'mailbox' '1001@default' + +config 'dialplangeneral' + option 'static' 'yes' + option 'writeprotect' 'no' + option 'canreinvite' 'no' + option 'clearglobalvars' 'no' + option 'allowtransfer' 'no' + +config 'dialplan' 'internal' + option 'include' 'localcall interstate smartnumber emergency extensions' + +config 'dialplanvoice' + option 'dialplan' 'internal' + option 'extension' '1001' + option 'voicecontext' 'default' + option 'voicebox' '1001' + +config 'dialplansaytime' + option 'dialplan' 'internal' + option 'extension' '108' + +config 'dialplanmeetme' + option 'dialplan' 'internal' + option 'extension' '109' + option 'room' '101' + +config 'dialplanmeetme' + option 'dialplan' 'internal' + option 'extension' '1009' + option 'room' '' + +config 'dialplan' 'localinternational' + option 'include' 'mobile interstate' + +config 'dialzone' 'interstate' + option 'uses' 'SIP/providerphone' + option 'match' '0[235-8]NXXXXXXX' + option 'localprefix' '0' + +config 'dialzone' 'mobile' + option 'uses' 'SIP/iinetphone' + option 'match' '04XXXXXXXX' + option 'localprefix' '0' + +config 'dialzone' 'smartnumber' + option 'uses' 'SIP/providerphone' + option 'match' '1[835]00.' + option 'match' '13ZXXX' + +config 'dialzone' 'emergency' + option 'uses' 'SIP/providerphone' + option 'match' '000' + option 'match' '112' + +config 'dialzone' 'localcall' + option 'uses' 'SIP/providerphone' + option 'match' 'NXXXXXXX' + option 'addprefix' '08' + option 'localprefix' '0' + +config 'dialzone' 'international' + option 'uses' 'SIP/providerphone' + option 'international' '0011,+' + option 'localzone' 'localinternational' + option 'localprefix' '0' + option 'addprefix' '' + +config 'meetmegeneral' + option 'audiobuffers' '32' + +config 'meetme' '101' + option 'pin' '' + option 'adminpin' '' + +config 'moh' 'default' + option 'mode' 'files' + option 'directory' '/opt/moh' + option 'random' 'no' diff --git a/applications/luci-asterisk/root/lib/uci/schema/default/asterisk b/applications/luci-asterisk/root/lib/uci/schema/default/asterisk new file mode 100644 index 0000000000..63bb2e7b6e --- /dev/null +++ b/applications/luci-asterisk/root/lib/uci/schema/default/asterisk @@ -0,0 +1,3625 @@ +# Asterisk UCI Scheme +# (c) 2008 FrogOnWheels +# $Id: asterisk 3620 2008-10-23 15:42:12Z jow $ + +package asterisk + +config section + option name 'asterisk' + option title 'Asterisk General Options' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'debug' + option title 'Debug Level' + option section 'asterisk.asterisk' + option datatype 'integer' + +config variable + option name 'verbose' + option title 'Verbose Level' + option section 'asterisk.asterisk' + option datatype 'integer' + +config variable + option name 'zone' + option title 'Time Zone' + option section 'asterisk.asterisk' + option datatype 'string' + +config variable + option name 'highpriority' + option title 'High Priority' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'initcrypto' + option title 'Initialise Crypto' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'nocolor' + option title 'Disable console colors' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'dontwarn' + option title 'Disable some warnings' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'dumpcore' + option title 'Dump core on crash' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'internal_timing' + option title 'Use Internal Timing' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'systemname' + option title 'Prefix UniquID with system name' + option section 'asterisk.asterisk' + option datatype 'string' + +config variable + option name 'maxcalls' + option title 'Maximum number of calls allowed' + option section 'asterisk.asterisk' + option datatype 'integer' + +config variable + option name 'maxload' + option title 'Maximum load to stop accepting new calls' + option section 'asterisk.asterisk' + option datatype 'float' + +config variable + option name 'cache_record_files' + option title 'Cache recorded sound files during recording' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'record_cache_dir' + option title 'Sound files Cache directory' + option section 'asterisk.asterisk' + option datatype 'directory' + option depends 'cache_record_files=true' + +config variable + option name 'transmit_silence_during_record' + option title 'Transmit SLINEAR silence while recording a channel' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'transcode_via_sln' + option title 'Build transcode paths via SLINEAR, not directly' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'runuser' + option title 'The User to run as' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'rungroup' + option title 'The Group to run as' + option section 'asterisk.asterisk' + option datatype 'boolean' + +config variable + option name 'spooldir' + option title 'Voicemail Spool directory' + option section 'asterisk.asterisk' + option datatype 'directory' + +config variable + option name 'logdir' + option title 'Log directory' + option section 'asterisk.asterisk' + option datatype 'directory' + +config variable + option name 'agidir' + option title 'AGI directory' + option section 'asterisk.asterisk' + option datatype 'directory' + + +config section + option name 'module' + option title 'Modules' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'chan_iax2' + option title 'Option chan_iax2' + option section 'asterisk.module' + option datatype 'boolean' + +config variable + option name 'res_odbc' + option title 'ODBC Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_odbc' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_odbc' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_odbc' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_config_odbc' + option title 'ODBC Config Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_config_odbc' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_config_odbc' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_config_odbc' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_config_mysql' + option title 'MySQL Config Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_config_mysql' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_config_mysql' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_config_mysql' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_crypto' + option title 'Cryptographic Digital Signatures' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_crypto' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_crypto' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_crypto' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_features' + option title 'Call Parking Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_features' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_features' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_features' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_indications' + option title 'Indications Configuration' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_indications' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_indications' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_indications' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_monitor' + option title 'Call Monitoring Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_monitor' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_monitor' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_monitor' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_csv' + option title 'Comma Separated Values CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_csv' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_csv' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_csv' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_custom' + option title 'Customizable Comma Separated Values CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_custom' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_custom' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_custom' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_manager' + option title 'Asterisk Call Manager CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_manager' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_manager' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_manager' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_mysql' + option title 'MySQL CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_mysql' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_mysql' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_mysql' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_pgsql' + option title 'PostgreSQL CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_pgsql' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_pgsql' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_pgsql' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'cdr_sqlite' + option title 'SQLite CDR Backend' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.cdr_sqlite' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.cdr_sqlite' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.cdr_sqlite' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_alsa' + option title 'Channel driver for GTalk' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_alsa' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_alsa' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_alsa' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_agent' + option title 'Agent Proxy Channel' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_agent' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_agent' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_agent' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_gtalk' + option title 'Channel driver for GTalk' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_gtalk' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_gtalk' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_gtalk' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_iax2' + option title 'Inter Asterisk eXchange (Ver 2)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_iax2' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_iax2' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_iax2' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_local' + option title 'Local Proxy Channel' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_local' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_local' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_local' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'chan_sip' + option title 'Session Initiation Protocol (SIP)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.chan_sip' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.chan_sip' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.chan_sip' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_a_mu' + option title 'A-law and Mulaw direct Coder/Decoder' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_a_mu' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_a_mu' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_a_mu' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_adpcm' + option title 'Adaptive Differential PCM Coder/Decoder' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_adpcm' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_adpcm' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_adpcm' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_alaw' + option title 'A-law Coder/Decoder' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_alaw' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_alaw' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_alaw' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_g726' + option title 'ITU G.726-32kbps G726 Transcoder' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_g726' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_g726' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_g726' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_gsm' + option title 'GSM/PCM16 (signed linear) Codec Translation' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_gsm' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_gsm' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_gsm' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_ulaw' + option title 'Mu-law Coder/Decoder' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_ulaw' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_ulaw' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_ulaw' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'codec_speex' + option title 'Speex/PCM16 (signed linear) Codec Translator' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.codec_speex' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.codec_speex' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.codec_speex' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_au' + option title 'Sun Microsystems AU format (signed linear)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_au' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_au' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_au' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_g723' + option title 'G.723.1 Simple Timestamp File Format' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_g723' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_g723' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_g723' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_g726' + option title 'Raw G.726 (16/24/32/40kbps) data' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_g726' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_g726' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_g726' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_g729' + option title 'Raw G729 data' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_g729' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_g729' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_g729' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_gsm' + option title 'Raw GSM data' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_gsm' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_gsm' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_gsm' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_h263' + option title 'Raw h263 data' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_h263' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_h263' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_h263' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_jpeg' + option title 'JPEG (Joint Picture Experts Group) Image' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_jpeg' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_jpeg' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_jpeg' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_pcm' + option title 'Raw uLaw 8khz Audio support (PCM)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_pcm' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_pcm' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_pcm' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_pcm_alaw' + option title 'load => .so ; Raw aLaw 8khz PCM Audio support' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_pcm_alaw' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_pcm_alaw' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_pcm_alaw' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_sln' + option title 'Raw Signed Linear Audio support (SLN)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_sln' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_sln' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_sln' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_vox' + option title 'Dialogic VOX (ADPCM) File Format' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_vox' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_vox' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_vox' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_wav' + option title 'Microsoft WAV format (8000hz Signed Line' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_wav' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_wav' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_wav' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'format_wav_gsm' + option title 'Microsoft WAV format (Proprietary GSM)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.format_wav_gsm' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.format_wav_gsm' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.format_wav_gsm' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_alarmreceiver' + option title 'Alarm Receiver Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_alarmreceiver' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_alarmreceiver' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_alarmreceiver' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_authenticate' + option title 'Authentication Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_authenticate' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_authenticate' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_authenticate' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_cdr' + option title 'Make sure asterisk doesn''t save CDR' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_cdr' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_cdr' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_cdr' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_chanisavail' + option title 'Check if channel is available' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_chanisavail' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_chanisavail' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_chanisavail' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_chanspy' + option title 'Listen in on any channel' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_chanspy' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_chanspy' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_chanspy' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_controlplayback' + option title 'Control Playback Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_controlplayback' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_controlplayback' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_controlplayback' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_cut' + option title 'Cuts up variables' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_cut' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_cut' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_cut' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_db' + option title 'Database access functions' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_db' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_db' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_db' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_dial' + option title 'Dialing Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_dial' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_dial' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_dial' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_dictate' + option title 'Virtual Dictation Machine Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_dictate' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_dictate' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_dictate' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_directory' + option title 'Extension Directory' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_directory' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_directory' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_directory' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_directed_pickup' + option title 'Directed Call Pickup Support' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_directed_pickup' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_directed_pickup' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_directed_pickup' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_disa' + option title 'DISA (Direct Inward System Access) Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_disa' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_disa' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_disa' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_dumpchan' + option title 'Dump channel variables Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_dumpchan' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_dumpchan' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_dumpchan' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_echo' + option title 'Simple Echo Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_echo' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_echo' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_echo' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_enumlookup' + option title 'ENUM Lookup' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_enumlookup' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_enumlookup' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_enumlookup' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_eval' + option title 'Reevaluates strings' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_eval' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_eval' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_eval' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_exec' + option title 'Executes applications' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_exec' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_exec' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_exec' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_externalivr' + option title 'External IVR application interface' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_externalivr' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_externalivr' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_externalivr' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_forkcdr' + option title 'Fork The CDR into 2 seperate entities' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_forkcdr' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_forkcdr' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_forkcdr' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_getcpeid' + option title 'Get ADSI CPE ID' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_getcpeid' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_getcpeid' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_getcpeid' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_groupcount' + option title 'Group Management Routines' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_groupcount' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_groupcount' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_groupcount' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_ices' + option title 'Encode and Stream via icecast and ices' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_ices' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_ices' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_ices' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_image' + option title 'Image Transmission Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_image' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_image' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_image' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_lookupblacklist' + option title 'Look up Caller*ID name/number from black' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_lookupblacklist' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_lookupblacklist' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_lookupblacklist' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_lookupcidname' + option title 'Look up CallerID Name from local databas' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_lookupcidname' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_lookupcidname' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_lookupcidname' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_macro' + option title 'Extension Macros' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_macro' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_macro' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_macro' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_math' + option title 'A simple math Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_math' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_math' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_math' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_md5' + option title 'MD5 checksum Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_md5' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_md5' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_md5' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_milliwatt' + option title 'Digital Milliwatt (mu-law) Test Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_milliwatt' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_milliwatt' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_milliwatt' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_mixmonitor' + option title 'Record a call and mix the audio during the recording' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_mixmonitor' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_mixmonitor' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_mixmonitor' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_parkandannounce' + option title 'Call Parking and Announce Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_parkandannounce' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_parkandannounce' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_parkandannounce' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_playback' + option title 'Trivial Playback Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_playback' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_playback' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_playback' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_privacy' + option title 'Require phone number to be entered' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_privacy' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_privacy' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_privacy' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_queue' + option title 'True Call Queueing' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_queue' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_queue' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_queue' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_random' + option title 'Random goto' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_random' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_random' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_random' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_read' + option title 'Read Variable Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_read' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_read' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_read' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_readfile' + option title 'Read in a file' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_readfile' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_readfile' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_readfile' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_realtime' + option title 'Realtime Data Lookup/Rewrite' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_realtime' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_realtime' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_realtime' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_record' + option title 'Trivial Record Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_record' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_record' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_record' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_sayunixtime' + option title 'Say time' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_sayunixtime' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_sayunixtime' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_sayunixtime' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_senddtmf' + option title 'Send DTMF digits Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_senddtmf' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_senddtmf' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_senddtmf' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_sendtext' + option title 'Send Text Applications' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_sendtext' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_sendtext' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_sendtext' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_setcallerid' + option title 'Set CallerID Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_setcallerid' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_setcallerid' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_setcallerid' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_setcdruserfield' + option title 'CDR user field apps' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_setcdruserfield' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_setcdruserfield' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_setcdruserfield' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_setcidname' + option title 'load => .so ; Set CallerID Name' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_setcidname' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_setcidname' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_setcidname' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_setcidnum' + option title 'load => .so ; Set CallerID Number' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_setcidnum' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_setcidnum' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_setcidnum' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_setrdnis' + option title 'Set RDNIS Number' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_setrdnis' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_setrdnis' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_setrdnis' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_settransfercapability' + option title 'Set ISDN Transfer Capability' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_settransfercapability' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_settransfercapability' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_settransfercapability' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_sms' + option title 'SMS/PSTN handler' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_sms' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_sms' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_sms' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_softhangup' + option title 'Hangs up the requested channel' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_softhangup' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_softhangup' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_softhangup' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_stack' + option title 'Stack Routines' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_stack' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_stack' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_stack' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_system' + option title 'Generic System() application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_system' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_system' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_system' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_talkdetect' + option title 'Playback with Talk Detection' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_talkdetect' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_talkdetect' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_talkdetect' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_test' + option title 'Interface Test Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_test' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_test' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_test' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_transfer' + option title 'Transfer' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_transfer' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_transfer' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_transfer' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_txtcidname' + option title 'TXTCIDName' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_txtcidname' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_txtcidname' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_txtcidname' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_url' + option title 'Send URL Applications' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_url' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_url' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_url' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_userevent' + option title 'Custom User Event Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_userevent' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_userevent' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_userevent' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_verbose' + option title 'Send verbose output' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_verbose' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_verbose' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_verbose' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_waitforring' + option title 'Waits until first ring after time' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_waitforring' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_waitforring' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_waitforring' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_waitforsilence' + option title 'Wait For Silence Application' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_waitforsilence' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_waitforsilence' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_waitforsilence' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_while' + option title 'While Loops and Conditional Execution' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_while' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_while' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_while' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'func_callerid' + option title 'Caller ID related dialplan functions' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.func_callerid' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.func_callerid' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.func_callerid' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'func_enum' + option title 'ENUM Functions' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.func_enum' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.func_enum' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.func_enum' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'func_uri' + option title 'URI encoding / decoding functions' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.func_uri' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.func_uri' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.func_uri' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_ael' + option title 'Asterisk Extension Language Compiler' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_ael' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_ael' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_ael' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_config' + option title 'Text Extension Configuration' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_config' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_config' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_config' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_functions' + option title 'load => .so ; Builtin dialplan functions' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_functions' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_functions' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_functions' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_loopback' + option title 'Loopback Switch' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_loopback' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_loopback' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_loopback' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_realtime' + option title 'Realtime Switch' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_realtime' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_realtime' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_realtime' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_spool' + option title 'Outgoing Spool Support' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_spool' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_spool' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_spool' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'pbx_wilcalu' + option title 'Wil Cal U (Auto Dialer)' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.pbx_wilcalu' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.pbx_wilcalu' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.pbx_wilcalu' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_smdi' + option title 'SMDI Module' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_smdi' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_smdi' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_smdi' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_snmp' + option title 'SNMP Module' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_snmp' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_snmp' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_snmp' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_config_pgsql' + option title 'PGSQL Module' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_config_pgsql' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_config_pgsql' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_config_pgsql' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'app_voicemail' + option title 'Voicemail' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.app_voicemail' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.app_voicemail' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.app_voicemail' + option value 'auto' + option title 'Load as Required' + +config variable + option name 'res_musiconhold' + option title 'Music On Hold Resource' + option section 'asterisk.module' + option type 'enum' + +config enum + option variable 'asterisk.module.res_musiconhold' + option value 'yes' + option title 'Load' + +config enum + option variable 'asterisk.module.res_musiconhold' + option value 'no' + option title 'Do Not Load' + +config enum + option variable 'asterisk.module.res_musiconhold' + option value 'auto' + option title 'Load as Required' + + +config section + option name 'sipgeneral' + option title 'Section sipgeneral' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config variable + option name 'allow' + option title 'Allow codecs' + option section 'asterisk.sipgeneral' + option type 'enum' + option multival 'true' + +config enum + option variable 'asterisk.sipgeneral.allow' + option value 'ulaw' + option title 'ulaw' + +config enum + option variable 'asterisk.sipgeneral.allow' + option value 'alaw' + option title 'alaw' + +config enum + option variable 'asterisk.sipgeneral.allow' + option value 'gsm' + option title 'gsm' + +config enum + option variable 'asterisk.sipgeneral.allow' + option value 'g726' + option title 'g726' + +config variable + option name 'port' + option title 'SIP Port' + option section 'asterisk.sipgeneral' + option datatype 'port' + +config variable + option name 'realm' + option title 'SIP realm' + option section 'asterisk.sipgeneral' + option datatype 'host' + + +config section + option name 'sip' + option title 'SIP Connection' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'type' + option title 'Client Type' + option section 'asterisk.sip' + option type 'enum' + +config enum + option variable 'asterisk.sip.type' + option value 'friend' + option title 'Friend (outbound/inbound)' + +config enum + option variable 'asterisk.sip.type' + option value 'user' + option title 'User (inbound - authenticate by "from")' + +config enum + option variable 'asterisk.sip.type' + option value 'peer' + option title 'Peer (outbound - match by host)' + +config variable + option name 'timeout' + option title 'Dial Timeout (sec)' + option section 'asterisk.sip' + option datatype 'integer' + +config variable + option name 'extension' + option title 'Add as Extension' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'prefix' + option title 'Dial Prefix (for external line)' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'internationalprefix' + option title 'International Dial Prefix' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'alwaysinternational' + option title 'Always Dial International' + option section 'asterisk.sip' + option datatype 'boolean' + +config variable + option name 'countrycode' + option title 'Country Code for connection' + option section 'asterisk.sip' + option datatype 'string' + + +config variable + option name 'canreinvite' + option title 'Reinvite/redirect media connections' + option section 'asterisk.sip' + option type 'enum' + +config enum + option variable 'asterisk.sip.canreinvite' + option value 'yes' + option title 'Yes' + +config enum + option variable 'asterisk.sip.canreinvite' + option value 'nonat' + option title 'Yes when not behind NAT' + +config enum + option variable 'asterisk.sip.canreinvite' + option value 'update' + option title 'Use UPDATE rather than INVITE for path redirection' + +config enum + option variable 'asterisk.sip.canreinvite' + option value 'no' + option title 'No' + +config variable + option name 'context' + option title 'Context to use' + option section 'asterisk.sip' + option datatype 'string' + option valueof 'asterisk.dialplan' + option valueof 'asterisk.dialzone' + +config variable + option name 'dtmfmode' + option title 'DTMF mode' + option section 'asterisk.sip' + option type 'enum' + +config enum + option variable 'asterisk.sip.dtmfmode' + option value 'info' + option title 'Use RFC2833 or INFO for the BudgeTone' + +config enum + option variable 'asterisk.sip.dtmfmode' + option value 'rfc2833' + option title 'Use RFC2833 for the BudgeTone' + +config enum + option variable 'asterisk.sip.dtmfmode' + option value 'inband' + option title 'Use Inband (only with ulaw/alaw)' + +config variable + option name 'fromdomain' + option title 'Primary domain identity for From: headers' + option section 'asterisk.sip' + option datatype 'hostname' + +config variable + option name 'fromuser' + option title 'From user (required by many SIP providers)' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'host' + option title 'Host name (or blank)' + option section 'asterisk.sip' + option datatype 'hostname' + +config variable + option name 'incoming' + option title 'Ring on incoming dialplan contexts' + option section 'asterisk.sip' + option datatype 'string' + option type 'lazylist' + +config variable + option name 'insecure' + option title 'Allow Insecure for' + option section 'asterisk.sip' + option datatype 'string' + option type 'enum' + +config enum + option variable 'asterisk.sip.insecure' + option value 'port' + option title 'Allow mismatched port number' + +config enum + option variable 'asterisk.sip.insecure' + option value 'invite' + option title 'Do not require auth of incoming INVITE' + +config enum + option variable 'asterisk.sip.insecure' + option value 'port,invite' + option title 'Allow mismatched port and Do not require auth of incoming INVITE' + +config variable + option name 'mailbox' + option title 'Mailbox for MWI' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'nat' + option title 'NAT between phone and Asterisk' + option section 'asterisk.sip' + option datatype 'boolean' + +config variable + option name 'pedantic' + option title 'Check tags in headers' + option section 'asterisk.sip' + option datatype 'boolean' + +config variable + option name 'port' + option title 'SIP Port' + option section 'asterisk.sip' + option datatype 'port' + +config variable + option name 'qualify' + option title 'Reply Timeout (ms) for down connection' + option section 'asterisk.sip' + option datatype 'integer' + +config variable + option name 'register' + option title 'Register connection' + option section 'asterisk.sip' + option datatype 'boolean' + +config variable + option name 'username' + option title 'Username' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'secret' + option title 'Secret' + option section 'asterisk.sip' + option datatype 'string' + +config variable + option name 'selfmailbox' + option title 'Dial own extension for mailbox' + option section 'asterisk.sip' + option datatype 'boolean' + + +config section + option name 'iax' + option title 'SIP Connection' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'type' + option title 'Option type' + option section 'asterisk.iax' + option datatype 'string' + option type 'enum' + +config enum + option variable 'asterisk.iax.type' + option value 'friend' + option title 'Friend (outbound/inbound)' + +config enum + option variable 'asterisk.iax.type' + option value 'user' + option title 'User (inbound - authenticate by "from")' + +config enum + option variable 'asterisk.iax.type' + option value 'peer' + option title 'Peer (outbound - match by host)' + +config variable + option name 'extension' + option title 'Add as Extension' + option section 'asterisk.iax' + option datatype 'string' + +config variable + option name 'timeout' + option title 'Dial Timeout (sec)' + option section 'asterisk.iax' + option datatype 'integer' + +config variable + option name 'prefix' + option title 'Dial Prefix (for external line)' + option section 'asterisk.iax' + option datatype 'string' + +config variable + option name 'internationalprefix' + option title 'International Dial Prefix' + option section 'asterisk.iax' + option datatype 'string' + +config variable + option name 'alwaysinternational' + option title 'Always Dial International' + option section 'asterisk.iax' + option datatype 'boolean' + +config variable + option name 'countrycode' + option title 'Country Code for connection' + option section 'asterisk.iax' + option datatype 'string' + +config variable + option name 'context' + option title 'Context to use' + option section 'asterisk.iax' + option datatype 'string' + option valueof 'asterisk.dialplan' + option valueof 'asterisk.dialzone' + +config variable + option name 'host' + option title 'Host name (or blank)' + option section 'asterisk.iax' + option datatype 'hostname' + +config variable + option name 'secret' + option title 'Secret' + option section 'asterisk.iax' + option datatype 'string' + +config variable + option name 'username' + option title 'User name' + option section 'asterisk.iax' + option datatype 'string' + + +config section + option name 'iaxgeneral' + option title 'IAX General Options' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config variable + option name 'allow' + option title 'Allow Codecs' + option section 'asterisk.iaxgeneral' + option datatype 'string' + option type 'enum' + option multival 'true' + +config enum + option variable 'asterisk.iaxgeneral.allow' + option value 'alaw' + option title 'alaw' + +config enum + option variable 'asterisk.iaxgeneral.allow' + option value 'gsm' + option title 'gsm' + +config enum + option variable 'asterisk.iaxgeneral.allow' + option value 'g726' + option title 'g726' + +config variable + option name 'canreinvite' + option title 'Reinvite/redirect media connections' + option section 'asterisk.iaxgeneral' + option type 'enum' + +config enum + option variable 'asterisk.iaxgeneral.canreinvite' + option value 'yes' + option title 'Yes' + +config enum + option variable 'asterisk.iaxgeneral.canreinvite' + option value 'nonat' + option title 'Yes when not behind NAT' + +config enum + option variable 'asterisk.iaxgeneral.canreinvite' + option value 'update' + option title 'Use UPDATE rather than INVITE for path redirection' + +config enum + option variable 'asterisk.iaxgeneral.canreinvite' + option value 'no' + option title 'No' + +config variable + option name 'static' + option title 'Static' + option section 'asterisk.iaxgeneral' + option datatype 'boolean' + +config variable + option name 'writeprotect' + option title 'Write Protect' + option section 'asterisk.iaxgeneral' + option datatype 'boolean' + + +config section + option name 'dialplangeneral' + option title 'Dialplan General Options' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config variable + option name 'allowtransfer' + option title 'Allow transfer' + option section 'asterisk.dialplangeneral' + option datatype 'boolean' + +config variable + option name 'canreinvite' + option title 'Reinvite/redirect media connections' + option section 'asterisk.dialplangeneral' + option type 'enum' + +config enum + option variable 'asterisk.dialplangeneral.canreinvite' + option value 'yes' + option title 'Yes' + +config enum + option variable 'asterisk.dialplangeneral.canreinvite' + option value 'nonat' + option title 'Yes when not behind NAT' + +config enum + option variable 'asterisk.dialplangeneral.canreinvite' + option value 'update' + option title 'Use UPDATE rather than INVITE for path redirection' + +config enum + option variable 'asterisk.dialplangeneral.canreinvite' + option value 'no' + option title 'No' + +config variable + option name 'clearglobalvars' + option title 'Clear global vars' + option section 'asterisk.dialplangeneral' + option datatype 'boolean' + + +config section + option name 'dialplan' + option title 'Section dialplan' + option package 'asterisk' + option named true + option unique false + option dynamic true + option required false + +config variable + option name 'include' + option title 'Option include' + option section 'asterisk.dialplan' + option datatype 'string' + option valueof 'asterisk.dialplan' + option valueof 'asterisk.dialzone' + option type 'enum' + +config enum + option variable 'asterisk.dialplan.include' + option value 'extensions' + option title 'Extensions' + +config section + option name 'dialplanvoice' + option title 'Dialplan Voicemail' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config section + option name 'dialplanexten' + option title 'Dialplan Extension' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config section + option name 'dialplanmeetme' + option title 'Dialplan Conference' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config section + option name 'dialplansaytime' + option title 'Dialplan Time' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + +config section + option name 'dialplangoto' + option title 'Dialplan Goto' + option package 'asterisk' + option named false + option unique false + option dynamic false + option required false + + +config section + option name 'dialzone' + option title 'Dial Zones for Dialplan' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'addprefix' + option title 'Prefix to add matching dialplans' + option section 'asterisk.dialzone' + option datatype 'integer' + +config variable + option name 'localprefix' + option title 'Prefix (0) to add/remove to/from international numbers' + option section 'asterisk.dialzone' + option datatype 'string' + +config variable + option name 'match' + option title 'Match plan' + option section 'asterisk.dialzone' + option datatype 'string' + +config variable + option name 'international' + option title 'Match International prefix' + option section 'asterisk.dialzone' + option datatype 'string' + option type 'lazylist' + +config variable + option name 'localzone' + option title 'Dialzone for international numbers matched as local' + option section 'asterisk.dialzone' + option datatype 'string' + option valueof 'asterisk.dialplan' + option valueof 'asterisk.dialzone' + +config variable + option name 'uses' + option title 'Connection to use' + option section 'asterisk.dialzone' + option datatype 'string' + + +config section + option name 'featurepark' + option title 'Parking Feature' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'parkenabled' + option title 'Enable Parking' + option section 'asterisk.featurepark' + option datatype 'boolean' + +config variable + option name 'adsipark' + option title 'ADSI Park' + option section 'asterisk.featurepark' + option datatype 'boolean' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'atxfernoanswertimeout' + option title 'Attended transfer timeout (sec)' + option section 'asterisk.featurepark' + option datatype 'integer' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'automon' + option title 'One touch record key' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'context' + option title 'Name of call context for parking' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'courtesytone' + option title 'Sound file to play to parked caller' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'featuredigittimeout' + option title 'Max time (ms) between digits for feature activation' + option section 'asterisk.featurepark' + option datatype 'integer' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'findslot' + option title 'Method to Find Parking slot' + option section 'asterisk.featurepark' + option type 'enum' + option depends 'asterisk.featurepark.parkenabled=true' + +config enum + option variable 'asterisk.featurepark.findslot' + option value 'first' + option title 'First available slot' + +config enum + option variable 'asterisk.featurepark.findslot' + option value 'next' + option title 'Next free parking space' + +config variable + option name 'parkedmusicclass' + option title 'Music on Hold class for the parked channel' + option section 'asterisk.featurepark' + option datatype 'string' + option valueof 'asterisk.moh' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'parkedplay' + option title 'Play courtesy tone to' + option section 'asterisk.featurepark' + option type 'enum' + option depends 'asterisk.featurepark.parkenabled=true' + +config enum + option variable 'asterisk.featurepark.parkedplay' + option value 'caller' + option title 'Caller' + +config enum + option variable 'asterisk.featurepark.parkedplay' + option value 'parked' + option title 'Parked user' + +config enum + option variable 'asterisk.featurepark.parkedplay' + option value 'both' + option title 'Both' + +config variable + option name 'parkext' + option title 'Extension to dial to park' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'parkingtime' + option title 'Parking time (secs)' + option section 'asterisk.featurepark' + option datatype 'integer' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'parkpos' + option title 'Range of extensions for call parking' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'pickupexten' + option title 'Pickup extension' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'transferdigittimeout' + option title 'Seconds to wait bewteen digits when transferring' + option section 'asterisk.featurepark' + option datatype 'integer' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'xferfailsound' + option title 'sound when attended transfer is complete' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + +config variable + option name 'xfersound' + option title 'Sound when attended transfer fails' + option section 'asterisk.featurepark' + option datatype 'string' + option depends 'asterisk.featurepark.parkenabled=true' + + +config section + option name 'featuremap' + option title 'Feature Key maps' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'blindxfer' + option title 'Blind transfer key' + option section 'asterisk.featuremap' + option datatype 'string' + +config variable + option name 'disconnect' + option title 'Key to Disconnect call' + option section 'asterisk.featuremap' + option datatype 'string' + +config variable + option name 'atxfer' + option title 'Attended transfer key' + option section 'asterisk.featuremap' + option datatype 'string' + +config variable + option name 'parkcall' + option title 'Key to Park call' + option section 'asterisk.featuremap' + option datatype 'string' + + +config section + option name 'hardwarereboot' + option title 'Reload Hardware Config' + option package 'asterisk' + option named true + option unique true + option dynamic false + option required false + +config variable + option name 'method' + option title 'Reboot Method' + option section 'asterisk.hardwarereboot' + option type 'enum' + +config enum + option variable 'asterisk.hardwarereboot.method' + option value 'web' + option title 'Web URL (wget)' + +config enum + option variable 'asterisk.hardwarereboot.method' + option value 'system' + option title 'program to run' + +config variable + option name 'param' + option title 'Parameter' + option section 'asterisk.hardwarereboot' + option datatype 'string' + + +config section + option name 'meetmegeneral' + option title 'Meetme Conference General Options' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'audiobuffers' + option title 'Number of 20ms audio buffers to be used' + option section 'asterisk.meetmegeneral' + option datatype 'integer' + + +config section + option name 'meetme' + option title 'Meetme Conference' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'adminpin' + option title 'Admin PIN' + option section 'asterisk.meetme' + option datatype 'string' + +config variable + option name 'pin' + option title 'Meeting PIN' + option section 'asterisk.meetme' + option datatype 'string' + + +config section + option name 'moh' + option title 'Music On Hold' + option package 'asterisk' + option named true + option unique true + option dynamic false + option required false + +config variable + option name 'directory' + option title 'Directory of Music' + option section 'asterisk.moh' + option datatype 'directory' + +config variable + option name 'mode' + option title 'Option mode' + option section 'asterisk.moh' + option type 'enum' + +config enum + option variable 'asterisk.moh.mode' + option value 'system' + option title 'program to run' + +config enum + option variable 'asterisk.moh.mode' + option value 'files' + option title 'Read files from directory' + +config enum + option variable 'asterisk.moh.mode' + option value 'quietmp3' + option title 'Quite MP3' + +config enum + option variable 'asterisk.moh.mode' + option value 'mp3' + option title 'Loud MP3' + +config enum + option variable 'asterisk.moh.mode' + option value 'mp3nb' + option title 'unbuffered MP3' + +config enum + option variable 'asterisk.moh.mode' + option value 'quietmp3nb' + option title 'Quiet Unbuffered MP3' + +config enum + option variable 'asterisk.moh.mode' + option value 'custom' + option title 'Run a custom application' + +config variable + option name 'application' + option title 'Application' + option section 'asterisk.moh' + option datatype 'string' + option depends 'asterisk.moh.mode=custom' + +config variable + option name 'random' + option title 'Random Play' + option section 'asterisk.moh' + option datatype 'boolean' + + +config section + option name 'voicegeneral' + option title 'Voicemail general options' + option package 'asterisk' + option named false + option unique true + option dynamic false + option required false + +config variable + option name 'serveremail' + option title 'From Email address of server' + option section 'asterisk.voicegeneral' + option datatype 'string' + + +config section + option name 'voicemail' + option title 'Voice Mail boxes' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'email' + option title 'Email' + option section 'asterisk.voicemail' + option datatype 'string' + +config variable + option name 'attach' + option title 'Email contains attachment' + option section 'asterisk.voicemail' + option datatype 'boolean' + +config variable + option name 'name' + option title 'Display Name' + option section 'asterisk.voicemail' + option datatype 'string' + +config variable + option name 'password' + option title 'Password' + option section 'asterisk.voicemail' + option datatype 'string' + +config variable + option name 'zone' + option title 'Voice zone' + option section 'asterisk.voicemail' + option datatype 'string' + option valueof 'asterisk.voicezone' + + +config section + option name 'voicezone' + option title 'Voice Zone settings' + option package 'asterisk' + option named true + option unique false + option dynamic false + option required false + +config variable + option name 'message' + option title 'Message Format' + option section 'asterisk.voicezone' + option datatype 'string' + +config variable + option name 'zone' + option title 'Time Zone' + option section 'asterisk.voicezone' + option datatype 'string' diff --git a/applications/community-halle/Makefile b/applications/luci-coovachilli/Makefile similarity index 100% rename from applications/community-halle/Makefile rename to applications/luci-coovachilli/Makefile diff --git a/applications/luci-coovachilli/luasrc/controller/coovachilli.lua b/applications/luci-coovachilli/luasrc/controller/coovachilli.lua new file mode 100644 index 0000000000..098f7b256a --- /dev/null +++ b/applications/luci-coovachilli/luasrc/controller/coovachilli.lua @@ -0,0 +1,29 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: coovachilli.lua 3548 2008-10-09 20:28:07Z Cyrus $ +]]-- +module("luci.controller.coovachilli", package.seeall) + +function index() + + require("luci.i18n") + local i18n = luci.i18n.translate + + local cc = entry( { "admin", "services", "coovachilli" }, cbi("coovachilli"), i18n("coovachilli", "CoovaChilli"), 90) + cc.i18n = "coovachilli" + cc.subindex = true + + entry( { "admin", "services", "coovachilli", "network" }, cbi("coovachilli_network"), i18n("coovachilli_network", "Network Configuration"), 10) + entry( { "admin", "services", "coovachilli", "radius" }, cbi("coovachilli_radius"), i18n("coovachilli_radius", "Radius Configuration"), 20) + entry( { "admin", "services", "coovachilli", "auth" }, cbi("coovachilli_auth"), i18n("coovachilli_auth", "UAM and MAC Authentication"), 30) + +end diff --git a/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.lua b/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.lua new file mode 100644 index 0000000000..23292fc394 --- /dev/null +++ b/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.lua @@ -0,0 +1,177 @@ +coovachilli = 'CoovaChilli' +coovachilli_general = 'General configuration' +coovachilli_general_desc = 'General CoovaChilli settings' +coovachilli_general_cmdsock = 'Command socket' +coovachilli_general_cmdsock_desc = 'UNIX socket used for communication with chilli_query' +coovachilli_general_interval = 'Config refresh interval' +coovachilli_general_interval_desc = 'Re-read configuration file and do DNS lookups every interval seconds. This has the same effect as sending the HUP signal. If interval is 0 (zero) this feature is disabled. ' +coovachilli_general_pidfile = 'Pid file' +coovachilli_general_pidfile_desc = 'Filename to put the process id' +coovachilli_general_statedir = 'State directory' +coovachilli_general_statedir_desc = 'Directory of non-volatile data' +coovachilli_tun = 'TUN/TAP configuration' +coovachilli_tun_desc = 'Network/Tun configuration' +coovachilli_tun_condown = 'Network down script' +coovachilli_tun_condown_desc = 'Script executed after a session has moved from authorized state to unauthorized' +coovachilli_tun_conup = 'Network up script' +coovachilli_tun_conup_desc = 'Script executed after the tun network interface has been brought up' +coovachilli_tun_dns1 = 'Primary DNS Server' +coovachilli_tun_dns1_desc = 'Is used to inform the client about the DNS address to use for host name resolution' +coovachilli_tun_dns2 = 'Secondary DNS Server' +coovachilli_tun_dns2_desc = 'Is used to inform the client about the DNS address to use for host name resolution' +coovachilli_tun_domain = 'Domain name' +coovachilli_tun_domain_desc = 'Is used to inform the client about the domain name to use for DNS lookups' +coovachilli_tun_dynip = 'Dynamic IP address pool' +coovachilli_tun_dynip_desc = 'Specifies a pool of dynamic IP addresses' +coovachilli_tun_ipdown = 'IP down script' +coovachilli_tun_ipdown_desc = 'Script executed after the tun network interface has been taken down' +coovachilli_tun_ipup = 'IP up script' +coovachilli_tun_ipup_desc = 'Script executed after the TUN/TAP network interface has been brought up' +coovachilli_tun_net = 'Uplink subnet' +coovachilli_tun_net_desc = 'Network address of the uplink interface (CIDR notation)' +coovachilli_tun_statip = 'Static IP address pool' +coovachilli_tun_statip_desc = 'Specifies a pool of static IP addresses' +coovachilli_tun_tundev = 'TUN/TAP device' +coovachilli_tun_tundev_desc = 'The specific device to use for the TUN/TAP interface' +coovachilli_tun_txqlen = 'TX queue length' +coovachilli_tun_txqlen_desc = 'The TX queue length to set on the TUN/TAP interface' +coovachilli_tun_usetap = 'Use TAP device' +coovachilli_tun_usetap_desc = 'Use the TAP interface instead of TUN' +coovachilli_dhcp = 'DHCP configuration' +coovachilli_dhcp_desc = 'Set DHCP options for connecting clients' +coovachilli_dhcp_dhcpend = 'DHCP end number' +coovachilli_dhcp_dhcpend_desc = 'Where to stop assigning IP addresses (default 254)' +coovachilli_dhcp_dhcpif = 'DHCP interface' +coovachilli_dhcp_dhcpif_desc = 'Ethernet interface to listen to for the downlink interface' +coovachilli_dhcp_dhcpmac = 'Listen MAC address' +coovachilli_dhcp_dhcpmac_desc = 'MAC address to listen to. If not specified the MAC address of the interface will be used' +coovachilli_dhcp_dhcpstart = 'DHCP start number' +coovachilli_dhcp_dhcpstart_desc = 'Where to start assigning IP addresses (default 10)' +coovachilli_dhcp_eapolenable = 'Enable IEEE 802.1x' +coovachilli_dhcp_eapolenable_desc = 'Enable IEEE 802.1x authentication and listen for EAP requests' +coovachilli_dhcp_lease = 'Leasetime' +coovachilli_dhcp_lease_desc = 'Use a DHCP lease of seconds (default 600)' +coovachilli_radius = 'RADIUS configuration' +coovachilli_radius_desc = 'RADIUS configuration' +coovachilli_radius_acctupdate = 'Allow session update through RADIUS' +coovachilli_radius_acctupdate_desc = 'Allow updating of session parameters with RADIUS attributes sent in Accounting-Response' +coovachilli_radius_adminpasswd = 'Admin password' +coovachilli_radius_adminpasswd_desc = 'Password to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session' +coovachilli_radius_adminuser = 'Admin user' +coovachilli_radius_adminuser_desc = 'User-name to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session' +coovachilli_radius_coanoipcheck = 'Do not check disconnection requests' +coovachilli_radius_coanoipcheck_desc = 'Do not check the source IP address of radius disconnect requests' +coovachilli_radius_coaport = 'RADIUS disconnect port' +coovachilli_radius_coaport_desc = 'UDP port to listen to for accepting radius disconnect requests' +coovachilli_radius_nasip = 'NAS IP' +coovachilli_radius_nasip_desc = 'Value to use in RADIUS NAS-IP-Address attribute' +coovachilli_radius_nasmac = 'NAS MAC' +coovachilli_radius_nasmac_desc = 'MAC address value to use in RADIUS Called-Station-ID attribute' +coovachilli_radius_openidauth = 'Allow OpenID authentication' +coovachilli_radius_openidauth_desc = 'Allows OpenID authentication by sending ChilliSpot-Config=allow-openidauth in RADIUS Access-Requests' +coovachilli_radius_radiusacctport = 'RADIUS accounting port' +coovachilli_radius_radiusacctport_desc = 'The UDP port number to use for radius accounting requests (default 1813)' +coovachilli_radius_radiusauthport = 'RADIUS authentication port' +coovachilli_radius_radiusauthport_desc = 'The UDP port number to use for radius authentication requests (default 1812)' +coovachilli_radius_radiuscalled = 'Option radiuscalled' +coovachilli_radius_radiuslisten = 'RADIUS listen address' +coovachilli_radius_radiuslisten_desc = 'Local interface IP address to use for the radius interface' +coovachilli_radius_radiuslocationid = 'RADIUS location ID' +coovachilli_radius_radiuslocationid_desc = 'WISPr Location ID' +coovachilli_radius_radiuslocationname = 'RADIUS location name' +coovachilli_radius_radiuslocationname_desc = 'WISPr Location Name' +coovachilli_radius_radiusnasid = 'NAS ID' +coovachilli_radius_radiusnasid_desc = 'Network access server identifier' +coovachilli_radius_radiusnasip = 'Option radiusnasip' +coovachilli_radius_radiusnasporttype = 'NAS port type' +coovachilli_radius_radiusnasporttype_desc = 'Value of NAS-Port-Type attribute. Defaults to 19 (Wireless-IEEE-802.11)' +coovachilli_radius_radiusoriginalurl = 'Send RADIUS VSA' +coovachilli_radius_radiusoriginalurl_desc = 'Send the ChilliSpot-OriginalURL RADIUS VSA in Access-Request' +coovachilli_radius_radiussecret = 'RADIUS secret' +coovachilli_radius_radiussecret_desc = 'Radius shared secret for both servers' +coovachilli_radius_radiusserver1 = 'RADIUS server 1' +coovachilli_radius_radiusserver1_desc = 'The IP address of radius server 1' +coovachilli_radius_radiusserver2 = 'RADIUS server 2' +coovachilli_radius_radiusserver2_desc = 'The IP address of radius server 2' +coovachilli_radius_swapoctets = 'Swap octets' +coovachilli_radius_swapoctets_desc = 'Swap the meaning of "input octets" and "output octets" as it related to RADIUS attribtues' +coovachilli_radius_wpaguests = 'Allow WPA guests' +coovachilli_radius_wpaguests_desc = 'Allows WPA Guest authentication by sending ChilliSpot-Config=allow-wpa-guests in RADIUS Access-Requests' +coovachilli_proxy = 'RADIUS proxy settings' +coovachilli_proxy_desc = 'RADIUS proxy settings' +coovachilli_proxy_proxyclient = 'Proxy client' +coovachilli_proxy_proxyclient_desc = 'IP address from which radius requests are accepted. If omitted the server will not accept radius requests' +coovachilli_proxy_proxylisten = 'Proxy listen address' +coovachilli_proxy_proxylisten_desc = 'Local interface IP address to use for accepting radius requests' +coovachilli_proxy_proxyport = 'Proxy port' +coovachilli_proxy_proxyport_desc = 'UDP Port to listen to for accepting radius requests' +coovachilli_proxy_proxysecret = 'Proxy secret' +coovachilli_proxy_proxysecret_desc = 'Radius shared secret for clients' +coovachilli_uam = 'UAM configuration' +coovachilli_uam_desc = 'Unified Configuration Method settings' +coovachilli_uam_chillixml = 'Use Chilli XML' +coovachilli_uam_chillixml_desc = 'Return the so-called Chilli XML along with WISPr XML' +coovachilli_uam_defidletimeout = 'Default idle timeout' +coovachilli_uam_defidletimeout_desc = 'Default idle timeout unless otherwise set by RADIUS (defaults to 0)' +coovachilli_uam_definteriminterval = 'Default interim interval' +coovachilli_uam_definteriminterval_desc = 'Default interim-interval for RADIUS accounting unless otherwise set by RADIUS (defaults to 0)' +coovachilli_uam_defsessiontimeout = 'Default session timeout' +coovachilli_uam_defsessiontimeout_desc = 'Default session timeout unless otherwise set by RADIUS (defaults to 0)' +coovachilli_uam_dnsparanoia = 'Inspect DNS traffic' +coovachilli_uam_dnsparanoia_desc = 'Inspect DNS packets and drop responses with any non- A, CNAME, SOA, or MX records to prevent dns tunnels (experimental)' +coovachilli_uam_localusers = 'Local users file' +coovachilli_uam_localusers_desc = 'A colon seperated file containing usernames and passwords of locally authenticated users' +coovachilli_uam_locationname = 'Location name' +coovachilli_uam_locationname_desc = 'Human readable location name used in JSON interface' +coovachilli_uam_nouamsuccess = 'Do not redirect to UAM server' +coovachilli_uam_nouamsuccess_desc = 'Do not return to UAM server on login success, just redirect to original URL' +coovachilli_uam_nouamwispr = 'Do not do WISPr' +coovachilli_uam_nouamwispr_desc = 'Do not do any WISPr XML, assume the back-end is doing this instead' +coovachilli_uam_postauthproxy = 'Post auth proxy' +coovachilli_uam_postauthproxy_desc = 'Used with postauthproxyport to define a post authentication HTTP proxy server' +coovachilli_uam_postauthproxyport = 'Post auth proxy port' +coovachilli_uam_postauthproxyport_desc = 'Used with postauthproxy to define a post authentication HTTP proxy server' +coovachilli_uam_uamallowed = 'Allowed resources' +coovachilli_uam_uamallowed_desc = 'List of resources the client can access without first authenticating' +coovachilli_uam_uamanydns = 'Allow any DNS server' +coovachilli_uam_uamanydns_desc = 'Allow any DNS server for unauthenticated clients' +coovachilli_uam_uamanyip = 'Allow any IP address' +coovachilli_uam_uamanyip_desc = 'Allow clients to use any IP settings they wish by spoofing ARP (experimental)' +coovachilli_uam_uamdomain = 'Allowed domains' +coovachilli_uam_uamdomain_desc = 'Defines a list of domain names to automatically add to the walled garden' +coovachilli_uam_uamhomepage = 'UAM homepage' +coovachilli_uam_uamhomepage_desc = 'URL of homepage to redirect unauthenticated users to' +coovachilli_uam_uamiport = 'UAM static content port' +coovachilli_uam_uamiport_desc = 'TCP port to bind to for only serving embedded content' +coovachilli_uam_uamlisten = 'UAM listening address' +coovachilli_uam_uamlisten_desc = 'IP address to listen to for authentication of clients' +coovachilli_uam_uamlogoutip = 'UAM logout IP' +coovachilli_uam_uamlogoutip_desc = 'Use this IP address to instantly logout a client accessing it (defaults to 1.1.1.1)' +coovachilli_uam_uamport = 'UAM listening port' +coovachilli_uam_uamport_desc = 'TCP port to bind to for authenticating clients (default 3990)' +coovachilli_uam_uamsecret = 'UAM secret' +coovachilli_uam_uamsecret_desc = 'Shared secret between uamserver and chilli' +coovachilli_uam_uamserver = 'UAM server' +coovachilli_uam_uamserver_desc = 'URL of web server to use for authenticating clients' +coovachilli_uam_uamui = 'UAM user interface' +coovachilli_uam_uamui_desc = 'An init.d style program to handle local content on the uamuiport web server' +coovachilli_uam_usestatusfile = 'Use status file' +coovachilli_uam_usestatusfile_desc = 'Write the status of clients in a non-volatile state file (experimental)' +coovachilli_uam_wisprlogin = 'WISPr login url' +coovachilli_uam_wisprlogin_desc = 'Specific URL to be given in WISPr XML LoginURL' +coovachilli_uam_wwwbin = 'CGI program' +coovachilli_uam_wwwbin_desc = 'Executable to run as a CGI type program (like haserl) for URLs with extention .chi' +coovachilli_uam_wwwdir = 'Web content directory' +coovachilli_uam_wwwdir_desc = 'Directory where embedded local web content is placed' +coovachilli_macauth = 'MAC configuration' +coovachilli_macauth_desc = 'Configure MAC authentication' +coovachilli_macauth_macallowed = 'Allowed MAC addresses' +coovachilli_macauth_macallowed_desc = 'List of MAC addresses for which MAC authentication will be performed' +coovachilli_macauth_macallowlocal = 'Authenticate locally allowed MACs' +coovachilli_macauth_macallowlocal_desc = 'Authenticate allowed MAC addresses without the use of RADIUS' +coovachilli_macauth_macauth = 'Enable MAC authentification' +coovachilli_macauth_macauth_desc = 'Try to authenticate all users based on their mac address alone' +coovachilli_macauth_macpasswd = 'Password' +coovachilli_macauth_macpasswd_desc = 'Password used when performing MAC authentication' +coovachilli_macauth_macsuffix = 'Suffix' +coovachilli_macauth_macsuffix_desc = 'Suffix to add to the MAC address in order to form the User-Name, which is sent to the radius server' diff --git a/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.xml b/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.xml new file mode 100644 index 0000000000..9efff41937 --- /dev/null +++ b/applications/luci-coovachilli/luasrc/i18n/coovachilli.en.xml @@ -0,0 +1,190 @@ + + + + +CoovaChilli + +General configuration +General CoovaChilli settings +Command socket +UNIX socket used for communication with chilli_query +Config refresh interval +Re-read configuration file and do DNS lookups every interval seconds. This has the same effect as sending the HUP signal. If interval is 0 (zero) this feature is disabled. +Pid file +Filename to put the process id +State directory +Directory of non-volatile data + +TUN/TAP configuration +Network/Tun configuration +Network down script +Script executed after a session has moved from authorized state to unauthorized +Network up script +Script executed after the tun network interface has been brought up +Primary DNS Server +Is used to inform the client about the DNS address to use for host name resolution +Secondary DNS Server +Is used to inform the client about the DNS address to use for host name resolution +Domain name +Is used to inform the client about the domain name to use for DNS lookups +Dynamic IP address pool +Specifies a pool of dynamic IP addresses +IP down script +Script executed after the tun network interface has been taken down +IP up script +Script executed after the TUN/TAP network interface has been brought up +Uplink subnet +Network address of the uplink interface (CIDR notation) +Static IP address pool +Specifies a pool of static IP addresses +TUN/TAP device +The specific device to use for the TUN/TAP interface +TX queue length +The TX queue length to set on the TUN/TAP interface +Use TAP device +Use the TAP interface instead of TUN + +DHCP configuration +Set DHCP options for connecting clients +DHCP end number +Where to stop assigning IP addresses (default 254) +DHCP interface +Ethernet interface to listen to for the downlink interface +Listen MAC address +MAC address to listen to. If not specified the MAC address of the interface will be used +DHCP start number +Where to start assigning IP addresses (default 10) +Enable IEEE 802.1x +Enable IEEE 802.1x authentication and listen for EAP requests +Leasetime +Use a DHCP lease of seconds (default 600) + +RADIUS configuration +RADIUS configuration +Allow session update through RADIUS +Allow updating of session parameters with RADIUS attributes sent in Accounting-Response +Admin password +Password to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session +Admin user +User-name to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session +Do not check disconnection requests +Do not check the source IP address of radius disconnect requests +RADIUS disconnect port +UDP port to listen to for accepting radius disconnect requests +NAS IP +Value to use in RADIUS NAS-IP-Address attribute +NAS MAC +MAC address value to use in RADIUS Called-Station-ID attribute +Allow OpenID authentication +Allows OpenID authentication by sending ChilliSpot-Config=allow-openidauth in RADIUS Access-Requests +RADIUS accounting port +The UDP port number to use for radius accounting requests (default 1813) +RADIUS authentication port +The UDP port number to use for radius authentication requests (default 1812) +Option radiuscalled +RADIUS listen address +Local interface IP address to use for the radius interface +RADIUS location ID +WISPr Location ID +RADIUS location name +WISPr Location Name +NAS ID +Network access server identifier +Option radiusnasip +NAS port type +Value of NAS-Port-Type attribute. Defaults to 19 (Wireless-IEEE-802.11) +Send RADIUS VSA +Send the ChilliSpot-OriginalURL RADIUS VSA in Access-Request +RADIUS secret +Radius shared secret for both servers +RADIUS server 1 +The IP address of radius server 1 +RADIUS server 2 +The IP address of radius server 2 +Swap octets +Swap the meaning of "input octets" and "output octets" as it related to RADIUS attribtues +Allow WPA guests +Allows WPA Guest authentication by sending ChilliSpot-Config=allow-wpa-guests in RADIUS Access-Requests + +RADIUS proxy settings +RADIUS proxy settings +Proxy client +IP address from which radius requests are accepted. If omitted the server will not accept radius requests +Proxy listen address +Local interface IP address to use for accepting radius requests +Proxy port +UDP Port to listen to for accepting radius requests +Proxy secret +Radius shared secret for clients + +UAM configuration +Unified Configuration Method settings +Use Chilli XML +Return the so-called Chilli XML along with WISPr XML +Default idle timeout +Default idle timeout unless otherwise set by RADIUS (defaults to 0) +Default interim interval +Default interim-interval for RADIUS accounting unless otherwise set by RADIUS (defaults to 0) +Default session timeout +Default session timeout unless otherwise set by RADIUS (defaults to 0) +Inspect DNS traffic +Inspect DNS packets and drop responses with any non- A, CNAME, SOA, or MX records to prevent dns tunnels (experimental) +Local users file +A colon seperated file containing usernames and passwords of locally authenticated users +Location name +Human readable location name used in JSON interface +Do not redirect to UAM server +Do not return to UAM server on login success, just redirect to original URL +Do not do WISPr +Do not do any WISPr XML, assume the back-end is doing this instead +Post auth proxy +Used with postauthproxyport to define a post authentication HTTP proxy server +Post auth proxy port +Used with postauthproxy to define a post authentication HTTP proxy server +Allowed resources +List of resources the client can access without first authenticating +Allow any DNS server +Allow any DNS server for unauthenticated clients +Allow any IP address +Allow clients to use any IP settings they wish by spoofing ARP (experimental) +Allowed domains +Defines a list of domain names to automatically add to the walled garden +UAM homepage +URL of homepage to redirect unauthenticated users to +UAM static content port +TCP port to bind to for only serving embedded content +UAM listening address +IP address to listen to for authentication of clients +UAM logout IP +Use this IP address to instantly logout a client accessing it (defaults to 1.1.1.1) +UAM listening port +TCP port to bind to for authenticating clients (default 3990) +UAM secret +Shared secret between uamserver and chilli +UAM server +URL of web server to use for authenticating clients +UAM user interface +An init.d style program to handle local content on the uamuiport web server +Use status file +Write the status of clients in a non-volatile state file (experimental) +WISPr login url +Specific URL to be given in WISPr XML LoginURL +CGI program +Executable to run as a CGI type program (like haserl) for URLs with extention .chi +Web content directory +Directory where embedded local web content is placed + +MAC configuration +Configure MAC authentication +Allowed MAC addresses +List of MAC addresses for which MAC authentication will be performed +Authenticate locally allowed MACs +Authenticate allowed MAC addresses without the use of RADIUS +Enable MAC authentification +Try to authenticate all users based on their mac address alone +Password +Password used when performing MAC authentication +Suffix +Suffix to add to the MAC address in order to form the User-Name, which is sent to the radius server + + diff --git a/applications/luci-coovachilli/luasrc/model/cbi/coovachilli.lua b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli.lua new file mode 100644 index 0000000000..111e9ce3b5 --- /dev/null +++ b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli.lua @@ -0,0 +1,31 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: coovachilli.lua 3442 2008-09-25 10:12:21Z jow $ +]]-- + + +m = Map("coovachilli") + +-- general +s = m:section(TypedSection, "general") +s.anonymous = true + +s:option( Flag, "debug" ) +s:option( Value, "interval" ) +s:option( Value, "pidfile" ).optional = true +s:option( Value, "statedir" ).optional = true +s:option( Value, "cmdsock" ).optional = true +s:option( Value, "logfacility" ).optional = true + + +return m diff --git a/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_auth.lua b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_auth.lua new file mode 100644 index 0000000000..f532eea18a --- /dev/null +++ b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_auth.lua @@ -0,0 +1,76 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: coovachilli_auth.lua 3445 2008-09-25 12:11:56Z jow $ +]]-- + + +m = Map("coovachilli") + +-- uam config +s1 = m:section(TypedSection, "uam") +s1.anonymous = true + +s1:option( Value, "uamserver" ) +s1:option( Value, "uamsecret" ).password = true + +s1:option( Flag, "uamanydns" ) +s1:option( Flag, "nouamsuccess" ) +s1:option( Flag, "nouamwispr" ) +s1:option( Flag, "chillixml" ) +s1:option( Flag, "uamanyip" ).optional = true +s1:option( Flag, "dnsparanoia" ).optional = true +s1:option( Flag, "usestatusfile" ).optional = true + +s1:option( Value, "uamhomepage" ).optional = true +s1:option( Value, "uamlisten" ).optional = true +s1:option( Value, "uamport" ).optional = true +s1:option( Value, "uamiport" ).optional = true +s1:option( DynamicList, "uamdomain" ).optional = true +s1:option( Value, "uamlogoutip" ).optional = true +s1:option( DynamicList, "uamallowed" ).optional = true +s1:option( Value, "uamui" ).optional = true + +s1:option( Value, "wisprlogin" ).optional = true + +s1:option( Value, "defsessiontimeout" ).optional = true +s1:option( Value, "defidletimeout" ).optional = true +s1:option( Value, "definteriminterval" ).optional = true + +s1:option( Value, "ssid" ).optional = true +s1:option( Value, "vlan" ).optional = true +s1:option( Value, "nasip" ).optional = true +s1:option( Value, "nasmac" ).optional = true +s1:option( Value, "wwwdir" ).optional = true +s1:option( Value, "wwwbin" ).optional = true + +s1:option( Value, "localusers" ).optional = true +s1:option( Value, "postauthproxy" ).optional = true +s1:option( Value, "postauthproxyport" ).optional = true +s1:option( Value, "locationname" ).optional = true + + +-- mac authentication +s2 = m:section(TypedSection, "macauth") +s2.anonymous = true + +s2:option( Flag, "macauth" ) +s2:option( Flag, "macallowlocal" ) +s2:option( DynamicList, "macallowed" ) + +pw = s2:option( Value, "macpasswd" ) +pw.optional = true +pw.password = true + +s2:option( Value, "macsuffix" ).optional = true + +return m diff --git a/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_network.lua b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_network.lua new file mode 100644 index 0000000000..6f89986d30 --- /dev/null +++ b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_network.lua @@ -0,0 +1,67 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: coovachilli_network.lua 3438M 2008-11-29 19:56:35Z (local) $ +]]-- + +require("luci.sys") +require("luci.ip") + +m = Map("coovachilli") + +-- tun +s1 = m:section(TypedSection, "tun") +s1.anonymous = true + +s1:option( Flag, "usetap" ) +s1:option( Value, "tundev" ).optional = true +s1:option( Value, "txqlen" ).optional = true + +net = s1:option( Value, "net" ) +for _, route in ipairs(luci.sys.net.routes()) do + if route.device ~= "lo" and route.dest:prefix() < 32 then + net:value( route.dest:string() ) + end +end + +s1:option( Value, "dynip" ).optional = true +s1:option( Value, "statip" ).optional = true + +s1:option( Value, "dns1" ).optional = true +s1:option( Value, "dns2" ).optional = true +s1:option( Value, "domain" ).optional = true + +s1:option( Value, "ipup" ).optional = true +s1:option( Value, "ipdown" ).optional = true + +s1:option( Value, "conup" ).optional = true +s1:option( Value, "condown" ).optional = true + + +-- dhcp config +s2 = m:section(TypedSection, "dhcp") +s2.anonymous = true + +dif = s2:option( Value, "dhcpif" ) +for _, nif in ipairs(luci.sys.net.devices()) do + if nif ~= "lo" then dif:value(nif) end +end + +s2:option( Value, "dhcpmac" ).optional = true +s2:option( Value, "lease" ).optional = true +s2:option( Value, "dhcpstart" ).optional = true +s2:option( Value, "dhcpend" ).optional = true + +s2:option( Flag, "eapolenable" ) + + +return m diff --git a/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_radius.lua b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_radius.lua new file mode 100644 index 0000000000..019fbcd3a9 --- /dev/null +++ b/applications/luci-coovachilli/luasrc/model/cbi/coovachilli_radius.lua @@ -0,0 +1,67 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: coovachilli_radius.lua 3438 2008-09-25 00:42:55Z jow $ +]]-- + + +m = Map("coovachilli") + +-- radius server +s1 = m:section(TypedSection, "radius") +s1.anonymous = true + +s1:option( Value, "radiusserver1" ) +s1:option( Value, "radiusserver2" ) +s1:option( Value, "radiussecret" ).password = true + +s1:option( Value, "radiuslisten" ).optional = true +s1:option( Value, "radiusauthport" ).optional = true +s1:option( Value, "radiusacctport" ).optional = true + +s1:option( Value, "radiusnasid" ).optional = true +s1:option( Value, "radiusnasip" ).optional = true + +s1:option( Value, "radiuscalled" ).optional = true +s1:option( Value, "radiuslocationid" ).optional = true +s1:option( Value, "radiuslocationname" ).optional = true + +s1:option( Value, "radiusnasporttype" ).optional = true + +s1:option( Flag, "radiusoriginalurl" ) + +s1:option( Value, "adminuser" ).optional = true +rs = s1:option( Value, "adminpassword" ) +rs.optional = true +rs.password = true + +s1:option( Flag, "swapoctets" ) +s1:option( Flag, "openidauth" ) +s1:option( Flag, "wpaguests" ) +s1:option( Flag, "acctupdate" ) + +s1:option( Value, "coaport" ).optional = true +s1:option( Flag, "coanoipcheck" ) + + +-- radius proxy +s2 = m:section(TypedSection, "proxy") +s2.anonymous = true + +s2:option( Value, "proxylisten" ).optional = true +s2:option( Value, "proxyport" ).optional = true +s2:option( Value, "proxyclient" ).optional = true +ps = s2:option( Value, "proxysecret" ) +ps.optional = true +ps.password = true + +return m diff --git a/applications/luci-coovachilli/root/etc/config/coovachilli b/applications/luci-coovachilli/root/etc/config/coovachilli new file mode 100644 index 0000000000..0b6be2c593 --- /dev/null +++ b/applications/luci-coovachilli/root/etc/config/coovachilli @@ -0,0 +1,243 @@ +############################################################################## +# +# Sample CoovaChilli configuration file +# +############################################################################## + +# General settings +config general + + # Enable this flag to include debug information. + option debug 0 + + # Re-read configuration file at this interval. Will also cause new domain + # name lookups to be performed. Value is given in seconds. + option interval 3600 + + # File to store information about the process id of the program. + # The program must have write access to this file/directory. + option pidfile /var/run/chilli.pid + + # Directory to use for nonvolatile storage. + # The program must have write access to this directory. + # This tag is currently ignored + #option statedir ./ + + +# TUN parameters +config tun + + # IP network address of external packet data network + # Used to allocate dynamic IP addresses and set up routing. + # Normally you do not need to uncomment this tag. + option net 192.168.182.0/24 + + # Dynamic IP address pool + # Used to allocate dynamic IP addresses to clients. + # If not set it defaults to the net tag. + # Do not uncomment this tag unless you are an experienced user! + #option dynip 192.168.182.0/24 + + # Static IP address pool + # Used to allocate static IP addresses to clients. + # Do not uncomment this tag unless you are an experienced user! + #option statip 192.168.182.0/24 + + # Primary DNS server. + # Will be suggested to the client. + # If omitted the system default will be used. + # Normally you do not need to uncomment this tag. + #option dns1 172.16.0.5 + + # Secondary DNS server. + # Will be suggested to the client. + # If omitted the system default will be used. + # Normally you do not need to uncomment this tag. + #option dns2 172.16.0.6 + + # Domain name + # Will be suggested to the client. + # Normally you do not need to uncomment this tag. + option domain key.chillispot.org + + # Script executed after network interface has been brought up. + # Executed with the following parameters: + # Normally you do not need to uncomment this tag. + #option ipup /etc/chilli.ipup + + # Script executed after network interface has been taken down. + # Executed with the following parameters: + # Normally you do not need to uncomment this tag. + #option ipdown /etc/chilli.ipdown + + # Script executed after a user has been authenticated. + # Executed with the following parameters: + # + # Normally you do not need to uncomment this tag. + #option conup /etc/chilli.conup + + # Script executed after a user has disconnected. + # Executed with the following parameters: + # + # Normally you do not need to uncomment this tag. + #option condown /etc/chilli.condown + + +# DHCP Parameters +config dhcp + + # Ethernet interface to listen to. + # This is the network interface which is connected to the access points. + # In a typical configuration this tag should be set to eth1. + option dhcpif eth1 + + # Use specified MAC address. + # An address in the range 00:00:5E:00:02:00 - 00:00:5E:FF:FF:FF falls + # within the IANA range of addresses and is not allocated for other + # purposes. + # Normally you do not need to uncomment this tag. + #option dhcpmac 00:00:5E:00:02:00 + + # Time before DHCP lease expires + # Normally you do not need to uncomment this tag. + #option lease 600 + + +# Radius parameters +config radius + + # IP address to listen to + # Normally you do not need to uncomment this tag. + #option radiuslisten 127.0.0.1 + + # IP address of radius server 1 + # For most installations you need to modify this tag. + option radiusserver1 rad01.chillispot.org + + # IP address of radius server 2 + # If you have only one radius server you should set radiusserver2 to the + # same value as radiusserver1. + # For most installations you need to modify this tag. + option radiusserver2 rad02.chillispot.org + + # Radius authentication port + # The UDP port number to use for radius authentication requests. + # The same port number is used for both radiusserver1 and radiusserver2. + # Normally you do not need to uncomment this tag. + #option radiusauthport 1812 + + # Radius accounting port + # The UDP port number to use for radius accounting requests. + # The same port number is used for both radiusserver1 and radiusserver2. + # Normally you do not need to uncomment this tag. + #option radiusacctport 1813 + + # Radius shared secret for both servers + # For all installations you should modify this tag. + #option radiussecret testing123 + + # Radius NAS-Identifier + # Normally you do not need to uncomment this tag. + #option radiusnasid nas01 + + # Radius NAS-IP-Address + # Normally you do not need to uncomment this tag. + #option radiusnasip 127.0.0.1 + + # Radius Called-Station-ID + # Normally you do not need to uncomment this tag. + #option radiuscalled 00133300 + + # WISPr Location ID. Should be in the format: isocc=, + # cc=,ac=,network= + # Normally you do not need to uncomment this tag. + #option radiuslocationid isocc=us,cc=1,ac=408,network=ACMEWISP_NewarkAirport + + # WISPr Location Name. Should be in the format: + # , + # Normally you do not need to uncomment this tag. + #option radiuslocationname ACMEWISP,Gate_14_Terminal_C_of_Newark_Airport + + +# Radius proxy parameters +config proxy + + # IP address to listen to + # Normally you do not need to uncomment this tag. + #option proxylisten 10.0.0.1 + + # UDP port to listen to. + # If not specified a port will be selected by the system + # Normally you do not need to uncomment this tag. + #option proxyport 1645 + + # Client(s) from which we accept radius requests + # Normally you do not need to uncomment this tag. + #option proxyclient 10.0.0.1/24 + + # Radius proxy shared secret for all clients + # If not specified defaults to radiussecret + # Normally you do not need to uncomment this tag. + #option proxysecret testing123 + + +# Universal access method (UAM) parameters +config uam + + # URL of web server handling authentication. + option uamserver https://radius.chillispot.org/hotspotlogin + + # URL of welcome homepage. + # Unauthenticated users will be redirected to this URL. If not specified + # users will be redirected to the uamserver instead. + # Normally you do not need to uncomment this tag. + #option uamhomepage http://192.168.182.1/welcome.html + + # Shared between chilli and authentication web server + #option uamsecret ht2eb8ej6s4et3rg1ulp + + # IP address to listen to for authentication requests + # Do not uncomment this tag unless you are an experienced user! + #option uamlisten 192.168.182.1 + + # TCP port to listen to for authentication requests + # Do not uncomment this tag unless you are an experienced user! + #option uamport 3990 + + # Comma separated list of domain names, IP addresses or network segments + # the client can access without first authenticating. + # It is possible to specify this tag multiple times. + # Normally you do not need to uncomment this tag. + #list uamallowed www.chillispot.org + #list uamallowed 10.11.12.0/24 + + # If this flag is given unauthenticated users are allowed to use + # any DNS server. + # Normally you do not need to uncomment this tag. + #uamanydns + + +# MAC authentication +config macauth + + # If this flag is given users will be authenticated only on their MAC + # address. + # Normally you do not need to enable this flag. + option macauth 0 + + # List of MAC addresses. + # The MAC addresses specified in this list will be authenticated only on + # their MAC address. + # This tag is ignored if the macauth tag is given. + # It is possible to specify this tag multiple times. + # Normally you do not need to uncomment this tag. + #list macallowed 00-0A-5E-AC-BE-51 + #list macallowed 00-30-1B-3C-32-E9 + + # Password to use for MAC authentication. + # Normally you do not need to uncomment this tag. + #option macpasswd password + + # Suffix to add to MAC address in order to form the username. + # Normally you do not need to uncomment this tag. + #option macsuffix suffix diff --git a/applications/luci-coovachilli/root/lib/uci/schema/default/coovachilli b/applications/luci-coovachilli/root/lib/uci/schema/default/coovachilli new file mode 100644 index 0000000000..898381a6d5 --- /dev/null +++ b/applications/luci-coovachilli/root/lib/uci/schema/default/coovachilli @@ -0,0 +1,642 @@ +package coovachilli + +config section + option name 'general' + option title 'General configuration' + option description 'General CoovaChilli settings' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'interval' + option title 'Config refresh interval' + option description 'Re-read configuration file and do DNS lookups every interval seconds. This has the same effect as sending the HUP signal. If interval is 0 (zero) this feature is disabled. ' + option section 'coovachilli.general' + option datatype 'uint' + +config variable + option name 'pidfile' + option title 'Pid file' + option description 'Filename to put the process id' + option section 'coovachilli.general' + option datatype 'string' + +config variable + option name 'statedir' + option title 'State directory' + option description 'Directory of non-volatile data' + option section 'coovachilli.general' + option datatype 'directory' + +config variable + option name 'cmdsock' + option title 'Command socket' + option description 'UNIX socket used for communication with chilli_query' + option section 'coovachilli.general' + option datatype 'string' + + +config section + option name 'tun' + option title 'TUN/TAP configuration' + option description 'Network/Tun configuration' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'txqlen' + option title 'TX queue length' + option description 'The TX queue length to set on the TUN/TAP interface' + option section 'coovachilli.tun' + option datatype 'uint' + +config variable + option name 'usetap' + option title 'Use TAP device' + option description 'Use the TAP interface instead of TUN' + option section 'coovachilli.tun' + option datatype 'boolean' + +config variable + option name 'tundev' + option title 'TUN/TAP device' + option description 'The specific device to use for the TUN/TAP interface' + option section 'coovachilli.tun' + option datatype 'file' + +config variable + option name 'net' + option title 'Uplink subnet' + option description 'Network address of the uplink interface (CIDR notation)' + option section 'coovachilli.tun' + option datatype 'ip4addr' + +config variable + option name 'statip' + option title 'Static IP address pool' + option description 'Specifies a pool of static IP addresses' + option section 'coovachilli.tun' + option datatype 'ip4addr' + +config variable + option name 'dynip' + option title 'Dynamic IP address pool' + option description 'Specifies a pool of dynamic IP addresses' + option section 'coovachilli.tun' + option datatype 'ip4addr' + +config variable + option name 'dns1' + option title 'Primary DNS Server' + option description 'Is used to inform the client about the DNS address to use for host name resolution' + option section 'coovachilli.tun' + option datatype 'host' + +config variable + option name 'dns2' + option title 'Secondary DNS Server' + option description 'Is used to inform the client about the DNS address to use for host name resolution' + option section 'coovachilli.tun' + option datatype 'host' + +config variable + option name 'domain' + option title 'Domain name' + option description 'Is used to inform the client about the domain name to use for DNS lookups' + option section 'coovachilli.tun' + option datatype 'string' + +config variable + option name 'ipdown' + option title 'IP down script' + option description 'Script executed after the tun network interface has been taken down' + option section 'coovachilli.tun' + option datatype 'file' + +config variable + option name 'ipup' + option title 'IP up script' + option description 'Script executed after the TUN/TAP network interface has been brought up' + option section 'coovachilli.tun' + option datatype 'file' + +config variable + option name 'condown' + option title 'Network down script' + option description 'Script executed after a session has moved from authorized state to unauthorized' + option section 'coovachilli.tun' + option datatype 'file' + +config variable + option name 'conup' + option title 'Network up script' + option description 'Script executed after the tun network interface has been brought up' + option section 'coovachilli.tun' + option datatype 'file' + + +config section + option name 'dhcp' + option title 'DHCP configuration' + option description 'Set DHCP options for connecting clients' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'dhcpif' + option title 'DHCP interface' + option description 'Ethernet interface to listen to for the downlink interface' + option section 'coovachilli.dhcp' + option datatype 'string' + option required true + +config variable + option name 'dhcpmac' + option title 'Listen MAC address' + option description 'MAC address to listen to. If not specified the MAC address of the interface will be used' + option section 'coovachilli.dhcp' + option datatype 'macaddr' + +config variable + option name 'lease' + option title 'Leasetime' + option description 'Use a DHCP lease of seconds (default 600)' + option section 'coovachilli.dhcp' + option datatype 'uint' + +config variable + option name 'dhcpstart' + option title 'DHCP start number' + option description 'Where to start assigning IP addresses (default 10)' + option section 'coovachilli.dhcp' + option datatype 'uint' + +config variable + option name 'dhcpend' + option title 'DHCP end number' + option description 'Where to stop assigning IP addresses (default 254)' + option section 'coovachilli.dhcp' + option datatype 'uint' + +config variable + option name 'eapolenable' + option title 'Enable IEEE 802.1x' + option description 'Enable IEEE 802.1x authentication and listen for EAP requests' + option section 'coovachilli.dhcp' + option datatype 'boolean' + + +config section + option name 'macauth' + option title 'MAC configuration' + option description 'Configure MAC authentication' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'macauth' + option title 'Enable MAC authentification' + option description 'Try to authenticate all users based on their mac address alone' + option section 'coovachilli.macauth' + option datatype 'boolean' + +config variable + option name 'macallowlocal' + option title 'Authenticate locally allowed MACs' + option description 'Authenticate allowed MAC addresses without the use of RADIUS' + option section 'coovachilli.macauth' + option datatype 'boolean' + +config variable + option name 'macallowed' + option title 'Allowed MAC addresses' + option description 'List of MAC addresses for which MAC authentication will be performed' + option section 'coovachilli.macauth' + option datatype 'string' + option type 'lazylist' + +config variable + option name 'macpasswd' + option title 'Password' + option description 'Password used when performing MAC authentication' + option section 'coovachilli.macauth' + option datatype 'string' + +config variable + option name 'macsuffix' + option title 'Suffix' + option description 'Suffix to add to the MAC address in order to form the User-Name, which is sent to the radius server' + option section 'coovachilli.macauth' + option datatype 'string' + + +config section + option name 'radius' + option title 'RADIUS configuration' + option description 'RADIUS configuration' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'acctupdate' + option title 'Allow session update through RADIUS' + option description 'Allow updating of session parameters with RADIUS attributes sent in Accounting-Response' + option section 'coovachilli.radius' + option datatype 'boolean' + +config variable + option name 'radiusoriginalurl' + option title 'Send RADIUS VSA' + option description 'Send the ChilliSpot-OriginalURL RADIUS VSA in Access-Request' + option section 'coovachilli.radius' + option datatype 'boolean' + +config variable + option name 'swapoctets' + option title 'Swap octets' + option description 'Swap the meaning of "input octets" and "output octets" as it related to RADIUS attribtues' + option section 'coovachilli.radius' + option datatype 'boolean' + +config variable + option name 'openidauth' + option title 'Allow OpenID authentication' + option description 'Allows OpenID authentication by sending ChilliSpot-Config=allow-openidauth in RADIUS Access-Requests' + option section 'coovachilli.radius' + option datatype 'boolean' + +config variable + option name 'wpaguests' + option title 'Allow WPA guests' + option description 'Allows WPA Guest authentication by sending ChilliSpot-Config=allow-wpa-guests in RADIUS Access-Requests' + option section 'coovachilli.radius' + option datatype 'boolean' + +config variable + option name 'radiusacctport' + option title 'RADIUS accounting port' + option description 'The UDP port number to use for radius accounting requests (default 1813)' + option section 'coovachilli.radius' + option datatype 'port' + +config variable + option name 'radiusauthport' + option title 'RADIUS authentication port' + option description 'The UDP port number to use for radius authentication requests (default 1812)' + option section 'coovachilli.radius' + option datatype 'port' + +config variable + option name 'radiuscalled' + option title 'Option radiuscalled' + option description '' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'radiuslisten' + option title 'RADIUS listen address' + option description 'Local interface IP address to use for the radius interface' + option section 'coovachilli.radius' + option datatype 'ip4addr' + +config variable + option name 'radiuslocationid' + option title 'RADIUS location ID' + option description 'WISPr Location ID' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'radiuslocationname' + option title 'RADIUS location name' + option description 'WISPr Location Name' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'radiusnasid' + option title 'NAS ID' + option description 'Network access server identifier' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'radiusnasip' + option title 'Option radiusnasip' + option description '' + option section 'coovachilli.radius' + option datatype 'ip4addr' + +config variable + option name 'radiusnasporttype' + option title 'NAS port type' + option description 'Value of NAS-Port-Type attribute. Defaults to 19 (Wireless-IEEE-802.11)' + option section 'coovachilli.radius' + option datatype 'port' + +config variable + option name 'radiussecret' + option title 'RADIUS secret' + option description 'Radius shared secret for both servers' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'radiusserver1' + option title 'RADIUS server 1' + option description 'The IP address of radius server 1' + option section 'coovachilli.radius' + option datatype 'host' + +config variable + option name 'radiusserver2' + option title 'RADIUS server 2' + option description 'The IP address of radius server 2' + option section 'coovachilli.radius' + option datatype 'host' + +config variable + option name 'nasip' + option title 'NAS IP' + option description 'Value to use in RADIUS NAS-IP-Address attribute' + option section 'coovachilli.radius' + option datatype 'ip4addr' + +config variable + option name 'nasmac' + option title 'NAS MAC' + option description 'MAC address value to use in RADIUS Called-Station-ID attribute' + option section 'coovachilli.radius' + option datatype 'macaddr' + +config variable + option name 'adminuser' + option title 'Admin user' + option description 'User-name to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'adminpasswd' + option title 'Admin password' + option description 'Password to use for Administrative-User authentication in order to pick up chilli configurations and establish a device "system" session' + option section 'coovachilli.radius' + option datatype 'string' + +config variable + option name 'coaport' + option title 'RADIUS disconnect port' + option description 'UDP port to listen to for accepting radius disconnect requests' + option section 'coovachilli.radius' + option datatype 'port' + +config variable + option name 'coanoipcheck' + option title 'Do not check disconnection requests' + option description 'Do not check the source IP address of radius disconnect requests' + option section 'coovachilli.radius' + option datatype 'boolean' + + +config section + option name 'proxy' + option title 'RADIUS proxy settings' + option description 'RADIUS proxy settings' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'proxyclient' + option title 'Proxy client' + option description 'IP address from which radius requests are accepted. If omitted the server will not accept radius requests' + option section 'coovachilli.proxy' + option datatype 'host' + +config variable + option name 'proxylisten' + option title 'Proxy listen address' + option description 'Local interface IP address to use for accepting radius requests' + option section 'coovachilli.proxy' + option datatype 'host' + +config variable + option name 'proxyport' + option title 'Proxy port' + option description 'UDP Port to listen to for accepting radius requests' + option section 'coovachilli.proxy' + option datatype 'port' + +config variable + option name 'proxysecret' + option title 'Proxy secret' + option description 'Radius shared secret for clients' + option section 'coovachilli.proxy' + option datatype 'string' + + +config section + option name 'uam' + option title 'UAM settings' + option description 'Unified Configuration Method settings' + option package 'coovachilli' + option unique true + option required true + +config variable + option name 'uamanydns' + option title 'Allow any DNS server' + option description 'Allow any DNS server for unauthenticated clients' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'uamanyip' + option title 'Allow any IP address' + option description 'Allow clients to use any IP settings they wish by spoofing ARP (experimental)' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'dnsparanoia' + option title 'Inspect DNS traffic' + option description 'Inspect DNS packets and drop responses with any non- A, CNAME, SOA, or MX records to prevent dns tunnels (experimental)' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'nouamsuccess' + option title 'Do not redirect to UAM server' + option description 'Do not return to UAM server on login success, just redirect to original URL' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'nouamwispr' + option title 'Do not do WISPr' + option description 'Do not do any WISPr XML, assume the back-end is doing this instead' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'usestatusfile' + option title 'Use status file' + option description 'Write the status of clients in a non-volatile state file (experimental)' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'chillixml' + option title 'Use Chilli XML' + option description 'Return the so-called Chilli XML along with WISPr XML' + option section 'coovachilli.uam' + option datatype 'boolean' + +config variable + option name 'uamui' + option title 'UAM user interface' + option description 'An init.d style program to handle local content on the uamuiport web server' + option section 'coovachilli.uam' + option datatype 'file' + +config variable + option name 'uamallowed' + option title 'Allowed resources' + option description 'List of resources the client can access without first authenticating' + option section 'coovachilli.uam' + option datatype 'string' + option type 'list' + +config variable + option name 'uamdomain' + option title 'Allowed domains' + option description 'Defines a list of domain names to automatically add to the walled garden' + option section 'coovachilli.uam' + option datatype 'string' + option type 'list' + +config variable + option name 'uamhomepage' + option title 'UAM homepage' + option description 'URL of homepage to redirect unauthenticated users to' + option section 'coovachilli.uam' + option datatype 'string' + +config variable + option name 'uamlisten' + option title 'UAM listening address' + option description 'IP address to listen to for authentication of clients' + option section 'coovachilli.uam' + option datatype 'host' + +config variable + option name 'uamport' + option title 'UAM listening port' + option description 'TCP port to bind to for authenticating clients (default 3990)' + option section 'coovachilli.uam' + option datatype 'port' + +config variable + option name 'uamiport' + option title 'UAM static content port' + option description 'TCP port to bind to for only serving embedded content' + option section 'coovachilli.uam' + option datatype 'port' + +config variable + option name 'uamsecret' + option title 'UAM secret' + option description 'Shared secret between uamserver and chilli' + option section 'coovachilli.uam' + option datatype 'string' + option required true + +config variable + option name 'uamserver' + option title 'UAM server' + option description 'URL of web server to use for authenticating clients' + option section 'coovachilli.uam' + option datatype 'string' + +config variable + option name 'uamlogoutip' + option title 'UAM logout IP' + option description 'Use this IP address to instantly logout a client accessing it (defaults to 1.1.1.1)' + option section 'coovachilli.uam' + option datatype 'ip4addr' + +config variable + option name 'wisprlogin' + option title 'WISPr login url' + option description 'Specific URL to be given in WISPr XML LoginURL' + option section 'coovachilli.uam' + option datatype 'string' + +config variable + option name 'defsessiontimeout' + option title 'Default session timeout' + option description 'Default session timeout unless otherwise set by RADIUS (defaults to 0)' + option section 'coovachilli.uam' + option datatype 'uint' + +config variable + option name 'defidletimeout' + option title 'Default idle timeout' + option description 'Default idle timeout unless otherwise set by RADIUS (defaults to 0)' + option section 'coovachilli.uam' + option datatype 'uint' + +config variable + option name 'definteriminterval' + option title 'Default interim interval' + option description 'Default interim-interval for RADIUS accounting unless otherwise set by RADIUS (defaults to 0)' + option section 'coovachilli.uam' + option datatype 'uint' + +config variable + option name 'wwwdir' + option title 'Web content directory' + option description 'Directory where embedded local web content is placed' + option section 'coovachilli.uam' + option datatype 'directory' + +config variable + option name 'wwwbin' + option title 'CGI program' + option description 'Executable to run as a CGI type program (like haserl) for URLs with extention .chi' + option section 'coovachilli.uam' + option datatype 'file' + +config variable + option name 'localusers' + option title 'Local users file' + option description 'A colon seperated file containing usernames and passwords of locally authenticated users' + option section 'coovachilli.uam' + option datatype 'file' + +config variable + option name 'postauthproxy' + option title 'Post auth proxy' + option description 'Used with postauthproxyport to define a post authentication HTTP proxy server' + option section 'coovachilli.uam' + option datatype 'file' + +config variable + option name 'postauthproxyport' + option title 'Post auth proxy port' + option description 'Used with postauthproxy to define a post authentication HTTP proxy server' + option section 'coovachilli.uam' + option datatype 'file' + +config variable + option name 'locationname' + option title 'Location name' + option description 'Human readable location name used in JSON interface' + option section 'coovachilli.uam' + option datatype 'file' diff --git a/applications/community-hannover/Makefile b/applications/luci-openvpn/Makefile similarity index 100% rename from applications/community-hannover/Makefile rename to applications/luci-openvpn/Makefile diff --git a/applications/luci-openvpn/luasrc/controller/openvpn.lua b/applications/luci-openvpn/luasrc/controller/openvpn.lua new file mode 100644 index 0000000000..64b20d4f78 --- /dev/null +++ b/applications/luci-openvpn/luasrc/controller/openvpn.lua @@ -0,0 +1,24 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: openvpn.lua 3549 2008-10-09 22:24:21Z jow $ +]]-- +module("luci.controller.openvpn", package.seeall) + +function index() + require("luci.i18n") + luci.i18n.loadc("openvpn") + + entry( {"admin", "services", "openvpn"}, cbi("openvpn"), luci.i18n.translate("openvpn", "OpenVPN") ).i18n = "openvpn" + entry( {"admin", "services", "openvpn", "basic"}, cbi("openvpn-basic"), nil ).leaf = true + entry( {"admin", "services", "openvpn", "advanced"}, cbi("openvpn-advanced"), nil ).leaf = true +end diff --git a/applications/luci-openvpn/luasrc/i18n/openvpn.en.lua b/applications/luci-openvpn/luasrc/i18n/openvpn.en.lua new file mode 100644 index 0000000000..b56e5780d2 --- /dev/null +++ b/applications/luci-openvpn/luasrc/i18n/openvpn.en.lua @@ -0,0 +1,196 @@ +openvpn="OpenVPN" + +openvpn_switch_basic="« Switch to basic configuration" +openvpn_switch_advanced="Switch to advanced configuration »" + +openvpn_enable="Enabled" +openvpn_active="Started" +openvpn_active_no="no" +openvpn_active_yes="yes (%i)" +openvpn_port="Port" +openvpn_proto="Protocol" + +openvpn_instance="Instance \"%s\"" + +openvpn_overview="OpenVPN instances" +openvpn_overview_desc="Below is a list of configured OpenVPN instances and their current state" + +openvpn_service="Daemon configuration" +openvpn_networking="Networking options" +openvpn_vpn="VPN options" +openvpn_cryptography="Cryptography settings" + +openvpn_param_config="Read configuration options from file" +openvpn_param_local="Local host name or ip address" +openvpn_param_remote="Remote host name or ip address" +openvpn_param_remote_random="Randomly choose remote server" +openvpn_param_mode="Major mode" +openvpn_param_proto="Use protocol" +openvpn_param_connect_retry="Connection retry interval" +openvpn_param_connect_timeout="Connection timeout" +openvpn_param_connect_retry_max="Maximum connection attempt retries" +openvpn_param_auto_proxy="Try to sense proxy settings automatically" +openvpn_param_http_proxy="Connect to remote host" +openvpn_param_http_proxy_retry="Retry indefinitely on HTTP proxy errors" +openvpn_param_http_proxy_timeout="Proxy timeout in seconds" +openvpn_param_http_proxy_option="Set extended HTTP proxy options" +openvpn_param_socks_proxy="Connect through Socks5 proxy" +openvpn_param_socks_proxy_retry="Retry indefinitely on Socks proxy errors" +openvpn_param_resolv_retry="If hostname resolve fails, retry" +openvpn_param_float="Allow remote to change its IP or port" +openvpn_param_ipchange="Execute shell command on remote ip change" +openvpn_param_port="TCP/UDP port # for both local and remote" +openvpn_param_lport="TCP/UDP port # for local (default=1194)" +openvpn_param_rport="TCP/UDP port # for remote (default=1194)" +openvpn_param_bind="Bind to local address and port" +openvpn_param_nobind="Do not bind to local address and port" +openvpn_param_dev="tun/tap device" +openvpn_param_dev_type="Type of used device" +openvpn_param_dev_node="Use tun/tap device node" +openvpn_param_lladdr="Set the link layer address of the tap device" +openvpn_param_topology="'net30', 'p2p', or 'subnet'" +openvpn_param_tun_ipv6="Make tun device IPv6 capable" +openvpn_param_ifconfig="Configure device to use IP address" +openvpn_param_ifconfig_noexec="Don't actually execute ifconfig" +openvpn_param_ifconfig_nowarn="Don't warn on ifconfig inconsistencies" +openvpn_param_route="Add route after establishing connection" +openvpn_param_route_gateway="Specify a default gateway for routes" +openvpn_param_route_metric="Specify a default metric for routes" +openvpn_param_route_delay="Delay n seconds after connection " +openvpn_param_route_up="Execute shell cmd after routes are added" +openvpn_param_route_noexec="Don't add routes automatically" +openvpn_param_route_nopull="Don't pull options from server" +openvpn_param_redirect_gateway="Automatically redirect default route" +openvpn_param_setenv="Pass environment variables to script" +openvpn_param_shaper="Shaping for peer bandwidth" +openvpn_param_keepalive="Set timeouts in server mode" +openvpn_param_inactive="tun/tap inactivity timeout" +openvpn_param_ping_exit="Remote ping timeout" +openvpn_param_ping_restart="Restart after remote ping timeout" +openvpn_param_ping_timer_rem="Only process ping timeouts if routes exist" +openvpn_param_ping="Ping remote every n seconds over TCP/UDP port" +openvpn_param_multihome="Configure a multi-homed UDP server" +openvpn_param_fast_io="Optimize TUN/TAP/UDP writes" +openvpn_param_remap_usr1="Remap SIGUSR1 signals" +openvpn_param_persist_tun="Keep tun/tap device open on restart" +openvpn_param_persist_remote_ip="Keep remote IP address on restart" +openvpn_param_persist_local_ip="Keep local IP address on restart" +openvpn_param_persist_key="Don't re-read key on restart" +openvpn_param_passtos="TOS passthrough (applies to IPv4 only)" +openvpn_param_tun_mtu="Set tun/tap device MTU" +openvpn_param_tun_mtu_extra="Set tun/tap device overhead" +openvpn_param_link_mtu="Set TCP/UDP MTU" +openvpn_param_mtu_disc="Enable Path MTU discovery" +openvpn_param_mtu_test="Empirically measure MTU" +openvpn_param_fragment="Enable internal datagram fragmentation" +openvpn_param_mssfix="Set upper bound on TCP MSS" +openvpn_param_sndbuf="Set the TCP/UDP send buffer size" +openvpn_param_rcvbuf="Set the TCP/UDP receive buffer size" +openvpn_param_txqueuelen="Set tun/tap TX queue length" +openvpn_param_mlock="Disable Paging" +openvpn_param_up="Shell cmd to execute after tun device open" +openvpn_param_up_delay="Delay tun/tap open and up script execution" +openvpn_param_down="Shell cmd to run after tun device close" +openvpn_param_down_pre="Call down cmd/script before TUN/TAP close" +openvpn_param_up_restart="Run up/down scripts for all restarts" +openvpn_param_user="Set UID to user" +openvpn_param_group="Set GID to group" +openvpn_param_chroot="Chroot to directory after initialization" +openvpn_param_cd="Change to directory before initialization" +openvpn_param_daemon="Daemonize after initialization" +openvpn_param_syslog="Output to syslog and do not daemonize" +openvpn_param_inetd="Run as an inetd or xinetd server" +openvpn_param_log="Write log to file" +openvpn_param_log_append="Append log to file" +openvpn_param_suppress_timestamps="Don't log timestamps" +openvpn_param_writepid="Write process ID to file" +openvpn_param_nice="Change process priority" +openvpn_param_echo="Echo parameters to log" +openvpn_param_verb="Set output verbosity" +openvpn_param_mute="Limit repeated log messages" +openvpn_param_status="Write status to file every n seconds" +openvpn_param_status_version="Status file format version" +openvpn_param_disable_occ="Disable options consistency check" +openvpn_param_gremlin="Special stress testing mode" +openvpn_param_comp_lzo="Use fast LZO compression" +openvpn_param_comp_noadapt="Don't use adaptive lzo compression" +openvpn_param_management="Enable TCP server on ip:port" +openvpn_param_management_client="Management interface will connect as a TCP client" +openvpn_param_management_query_passwords="Query management channel for private key" +openvpn_param_management_hold="Start OpenVPN in a hibernating state" +openvpn_param_management_signal="Issue SIGUSR1 on management disconnect" +openvpn_param_management_forget_disconnect="Forget passwords on management disconnect" +openvpn_param_management_log_cache="Number of lines for log file history" +openvpn_param_plugin="Load plug-in module" +openvpn_param_server="Configure server mode" +openvpn_param_server_bridge="Configure server bridge" +openvpn_param_push="Push options to peer" +openvpn_param_push_reset="Don't inherit global push options" +openvpn_param_ifconfig_pool="Set aside a pool of subnets" +openvpn_param_ifconfig_pool_linear="Use individual addresses rather than /30 subnets" +openvpn_param_ifconfig_pool_persist="Persist/unpersist ifconfig-pool" +openvpn_param_ifconfig_push="Push an ifconfig option to remote" +openvpn_param_iroute="Route subnet to client" +openvpn_param_disable="Client is disabled" +openvpn_param_client_cert_not_required="Don't require client certificate" +openvpn_param_username_as_common_name="Use username as common name" +openvpn_param_auth_user_pass_verify="Script to verify interactive authentication" +openvpn_param_client_to_client="Allow client-to-client traffic" +openvpn_param_duplicate_cn="Allow multiple clients with same certificate" +openvpn_param_client_connect="Run script cmd on client connection" +openvpn_param_client_disconnect="Run script cmd on client disconnection" +openvpn_param_client_config_dir="Directory for custom client config files" +openvpn_param_ccd_exclusive="Refuse connection if no custom client config" +openvpn_param_tmp_dir="Temporary directory for client-connect return file" +openvpn_param_hash_size="Set size of real and virtual address hash tables" +openvpn_param_bcast_buffers="Number of allocated broadcast buffers" +openvpn_param_tcp_queue_limit="Maximum number of queued TCP output packets" +openvpn_param_learn_address="Script to validate client virtual addresses" +openvpn_param_connect_freq="Allowed maximum of new connections" +openvpn_param_max_clients="Allowed maximum of connected clients" +openvpn_param_max_routes_per_client="Allowed maximum of internal" +openvpn_param_port_share="Proxy incoming HTTPS sessions" +openvpn_param_client="Configure client mode" +openvpn_param_auth_user_pass="Authenticate using username/password" +openvpn_param_pull="Accept options pushed from server" +openvpn_param_auth_retry="Handling of authentication failures" +openvpn_param_explicit_exit_notify="Send notification to peer on disconnect" +openvpn_param_secret="Enable Static Key encryption mode (non-TLS)" +openvpn_param_auth="HMAC authentication for packets" +openvpn_param_cipher="Encryption cipher for packets" +openvpn_param_keysize="Size of cipher key" +openvpn_param_engine="Enable OpenSSL hardware crypto engines" +openvpn_param_no_replay="Disable replay protection" +openvpn_param_mute_replay_warnings="Silence the output of replay warnings" +openvpn_param_replay_window="Replay protection sliding window size" +openvpn_param_no_iv="Disable cipher initialisation vector" +openvpn_param_replay_persist="Persist replay-protection state" +openvpn_param_test_crypto="Run a self-test of crypto features" +openvpn_param_tls_server="Enable TLS and assume server role" +openvpn_param_tls_client="Enable TLS and assume client role" +openvpn_param_key_method="Data channel key exchange method" +openvpn_param_ca="Certificate authority" +openvpn_param_capath="Directory of trusted certificates (CAs and CRLs)" +openvpn_param_dh="Diffie Hellman parameters" +openvpn_param_cert="Local certificate" +openvpn_param_key="Local private key" +openvpn_param_pkcs12="PKCS#12 file containing keys" +openvpn_param_tls_cipher="TLS cipher" +openvpn_param_tls_timeout="Retransmit timeout on TLS control channel" +openvpn_param_reneg_bytes="Renegotiate data chan. key after bytes" +openvpn_param_reneg_pkts="Renegotiate data chan. key after packets" +openvpn_param_reneg_sec="Renegotiate data chan. key after seconds" +openvpn_param_hand_window="Timeframe for key exchange" +openvpn_param_tran_window="Key transition window" +openvpn_param_single_session="Allow only one session" +openvpn_param_tls_exit="Exit on TLS negotiation failure" +openvpn_param_tls_auth="Additional authentication over TLS" +openvpn_param_askpass="Get PEM password from controlling tty before we daemonize" +openvpn_param_auth_nocache="Don't cache --askpass or --auth-user-pass passwords" +openvpn_param_crl_verify="Check peer certificate against a CRL" +openvpn_param_tls_verify="Shell command to verify X509 name" +openvpn_param_tls_remote="Only accept connections from given X509 name" +openvpn_param_ns_cert_type="Require explicit designation on certificate" +openvpn_param_remote_cert_ku="Require explicit key usage on certificate" +openvpn_param_remote_cert_eku="Require extended explicit key usage on certificate" +openvpn_param_remote_cert_tls="Require normal and extended key usage on certificate" diff --git a/applications/luci-openvpn/luasrc/model/cbi/openvpn-advanced.lua b/applications/luci-openvpn/luasrc/model/cbi/openvpn-advanced.lua new file mode 100644 index 0000000000..65ad1c7a4d --- /dev/null +++ b/applications/luci-openvpn/luasrc/model/cbi/openvpn-advanced.lua @@ -0,0 +1,271 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: openvpn-advanced.lua 3551 2008-10-10 11:48:04Z jow $ +]]-- + +require("luci.fs") +require("luci.ip") + + +local knownParams = { + -- + -- Widget Name Optn. Default(s) + -- + + { "service", { + -- initialisation and daemon options + { ListValue, "verb", { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } }, + { Flag, "mlock", 0 }, + { Flag, "disable_occ", 0 }, + -- { Value, "user", "root" }, + -- { Value, "group", "root" }, + { Value, "cd", "/etc/openvpn" }, + { Value, "chroot", "/var/run" }, + -- { Value, "daemon", "Instance-Name" }, + -- { Value, "syslog", "Instance-Name" }, + { Flag, "passtos", 0 }, + -- { Value, "inetd", "nowait Instance-Name" }, + { Value, "log", "/var/log/openvpn.log" }, + { Value, "log_append", "/var/log/openvpn.log" }, + { Flag, "suppress_timestamps", 0 }, + -- { Value, "writepid", "/var/run/openvpn.pid" }, + { Value, "nice", 0 }, + { Flag, "fast_io", 0 }, + { Value, "echo", "some params echoed to log" }, + { ListValue, "remap_usr1", { "SIGHUP", "SIGTERM" } }, + { Value, "status", "/var/run/openvpn.status 5" }, + { Value, "status_version", { 1, 2 } }, -- status + { Value, "mute", 5 }, + + { Value, "up", "/usr/bin/ovpn-up" }, + { Value, "up_delay", 5 }, + { Value, "down", "/usr/bin/ovpn-down" }, + { Flag, "down_pre", 0 }, + { Flag, "up_restart", 0 }, + { Value, "route_up", "/usr/bin/ovpn-routeup" }, + { Value, "ipchange", "/usr/bin/ovpn-ipchange", { mode="p2p" } }, + { DynamicList, "setenv", { "VAR1 value1", "VAR2 value2" } }, + { Value, "tls_verify", "/usr/bin/ovpn-tlsverify" }, + { Value, "client_connect", "/usr/bin/ovpn-clientconnect" }, + { Flag, "client_disconnect", 0 }, + { Value, "learn_address", "/usr/bin/ovpn-learnaddress" }, + { Value, "auth_user_pass_verify", "/usr/bin/ovpn-userpass via-env" }, + } }, + + { "networking", { + -- socket config + { ListValue, "mode", { "p2p", "server" } }, + { Value, "local", "0.0.0.0" }, + { Value, "port", 1194 }, + { Value, "lport", 1194 }, + { Value, "rport", 1194 }, + { Flag, "float", 0 }, + { Flag, "nobind", 0 }, + + { Value, "dev", "tun0" }, + { ListValue, "dev_type", { "tun", "tap" } }, + { Value, "dev_node", "/dev/net/tun" }, + { Flag, "tun_ipv6", 0 }, + + { Value, "ifconfig", "10.200.200.3 10.200.200.1" }, + { Flag, "ifconfig_noexec", 0 }, + { Flag, "ifconfig_nowarn", 0 }, + + { DynamicList, "route", "10.123.0.0 255.255.0.0" }, + { Value, "route_gateway", "10.234.1.1" }, + { Value, "route_delay", 0 }, + { Flag, "route_noexec", 0 }, + + { ListValue, "mtu_disc", { "yes", "maybe", "no" } }, + { Flag, "mtu_test", 0 }, + { Flag, "comp_lzo", 0 }, + { Flag, "comp_noadept", 0, { comp_lzo=1 } }, + { Value, "link_mtu", 1500 }, + { Value, "tun_mtu", 1500 }, + { Value, "tun_mtu_extra", 1500 }, + { Value, "fragment", 1500, { proto="udp" } }, + { Value, "mssfix", 1500, { proto="udp" } }, + { Value, "sndbuf", 65536 }, + { Value, "rcvbuf", 65536 }, + { Value, "txqueuelen", 100 }, + { Value, "shaper", 10240 }, + + { Value, "inactive", 240 }, + { Value, "keepalive", "10 60" }, + { Value, "ping", 30 }, + { Value, "ping_exit", 120 }, + { Value, "ping_restart", 60 }, + { Flag, "ping_timer_rem", 0 }, + + { Flag, "persist_tun", 0 }, + { Flag, "persist_key", 0 }, + { Flag, "persist_local_ip", 0 }, + { Flag, "persist_remote_ip", 0 }, + + -- management channel + { Value, "management", "127.0.0.1 31194 /etc/openvpn/mngmt-pwds" }, + { Flag, "management_query_passwords", 0 }, -- management + { Flag, "management_hold", 0 }, -- management + { Flag, "management_log_cache", 100 }, -- management + } }, + + { "vpn", { + { Value, "server", "10.200.200.0 255.255.255.0", { server_mode="1" } }, + { Value, "server_bridge", "10.200.200.1 255.255.255.0 10.200.200.200 10.200.200.250", { server_mode="1" } }, + { DynamicList, "push", { "redirect-gateway", "comp-lzo" }, { server_mode="1" } }, + { Flag, "push_reset", 0, { server_mode="1" } }, + { Flag, "disable", 0, { server_mode="1" } }, + { Value, "ifconfig_pool", "10.200.200.100 10.200.200.150 255.255.255.0", { server_mode="1" } }, + { Value, "ifconfig_pool_persist", "/etc/openvpn/ipp.txt 600", { server_mode="1" } }, + { Flag, "ifconfig_pool_linear", 0, { server_mode="1" } }, + { Value, "ifconfig_push", "10.200.200.1 255.255.255.255", { server_mode="1" } }, + { Value, "iroute", "10.200.200.0 255.255.255.0", { server_mode="1" } }, + { Flag, "client_to_client", 0, { server_mode="1" } }, + { Flag, "duplicate_cn", 0, { server_mode="1" } }, + { Value, "client_config_dir", "/etc/openvpn/ccd", { server_mode="1" } }, + { Flag, "ccd_exclusive", 0, { server_mode="1" } }, + { Value, "tmp_dir", "/var/run/openvpn", { server_mode="1" } }, + { Value, "hash_size", "256 256", { server_mode="1" } }, + { Value, "bcast_buffers", 256, { server_mode="1" } }, + { Value, "tcp_queue_limit", 64, { server_mode="1" } }, + { Value, "max_clients", 10, { server_mode="1" } }, + { Value, "max_routes_per_client", 256, { server_mode="1" } }, + { Value, "connect_freq", "3 10", { server_mode="1" } }, + { Flag, "client_cert_not_required", 0, { server_mode="1" } }, + { Flag, "username_as_common_name", 0, { server_mode="1" } }, + { Flag, "client", 0, { server_mode="0" }, { server_mode="" } }, + { Flag, "pull", 0, { client="1" } }, + { Value, "auth_user_pass", "/etc/openvpn/userpass.txt", { client="1" } }, + { ListValue, "auth_retry", { "none", "nointeract", "interact" }, { client="1" } }, + { Value, "explicit_exit_notify", 1, { client="1" } }, + { DynamicList, "remote", "1.2.3.4", { client="1" } }, -- client + { Flag, "remote_random", 1, { client="1" } }, -- client + { ListValue, "proto", { "udp", "tcp-client", "tcp-server" }, { client="1" } }, + { Value, "connect_retry", 5, { proto="tcp-client" }, { client="1" } }, -- client && proto=tcp-client + { Value, "http_proxy_server", "192.168.1.100 8080", { client="1" } }, -- client + { Flag, "http_proxy_retry", 0, { client="1" } }, -- client && http_proxy_server + { Value, "http_proxy_timeout", 5, { client="1" } }, -- client && http_proxy_server + { DynamicList, "http_proxy_option", { "VERSION 1.0", "AGENT OpenVPN/2.0.9" }, { client="1" } }, -- client && http_proxy_server + { Value, "socks_proxy_server", "192.168.1.200 1080", { client="1" } }, -- client + { Value, "socks_proxy_retry", 5, { client="1" } }, -- client && socks_proxy_server + { Value, "resolv_retry", "infinite", { client="1" } }, -- client + { ListValue, "redirect_gateway", { "", "local", "def1", "local def1" }, { client="1" } }, -- client + } }, + + { "cryptography", { + { Value, "secret", "/etc/openvpn/secret.key 1" }, + { Value, "auth", "SHA1" }, -- parse + { Value, "cipher", "BF-CBC" }, -- parse + { Value, "keysize", 1024 }, -- parse + { Value, "engine", "dynamic" }, -- parse + { Flag, "no_replay", 0 }, + { Value, "replay_window", "64 15" }, + { Flag, "mute_replay_warnings", 0 }, + { Value, "replay_persist", "/var/run/openvpn-replay-state" }, + { Flag, "no_iv", 0 }, + { Flag, "tls_server", 0, { tls_client="" }, { tls_client="0" } }, + { Flag, "tls_client", 0, { tls_server="" }, { tls_server="0" } }, + { Value, "ca", "/etc/easy-rsa/keys/ca.crt" }, + { Value, "dh", "/etc/easy-rsa/keys/dh1024.pem" }, + { Value, "cert", "/etc/easy-rsa/keys/some-client.crt" }, + { Value, "key", "/etc/easy-rsa/keys/some-client.key" }, + { Value, "pkcs12", "/etc/easy-rsa/keys/some-client.pk12" }, + { ListValue, "key_method", { 1, 2 } }, + { Value, "tls_cipher", "DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DES-CBC3-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:AES128-SHA:RC4-SHA:RC4-MD5:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DES-CBC-SHA:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC4-MD5" }, + { Value, "tls_timeout", 2 }, + { Value, "reneg_bytes", 1024 }, + { Value, "reneg_pkts", 100 }, + { Value, "reneg_sec", 3600 }, + { Value, "hand_window", 60 }, + { Value, "tran_window", 3600 }, + { Flag, "single_session", 0 }, + { Flag, "tls_exit", 0 }, + { Value, "tls_auth", "/etc/openvpn/tlsauth.key 1" }, + --{ Value, "askpass", "[file]" }, + { Flag, "auth_nocache", 0 }, + { Value, "tls_remote", "remote_x509_name" }, + { ListValue, "ns_cert_type", { "client", "server" } }, + { Value, "crl_verify", "/etc/easy-rsa/keys/crl.pem" }, + } } +} + + +local cts = { } +local params = { } + +local m = Map("openvpn") +local p = m:section( SimpleSection ) + +p.template = "openvpn/pageswitch" +p.mode = "advanced" +p.instance = arg[1] +p.category = arg[2] or "service" + +for _, c in ipairs(knownParams) do + cts[#cts+1] = c[1] + if c[1] == p.category then params = c[2] end +end + +p.categories = cts + + +local s = m:section( + NamedSection, arg[1], "openvpn", + translate("openvpn_%s" % arg[2]), + translate("openvpn_%s_desc" % arg[2]) +) + +s.title = translate("openvpn_%s" % arg[2]) +s.addremove = false +s.anonymous = true + + +for _, option in ipairs(params) do + local o = s:option( + option[1], option[2], + translate("openvpn_param_%s" % option[2]), + translate("openvpn_param_%s_desc" % option[2]) + ) + + if option[1] == DummyValue then + o.value = option[3] + else + if option[1] == DynamicList then + o.cast = nil + function o.cfgvalue(...) + local val = AbstractValue.cfgvalue(...) + return ( val and type(val) ~= "table" ) and { val } or val + end + end + + o.optional = true + + if type(option[3]) == "table" then + if o.optional then o:value("", "-- remove --") end + for _, v in ipairs(option[3]) do + v = tostring(v) + o:value(v) + end + o.default = tostring(option[3][1]) + else + o.default = tostring(option[3]) + end + end + + for i=5,#option do + if type(option[i]) == "table" then + o:depends(option[i]) + end + end +end + +return m diff --git a/applications/luci-openvpn/luasrc/model/cbi/openvpn-basic.lua b/applications/luci-openvpn/luasrc/model/cbi/openvpn-basic.lua new file mode 100644 index 0000000000..9a4901a782 --- /dev/null +++ b/applications/luci-openvpn/luasrc/model/cbi/openvpn-basic.lua @@ -0,0 +1,102 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: openvpn-basic.lua 3551 2008-10-10 11:48:04Z jow $ +]]-- + +require("luci.fs") +require("luci.ip") +require("luci.model.uci") + + +local basicParams = { + -- + -- Widget Name Optn. Default(s) + -- + + { ListValue, "verb", { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } }, + { Value, "nice", 0 }, + { Value, "port", 1194 }, + { ListValue, "dev_type", { "tun", "tap" } }, + { Flag, "tun_ipv6", 0 }, + + { Value, "ifconfig", "10.200.200.3 10.200.200.1" }, + { Value, "server", "10.200.200.0 255.255.255.0" }, + { Value, "server_bridge", "192.168.1.1 255.255.255.0 192.168.1.128 192.168.1.254" }, + { Flag, "nobind", 0 }, + + { Flag, "comp_lzo", 0 }, + { Value, "keepalive", "10 60" }, + + { ListValue, "proto", { "udp", "tcp" } }, + + { Flag, "client", 0 }, + { Flag, "client_to_client", 0 }, + { DynamicList, "remote", "vpnserver.example.org" }, + + { Value, "secret", "/etc/openvpn/secret.key 1" }, + { Value, "ca", "/etc/easy-rsa/keys/ca.crt" }, + { Value, "dh", "/etc/easy-rsa/keys/dh1024.pem" }, + { Value, "cert", "/etc/easy-rsa/keys/some-client.crt" }, + { Value, "key", "/etc/easy-rsa/keys/some-client.key" }, +} + + +local m = Map("openvpn") +local p = m:section( SimpleSection ) + +p.template = "openvpn/pageswitch" +p.mode = "basic" +p.instance = arg[1] + + +local s = m:section( NamedSection, arg[1], "openvpn" ) + +for _, option in ipairs(basicParams) do + local o = s:option( + option[1], option[2], + translate("openvpn_param_%s" % option[2]), + translate("openvpn_param_%s_desc" % option[2]) + ) + + o.optional = true + + if option[1] == DummyValue then + o.value = option[3] + else + if option[1] == DynamicList then + o.cast = nil + function o.cfgvalue(...) + local val = AbstractValue.cfgvalue(...) + return ( val and type(val) ~= "table" ) and { val } or val + end + end + + if type(option[3]) == "table" then + if o.optional then o:value("", "-- remove --") end + for _, v in ipairs(option[3]) do + v = tostring(v) + o:value(v) + end + o.default = tostring(option[3][1]) + else + o.default = tostring(option[3]) + end + end + + for i=5,#option do + if type(option[i]) == "table" then + o:depends(option[i]) + end + end +end + +return m diff --git a/applications/luci-openvpn/luasrc/model/cbi/openvpn.lua b/applications/luci-openvpn/luasrc/model/cbi/openvpn.lua new file mode 100644 index 0000000000..ed2b6b8127 --- /dev/null +++ b/applications/luci-openvpn/luasrc/model/cbi/openvpn.lua @@ -0,0 +1,101 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: openvpn.lua 3551 2008-10-10 11:48:04Z jow $ +]]-- + +require("luci.fs") +require("luci.ip") +require("luci.sys") +require("luci.model.uci") + + +local uci = luci.model.uci.cursor() + +local m = Map("openvpn", translate("openvpn")) +local s = m:section( TypedSection, "openvpn", translate("openvpn_overview"), translate("openvpn_overview_desc") ) +s.template = "cbi/tblsection" +s.template_addremove = "openvpn/cbi-select-input-add" +s.addremove = true +s.add_select_options = { } +s.extedit = luci.dispatcher.build_url( + "admin", "services", "openvpn", "basic", "%s" +) + +uci:load("openvpn_recipes") +uci:foreach( "openvpn_recipes", "openvpn_recipe", + function(section) + s.add_select_options[section['.name']] = + section['_description'] or section['.name'] + end +) + +function s.parse(self, section) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + if recipe and not s.add_select_options[recipe] then + self.invalid_cts = true + else + TypedSection.parse( self, section ) + end +end + +function s.create(self, name) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + uci:section( + "openvpn", "openvpn", name, + uci:get_all( "openvpn_recipes", recipe ) + ) + + uci:delete("openvpn", name, "_role") + uci:delete("openvpn", name, "_description") + uci:save("openvpn") + + luci.http.redirect( self.extedit:format(name) ) +end + + +s:option( Flag, "enable", translate("openvpn_enable") ) + +local active = s:option( DummyValue, "_active", translate("openvpn_active") ) +function active.cfgvalue(self, section) + if luci.fs.isfile("/var/run/openvpn_%s.pid" % section) then + local pid = io.lines("/var/run/openvpn_%s.pid" % section)() + if pid and #pid > 0 and tonumber(pid) ~= nil then + return (luci.sys.process.signal(pid, 0)) + and translatef("openvpn_active_yes", pid) + or translate("openvpn_active_no") + end + end + return translate("openvpn_active_no") +end + +local port = s:option( DummyValue, "port", translate("openvpn_port") ) +function port.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "1194" +end + +local proto = s:option( DummyValue, "proto", translate("openvpn_proto") ) +function proto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "udp" +end + + +return m diff --git a/applications/luci-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm b/applications/luci-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm new file mode 100644 index 0000000000..0744cf88b6 --- /dev/null +++ b/applications/luci-openvpn/luasrc/view/openvpn/cbi-select-input-add.htm @@ -0,0 +1,11 @@ +
+ <% if self.invalid_cts then -%>
<% end %> + + + + <% if self.invalid_cts then %>
<%:cbi_invalid%>
<% end %> +
diff --git a/applications/luci-openvpn/luasrc/view/openvpn/pageswitch.htm b/applications/luci-openvpn/luasrc/view/openvpn/pageswitch.htm new file mode 100644 index 0000000000..a99fbd9cf3 --- /dev/null +++ b/applications/luci-openvpn/luasrc/view/openvpn/pageswitch.htm @@ -0,0 +1,39 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: pageswitch.htm 3551 2008-10-10 11:48:04Z jow $ + +-%> + +
+ + "><%:openvpn_overview Overview%> » + <%=luci.i18n.translatef("openvpn_instance", "%s", self.instance)%> + + + <% if self.mode == "basic" then %> + "><%:openvpn_switch_advanced Switch to advanced configuration »%> + <% else %> + "><%:openvpn_switch_basic « Switch to basic configuration%> +
+ <%:openvpn_confcategory Configuration category%>: + <% for i, c in ipairs(self.categories) do %> + <% if c == self.category then %> + <%=translate("openvpn_%s" % c, c)%> + <% else %> + "><%=translate("openvpn_%s" % c, c)%> + <% end %> + <% if next(self.categories, i) then %>|<% end %> + <% end %> + <% end %> +
diff --git a/applications/luci-openvpn/root/etc/config/openvpn b/applications/luci-openvpn/root/etc/config/openvpn new file mode 100644 index 0000000000..9831ad15a1 --- /dev/null +++ b/applications/luci-openvpn/root/etc/config/openvpn @@ -0,0 +1,383 @@ +################################################# +# Sample OpenVPN 2.0 config file for # +# multi-client server. # +################################################# + +config openvpn sample_server + + # Set to 1 to enable this instance: + option enable 0 + + # Which local IP address should OpenVPN + # listen on? (optional) +# option local 0.0.0.0 + + # Which TCP/UDP port should OpenVPN listen on? + # If you want to run multiple OpenVPN instances + # on the same machine, use a different port + # number for each one. You will need to + # open up this port on your firewall. + option port 1194 + + # TCP or UDP server? +# option proto tcp + option proto udp + + # "dev tun" will create a routed IP tunnel, + # "dev tap" will create an ethernet tunnel. + # Use "dev tap0" if you are ethernet bridging + # and have precreated a tap0 virtual interface + # and bridged it with your ethernet interface. + # If you want to control access policies + # over the VPN, you must create firewall + # rules for the the TUN/TAP interface. + # On non-Windows systems, you can give + # an explicit unit number, such as tun0. + # On Windows, use "dev-node" for this. + # On most systems, the VPN will not function + # unless you partially or fully disable + # the firewall for the TUN/TAP interface. +# option dev tap + option dev tun + + # SSL/TLS root certificate (ca), certificate + # (cert), and private key (key). Each client + # and the server must have their own cert and + # key file. The server and all clients will + # use the same ca file. + # + # See the "easy-rsa" directory for a series + # of scripts for generating RSA certificates + # and private keys. Remember to use + # a unique Common Name for the server + # and each of the client certificates. + # + # Any X509 key management system can be used. + # OpenVPN can also use a PKCS #12 formatted key file + # (see "pkcs12" directive in man page). + option ca ca.crt + option cert server.crt + # This file should be kept secret: + option key server.key + + # Diffie hellman parameters. + # Generate your own with: + # openssl dhparam -out dh1024.pem 1024 + # Substitute 2048 for 1024 if you are using + # 2048 bit keys. + option dh dh1024.pem + + # Configure server mode and supply a VPN subnet + # for OpenVPN to draw client addresses from. + # The server will take 10.8.0.1 for itself, + # the rest will be made available to clients. + # Each client will be able to reach the server + # on 10.8.0.1. Comment this line out if you are + # ethernet bridging. See the man page for more info. + option server "10.8.0.0 255.255.255.0" + + # Maintain a record of client <-> virtual IP address + # associations in this file. If OpenVPN goes down or + # is restarted, reconnecting clients can be assigned + # the same virtual IP address from the pool that was + # previously assigned. + option ifconfig_pool_persist ipp.txt + + # Configure server mode for ethernet bridging. + # You must first use your OS's bridging capability + # to bridge the TAP interface with the ethernet + # NIC interface. Then you must manually set the + # IP/netmask on the bridge interface, here we + # assume 10.8.0.4/255.255.255.0. Finally we + # must set aside an IP range in this subnet + # (start=10.8.0.50 end=10.8.0.100) to allocate + # to connecting clients. Leave this line commented + # out unless you are ethernet bridging. +# option server_bridge "10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100" + + # Push routes to the client to allow it + # to reach other private subnets behind + # the server. Remember that these + # private subnets will also need + # to know to route the OpenVPN client + # address pool (10.8.0.0/255.255.255.0) + # back to the OpenVPN server. +# list push "route 192.168.10.0 255.255.255.0" +# list push "route 192.168.20.0 255.255.255.0" + + # To assign specific IP addresses to specific + # clients or if a connecting client has a private + # subnet behind it that should also have VPN access, + # use the subdirectory "ccd" for client-specific + # configuration files (see man page for more info). + + # EXAMPLE: Suppose the client + # having the certificate common name "Thelonious" + # also has a small subnet behind his connecting + # machine, such as 192.168.40.128/255.255.255.248. + # First, uncomment out these lines: +# option client_config_dir ccd +# list route "192.168.40.128 255.255.255.248" + # Then create a file ccd/Thelonious with this line: + # iroute 192.168.40.128 255.255.255.248 + # This will allow Thelonious' private subnet to + # access the VPN. This example will only work + # if you are routing, not bridging, i.e. you are + # using "dev tun" and "server" directives. + + # EXAMPLE: Suppose you want to give + # Thelonious a fixed VPN IP address of 10.9.0.1. + # First uncomment out these lines: +# option client_config_dir ccd +# list route "10.9.0.0 255.255.255.252" +# list route "192.168.100.0 255.255.255.0" + # Then add this line to ccd/Thelonious: + # ifconfig-push "10.9.0.1 10.9.0.2" + + # Suppose that you want to enable different + # firewall access policies for different groups + # of clients. There are two methods: + # (1) Run multiple OpenVPN daemons, one for each + # group, and firewall the TUN/TAP interface + # for each group/daemon appropriately. + # (2) (Advanced) Create a script to dynamically + # modify the firewall in response to access + # from different clients. See man + # page for more info on learn-address script. +# option learn_address ./script + + # If enabled, this directive will configure + # all clients to redirect their default + # network gateway through the VPN, causing + # all IP traffic such as web browsing and + # and DNS lookups to go through the VPN + # (The OpenVPN server machine may need to NAT + # the TUN/TAP interface to the internet in + # order for this to work properly). + # CAVEAT: May break client's network config if + # client's local DHCP server packets get routed + # through the tunnel. Solution: make sure + # client's local DHCP server is reachable via + # a more specific route than the default route + # of 0.0.0.0/0.0.0.0. +# list push "redirect-gateway" + + # Certain Windows-specific network settings + # can be pushed to clients, such as DNS + # or WINS server addresses. CAVEAT: + # http://openvpn.net/faq.html#dhcpcaveats +# list push "dhcp-option DNS 10.8.0.1" +# list push "dhcp-option WINS 10.8.0.1" + + # Uncomment this directive to allow different + # clients to be able to "see" each other. + # By default, clients will only see the server. + # To force clients to only see the server, you + # will also need to appropriately firewall the + # server's TUN/TAP interface. +# option client_to_client 1 + + # Uncomment this directive if multiple clients + # might connect with the same certificate/key + # files or common names. This is recommended + # only for testing purposes. For production use, + # each client should have its own certificate/key + # pair. + # + # IF YOU HAVE NOT GENERATED INDIVIDUAL + # CERTIFICATE/KEY PAIRS FOR EACH CLIENT, + # EACH HAVING ITS OWN UNIQUE "COMMON NAME", + # UNCOMMENT THIS LINE OUT. +# option duplicate_cn 1 + + # The keepalive directive causes ping-like + # messages to be sent back and forth over + # the link so that each side knows when + # the other side has gone down. + # Ping every 10 seconds, assume that remote + # peer is down if no ping received during + # a 120 second time period. + option keepalive "10 120" + + # For extra security beyond that provided + # by SSL/TLS, create an "HMAC firewall" + # to help block DoS attacks and UDP port flooding. + # + # Generate with: + # openvpn --genkey --secret ta.key + # + # The server and each client must have + # a copy of this key. + # The second parameter should be '0' + # on the server and '1' on the clients. + # This file is secret: +# option tls_auth "ta.key 0" + + # Select a cryptographic cipher. + # This config item must be copied to + # the client config file as well. + # Blowfish (default): +# option cipher BF-CBC + # AES: +# option cipher AES-128-CBC + # Triple-DES: +# option cipher DES-EDE3-CBC + + # Enable compression on the VPN link. + # If you enable it here, you must also + # enable it in the client config file. + option comp_lzo 1 + + # The maximum number of concurrently connected + # clients we want to allow. +# option max_clients 100 + + # The persist options will try to avoid + # accessing certain resources on restart + # that may no longer be accessible because + # of the privilege downgrade. + option persist_key 1 + option persist_tun 1 + + # Output a short status file showing + # current connections, truncated + # and rewritten every minute. + option status openvpn-status.log + + # By default, log messages will go to the syslog (or + # on Windows, if running as a service, they will go to + # the "\Program Files\OpenVPN\log" directory). + # Use log or log-append to override this default. + # "log" will truncate the log file on OpenVPN startup, + # while "log-append" will append to it. Use one + # or the other (but not both). +# option log openvpn.log +# option log_append openvpn.log + + # Set the appropriate level of log + # file verbosity. + # + # 0 is silent, except for fatal errors + # 4 is reasonable for general usage + # 5 and 6 can help to debug connection problems + # 9 is extremely verbose + option verb 3 + + # Silence repeating messages. At most 20 + # sequential messages of the same message + # category will be output to the log. +# option mute 20 + + +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +############################################## + +config openvpn sample_client + + # Set to 1 to enable this instance: + option enable 0 + + # Specify that we are a client and that we + # will be pulling certain config file directives + # from the server. + option client 1 + + # Use the same setting as you are using on + # the server. + # On most systems, the VPN will not function + # unless you partially or fully disable + # the firewall for the TUN/TAP interface. +# option dev tap + option dev tun + + # Are we connecting to a TCP or + # UDP server? Use the same setting as + # on the server. +# option proto tcp + option proto udp + + # The hostname/IP and port of the server. + # You can have multiple remote entries + # to load balance between the servers. + list remote "my_server_1 1194" +# list remote "my_server_2 1194" + + # Choose a random host from the remote + # list for load_balancing. Otherwise + # try hosts in the order specified. +# option remote_random 1 + + # Keep trying indefinitely to resolve the + # host name of the OpenVPN server. Very useful + # on machines which are not permanently connected + # to the internet such as laptops. + option resolv_retry infinite + + # Most clients don't need to bind to + # a specific local port number. + option nobind 1 + + # Try to preserve some state across restarts. + option persist_key 1 + option persist_tun 1 + + # If you are connecting through an + # HTTP proxy to reach the actual OpenVPN + # server, put the proxy server/IP and + # port number here. See the man page + # if your proxy server requires + # authentication. + # retry on connection failures: +# option http_proxy_retry 1 + # specify http proxy address and port: +# option http_proxy "192.168.1.100 8080" + + # Wireless networks often produce a lot + # of duplicate packets. Set this flag + # to silence duplicate packet warnings. +# option mute_replay_warnings 1 + + # SSL/TLS parms. + # See the server config file for more + # description. It's best to use + # a separate .crt/.key file pair + # for each client. A single ca + # file can be used for all clients. + option ca ca.crt + option cert client.crt + option key client.key + + # Verify server certificate by checking + # that the certicate has the nsCertType + # field set to "server". This is an + # important precaution to protect against + # a potential attack discussed here: + # http://openvpn.net/howto.html#mitm + # + # To use this feature, you will need to generate + # your server certificates with the nsCertType + # field set to "server". The build_key_server + # script in the easy_rsa folder will do this. +# option ns_cert_type server + + # If a tls_auth key is used on the server + # then every client must also have the key. +# option tls_auth "ta.key 1" + + # Select a cryptographic cipher. + # If the cipher option is used on the server + # then you must also specify it here. +# option cipher x + + # Enable compression on the VPN link. + # Don't enable this unless it is also + # enabled in the server config file. + option comp_lzo 1 + + # Set log file verbosity. + option verb 3 + + # Silence repeating messages +# option mute 20 diff --git a/applications/luci-openvpn/root/etc/config/openvpn_recipes b/applications/luci-openvpn/root/etc/config/openvpn_recipes new file mode 100644 index 0000000000..94e879b913 --- /dev/null +++ b/applications/luci-openvpn/root/etc/config/openvpn_recipes @@ -0,0 +1,95 @@ +# +# Routed point-to-point server +# +config openvpn_recipe server_tun_ptp + option _description "Simple server configuration for a routed point-to-point VPN" + option _role "server" + option dev "tun" + option port "1194" + option ifconfig "10.0.0.1 10.0.0.2" + option secret "shared-secret.key" + +# +# Routed point-to-point client +# +config openvpn_recipe client_tun_ptp + option _description "Simple client configuration for a routed point-to-point VPN" + option _role "client" + option dev "tun" + list remote "mypeer.dyndns.org" + option port "1194" + option ifconfig "10.0.0.2 10.0.0.1" + option secret "shared-secret.key" + option nobind "1" + + +# +# Routed multi-client server +# +config openvpn_recipe server_tun + option _description "Server configuration for a routed multi-client VPN" + option _role "server" + option dev "tun" + option port "1194" + option server "10.0.100.0 255.255.255.0" + option ca "ca.crt" + option cert "server.crt" + option key "server.key" + option dh "dh1024.pem" + option client_to_client "1" + option keepalive "10 120" + option comp_lzo "1" + +# +# Routed client +# +config openvpn_recipe client_tun + option _description "Client configuration for a routed multi-client VPN" + option _role "client" + option client "1" + option dev "tun" + list remote "vpnserver.example.org 1194" + option ca "ca.crt" + option cert "my_client.crt" + option key "my_client.key" + option dh "dh1024.pem" + option ns_cert_type "server" + option keepalive "10 120" + option comp_lzo "1" + option nobind "1" + + +# +# Multi-client ethernet bridge server +# +config openvpn_recipe server_tap_bridge + option _description "Server configuration for an ethernet bridge VPN" + option _role "server" + option dev "tap" + option port "1194" + option server_bridge "192.168.1.1 255.255.255.0 192.168.1.128 192.168.1.254" + option ca "ca.crt" + option cert "server.crt" + option key "server.key" + option dh "dh1024.pem" + option client_to_client "1" + option keepalive "10 120" + option comp_lzo "1" + +# +# Ethernet bridge client +# +config openvpn_recipe client_tap_bridge + option _description "Client configuration for an ethernet bridge VPN" + option _role "client" + option client "1" + option dev "tap" + list remote "vpnserver.example.org 1194" + option ca "ca.crt" + option cert "my_client.crt" + option key "my_client.key" + option dh "dh1024.pem" + option ns_cert_type "server" + option keepalive "10 120" + option comp_lzo "1" + option nobind "1" diff --git a/applications/luci-openvpn/root/etc/init.d/openvpn b/applications/luci-openvpn/root/etc/init.d/openvpn new file mode 100644 index 0000000000..baa683ff49 --- /dev/null +++ b/applications/luci-openvpn/root/etc/init.d/openvpn @@ -0,0 +1,144 @@ +#!/bin/sh /etc/rc.common +# OpenVPN init script +# Copyright (C) 2008 Jo-Philipp Wich +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# $Id$ + +START=95 +BIN=/usr/sbin/openvpn +SSD=start-stop-daemon + +LIST_SEP=" +" + +append_param() { + local v="$1" + case "$v" in + *_*_*_*) v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;; + *_*_*) v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;; + *_*) v=${v%%_*}-${v#*_} ;; + esac + ARGS="$ARGS --$v" + return 0 +} + +append_bools() { + local p; local v; local s="$1"; shift + for p in $*; do + config_get_bool v "$s" "$p" + [ "$v" == 1 ] && append_param "$p" + done +} + +append_params() { + local p; local v; local s="$1"; shift + for p in $*; do + config_get v "$s" "$p" + IFS="$LIST_SEP" + for v in $v; do + [ -n "$v" ] && append_param "$p" && ARGS="$ARGS $v" + done + unset IFS + done +} + +append_params_quoted() { + local p; local v; local s="$1"; shift + for p in $*; do + config_get v "$s" "$p" + IFS="$LIST_SEP" + for v in $v; do + [ -n "$v" ] && append_param "$p" && ARGS="$ARGS '$v'" + done + unset IFS + done +} + +start_service() { + local s="$1" + local enable=0 + + # disabled? + config_get_bool enable "$s" enable 0 + [ "$enable" == 0 ] && return 0 + + PID="/var/run/openvpn-$s.pid" + ARGS="" + + # append flags + append_bools "$s" \ + auth_nocache ccd_exclusive client client_cert_not_required \ + client_disconnect client_to_client comp_lzo comp_noadapt disable \ + disable_occ down_pre duplicate_cn fast_io float http_proxy_retry \ + ifconfig_noexec ifconfig_nowarn ifconfig_pool_linear management_hold \ + management_query_passwords mktun mlock mtu_test mute_replay_warnings \ + nobind no_iv no_replay passtos persist_key persist_local_ip \ + persist_remote_ip persist_tun ping_timer_rem pull push_reset \ + remote_random rmtun route_noexec single_session socks_proxy_retry \ + suppress_timestamps test_crypto tls_client tls_exit tls_server \ + tun_ipv6 up_delay up_restart username_as_common_name + + # append params + append_params "$s" \ + auth auth_user_pass auth_user_pass_verify bcast_buffers ca cd cert \ + chroot cipher client_config_dir client_connect config connect_freq \ + connect_retry crl_verify cryptoapicert dev dev_node dev_type dh down \ + echo engine explicit_exit_notify fragment group hand_window hash_size \ + http_proxy http_proxy_option http_proxy_timeout ifconfig ifconfig_pool \ + ifconfig_pool_persist ifconfig_push inactive ipchange iroute keepalive \ + key key_method keysize learn_address link_mtu local log log_append \ + lport management management_log_cache max_clients \ + max_routes_per_client mode mssfix mtu_disc mute nice ns_cert_type ping \ + ping_exit ping_restart pkcs12 plugin port proto rcvbuf \ + redirect_gateway remap_usr1 remote reneg_bytes reneg_pkts reneg_sec \ + replay_persist replay_window resolv_retry route route_delay \ + route_gateway route_up rport server server_bridge setenv shaper sndbuf \ + socks_proxy status status_version syslog tcp_queue_limit tls_auth \ + tls_cipher tls_remote tls_timeout tls_verify tmp_dir tran_window \ + tun_mtu tun_mtu_extra txqueuelen up user verb + + # append multi-value params + append_params_quoted "$s" \ + push + + + [ -n "$ARGS" ] && \ + eval "$SSD -q -b -m -p $PID -x $BIN -S -- --syslog 'openvpn($s)' $ARGS" +} + +kill_service() { + local s="$1" + local S="${2:-TERM}" + local enable=0 + + # disabled? + config_get_bool enable "$s" enable 0 + [ "$enable" == 0 ] && return 0 + + PID="/var/run/openvpn-$s.pid" + + $SSD -q -p $PID -x $BIN -K -s $S +} + +hup_service() { kill_service "$1" HUP; } +stop_service() { kill_service "$1" TERM; } + +start() { + config_load openvpn + config_foreach start_service openvpn +} + +stop() { + config_load openvpn + config_foreach stop_service openvpn +} + +reload() { + config_load openvpn + config_foreach hup_service openvpn +} + +restart() { + stop; sleep 5; start +} diff --git a/applications/luci-openvpn/root/lib/uci/schema/default/openvpn b/applications/luci-openvpn/root/lib/uci/schema/default/openvpn new file mode 100644 index 0000000000..2a31ff4992 --- /dev/null +++ b/applications/luci-openvpn/root/lib/uci/schema/default/openvpn @@ -0,0 +1,299 @@ +mode m +Set OpenVPN major mode + +local host +Local host name or IP address for bind + +remote host [port] +Remote host name or IP address + +remote-random +When multiple --remote address/ports are specified, initially randomize the order of the list as a kind of basic load-balancing measure + +proto p +Use protocol p for communicating with remote host + +connect-retry n +For --proto tcp-client, take n as the number of seconds to wait between connection retries (default=5) + +connect-retry-max n +For --proto tcp-client, take n as the number of retries of connection attempt (default=infinite) + +auto-proxy +Try to sense HTTP or SOCKS proxy settings automatically + +http-proxy server port [authfile|'auto'] [auth-method] +Connect to remote host through an HTTP proxy at address server and port port + +http-proxy-retry +Retry indefinitely on HTTP proxy errors + +http-proxy-timeout n +Set proxy timeout to n seconds, default=5 + +http-proxy-option type [parm] +Set extended HTTP proxy options + +socks-proxy server [port] +Connect to remote host through a Socks5 proxy at address server and port port (default=1080) + +socks-proxy-retry +Retry indefinitely on Socks proxy errors + +resolv-retry n +If hostname resolve fails for --remote, retry resolve for n seconds before failing + +float +Allow remote peer to change its IP address and/or port number, such as due to DHCP (this is the default if --remote is not used) + +ipchange cmd +Execute shell command cmd when our remote ip-address is initially authenticated or changes + +port port +TCP/UDP port number for both local and remote + +lport port +TCP/UDP port number for bind + +rport port +TCP/UDP port number for remote + +bind +Bind to local address and port + +nobind +Do not bind to local address and port + +dev tunX | tapX | null +TUN/TAP virtual network device ( X can be omitted for a dynamic device + +dev-type device-type +Which device type are we using? device-type should be tun or tap + +topology mode +Configure virtual addressing topology when running in --dev tun mode + +tun-ipv6 +Build a tun link capable of forwarding IPv6 traffic + +dev-node node +Explicitly set the device node rather than using /dev/net/tun, /dev/tun, /dev/tap, etc + +lladdr address +Specify the link layer address, more commonly known as the MAC address + +iproute cmd +Set alternate command to execute instead of default iproute2 command + +ifconfig l rn +Set TUN/TAP adapter parameters + +ifconfig-noexec +Don't actually execute ifconfig/netsh commands, instead pass --ifconfig parameters to scripts using environmental variables + +ifconfig-nowarn +Don't output an options consistency check warning if the --ifconfig option on this side of the connection doesn't match the remote side + +route network/IP [netmask] [gateway] [metric] +Add route to routing table after connection is established + +route-gateway gw +Specify a default gateway gw for use with --route + +route-metric m +Specify a default metric m for use with --route + +route-delay [n] [w] +Delay n seconds (default=0) after connection establishment, before adding routes + +route-up cmd +Execute shell command cmd after routes are added, subject to --route-delay + +route-noexec +Don't add or remove routes automatically + +route-nopull +When used with --client or --pull, accept options pushed by server EXCEPT for routes + +redirect-gateway flags... +(Experimental) Automatically execute routing commands to cause all outgoing IP traffic to be redirected over the VPN + +link-mtu n +Sets an upper bound on the size of UDP packets which are sent between OpenVPN peers + +tun-mtu n +Take the TUN device MTU to be n and derive the link MTU from it (default=1500) + +tun-mtu-extra n +Assume that the TUN/TAP device might return as many as n bytes more than the --tun-mtu size on read + +mtu-disc type +Should we do Path MTU discovery on TCP/UDP channel? Only supported on OSes such as Linux that supports the necessary system call to set + +mtu-test +To empirically measure MTU on connection startup, add the --mtu-test option to your configuration + +fragment max +Enable internal datagram fragmentation so that no UDP datagrams are sent which are larger than max bytes + +mssfix max +Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed max bytes + +sndbuf size +Set the TCP/UDP socket send buffer size + +rcvbuf size +Set the TCP/UDP socket receive buffer size + +socket-flags flags... +Apply the given flags to the OpenVPN transport socket + +txqueuelen n +(Linux only) Set the TX queue length on the TUN/TAP interface + +shaper n +Limit bandwidth of outgoing tunnel data to n bytes per second on the TCP/UDP port + +inactive n [bytes] +Causes OpenVPN to exit after n seconds of inactivity on the TUN/TAP device + +ping n +Ping remote over the TCP/UDP control channel if no packets have been sent for at least n seconds (specify --ping on both peers to cause ping packets to be sent in both directions since OpenVPN ping packets are not echoed like IP ping packets) + +ping-exit n +Causes OpenVPN to exit after n seconds pass without reception of a ping or other packet from remote + +ping-restart n +Similar to --ping-exit, but trigger a SIGUSR1 restart after n seconds pass without reception of a ping or other packet from remote + +keepalive n m +A helper directive designed to simplify the expression of --ping and --ping-restart in server mode configurations + +ping-timer-rem +Run the --ping-exit / --ping-restart timer only if we have a remote address + +persist-tun +Don't close and reopen TUN/TAP device or run up/down scripts across SIGUSR1 or --ping-restart restarts + +persist-key +Don't re-read key files across SIGUSR1 or --ping-restart + +persist-local-ip +Preserve initially resolved local IP address and port number across SIGUSR1 or --ping-restart restarts + +persist-remote-ip +Preserve most recently authenticated remote IP address and port number across SIGUSR1 or --ping-restart restarts + +mlock +Disable paging by calling the POSIX mlockall function + +up cmd +Shell command to run after successful TUN/TAP device open (pre --user UID change) + +up-delay +Delay TUN/TAP open and possible --up script execution until after TCP/UDP connection establishment with peer + +down cmd +Shell command to run after TUN/TAP device close (post --user UID change and/or --chroot ) + +down-pre +Call --down cmd/script before, rather than after, TUN/TAP close + +up-restart +Enable the --up and --down scripts to be called for restarts as well as initial program start + +setenv name value +Set a custom environmental variable name=value to pass to script + +setenv-safe name value +Set a custom environmental variable OPENVPN_name=value to pass to script + +disable-occ +Don't output a warning message if option inconsistencies are detected between peers + +user user +Change the user ID of the OpenVPN process to user after initialization, dropping privileges in the process + +group group +Similar to the --user option, this option changes the group ID of the OpenVPN process to group after initialization + +cd dir +Change directory to dir prior to reading any files such as configuration files, key files, scripts, etc + +chroot dir +Chroot to dir after initialization + +#daemon [progname] +#Become a daemon after all initialization functions are completed + +#syslog [progname] +#Direct log output to system logger, but do not become a daemon + +passtos +Set the TOS field of the tunnel packet to what the payload's TOS is + +inetd [wait|nowait] [progname] +Use this option when OpenVPN is being run from the inetd or xinetd(8) server + +log file +Output logging messages to file, including output to stdout/stderr which is generated by called scripts + +log-append file +Append logging messages to file + +suppress-timestamps +Avoid writing timestamps to log messages, even when they otherwise would be prepended + +writepid file +Write OpenVPN's main process ID to file + +nice n +Change process priority after initialization ( n greater than 0 is lower priority, n less than zero is higher priority) + +fast-io +(Experimental) Optimize TUN/TAP/UDP I/O writes by avoiding a call to poll/epoll/select prior to the write operation + +echo [parms...] +Echo parms to log output + +remap-usr1 signal +Control whether internally or externally generated SIGUSR1 signals are remapped to SIGHUP (restart without persisting state) or SIGTERM (exit) + +verb n +Set output verbosity to n (default=1) + +status file [n] +Write operational status to file every n seconds + +status-version [n] +Choose the status file format version number + +mute n +Log at most n consecutive messages in the same category + +comp-lzo [mode] +Use fast LZO compression -- may add up to 1 byte per packet for incompressible data + +comp-noadapt +When used in conjunction with --comp-lzo, this option will disable OpenVPN's adaptive compression algorithm + +management IP port [pw-file] +Enable a TCP server on IP:port to handle daemon management functions + +management-query-passwords +Query management channel for private key password and --auth-user-pass username/password + +management-forget-disconnect +Make OpenVPN forget passwords when management session disconnects + +management-hold +Start OpenVPN in a hibernating state, until a client of the management interface explicitly starts it with the hold release command + +management-signal +Send SIGUSR1 signal to OpenVPN if management session disconnects + +management-log-cache n +Cache the most recent n lines of log file history for usage by the management channel + +plugin module-pathname [init-string] +Load plug-in module from the file module-pathname, passing init-string as an argument to the module initialization function diff --git a/applications/community-leipzig/Makefile b/applications/luci-siitwizard/Makefile similarity index 100% rename from applications/community-leipzig/Makefile rename to applications/luci-siitwizard/Makefile diff --git a/applications/luci-siitwizard/luasrc/controller/siitwizard.lua b/applications/luci-siitwizard/luasrc/controller/siitwizard.lua new file mode 100644 index 0000000000..64c9b98b5c --- /dev/null +++ b/applications/luci-siitwizard/luasrc/controller/siitwizard.lua @@ -0,0 +1,21 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +$Id: siitwizard.lua 3934 2008-12-23 05:18:08Z jow $ + +]]-- + +module "luci.controller.siitwizard" + +function index() + entry({"admin", "network", "siitwizard"}, form("siitwizard"), "SIIT 4over6 assistent", 99) +end diff --git a/applications/luci-siitwizard/luasrc/model/cbi/siitwizard.lua b/applications/luci-siitwizard/luasrc/model/cbi/siitwizard.lua new file mode 100644 index 0000000000..048c0f4a5a --- /dev/null +++ b/applications/luci-siitwizard/luasrc/model/cbi/siitwizard.lua @@ -0,0 +1,338 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +$Id: siitwizard.lua 3940 2008-12-23 16:49:48Z jow $ + +]]-- + +local uci = require "luci.model.uci".cursor() + +-------------------- View -------------------- +f = SimpleForm("siitwizward", "4over6-Assistent", + "Dieser Assistent unterstüzt bei der Einrichtung von IPv4-over-IPv6 Translation.") + +mode = f:field(ListValue, "mode", "Betriebsmodus") +mode:value("client", "Client") +mode:value("gateway", "Gateway") + +dev = f:field(ListValue, "device", "WLAN-Gerät") +uci:foreach("wireless", "wifi-device", + function(section) + dev:value(section[".name"]) + end) + +lanip = f:field(Value, "ipaddr", "LAN IP Adresse") +lanip.value = "172.23.1.1" + +lanmsk = f:field(Value, "lanmask", "Lokale LAN Netzmaske") +lanmsk.value = "255.255.255.0" + +gv4msk = f:field(Value, "gv4mask", "Globale LAN Netzmaske") +gv4msk.value = "255.255.0.0" + + +-------------------- Control -------------------- +LL_PREFIX = luci.ip.IPv6("fe80::/64") + +-- +-- find link-local address +-- +function find_ll() + for _, r in ipairs(luci.sys.net.routes6()) do + if LL_PREFIX:contains(r.dest) and r.dest:higher(LL_PREFIX) then + return r.dest:sub(LL_PREFIX) + end + end + return luci.ip.IPv6("::") +end + + + +function f.handle(self, state, data) + if state == FORM_VALID then + luci.http.redirect(luci.dispatcher.build_url("admin", "uci", "changes")) + return false + elseif state == FORM_INVALID then + self.errmessage = "Ungültige Eingabe: Bitte die Formularfelder auf Fehler prüfen." + end + return true +end + +function mode.write(self, section, value) + + -- lan interface + local lan_net = luci.ip.IPv4( + lanip:formvalue(section) or "192.168.1.1", + lanmsk:formvalue(section) or "255.255.255.0" + ) + + local gv4_net = luci.ip.IPv4( + lanip:formvalue(section) or "192.168.1.1", + gv4msk:formvalue(section) or "255.255.0.0" + ) + + -- + -- Configure wifi device + -- + local wifi_device = dev:formvalue(section) + local wifi_essid = uci:get("siit", "wifi", "essid") or "6mesh.freifunk.net" + local wifi_bssid = uci:get("siit", "wifi", "bssid") or "02:ca:ff:ee:ba:be" + local wifi_channel = uci:get("siit", "wifi", "channel") or "1" + + -- nuke old device definition + uci:delete_all("wireless", "wifi-iface", + function(s) return s.device == wifi_device end ) + + uci:delete_all("network", "interface", + function(s) return s['.name'] == wifi_device end ) + + -- create wifi device definition + uci:tset("wireless", wifi_device, { + disabled = 0, + channel = wifi_channel, +-- txantenna = 1, +-- rxantenna = 1, +-- diversity = 0 + }) + + uci:section("wireless", "wifi-iface", nil, { + encryption = "none", + mode = "adhoc", + network = wifi_device, + device = wifi_device, + ssid = wifi_essid, + bssid = wifi_bssid, + }) + + + -- + -- Determine defaults + -- + local ula_prefix = uci:get("siit", "ipv6", "ula_prefix") or "fd00::" + local ula_global = uci:get("siit", "ipv6", "ula_global") or "00ca:ffee:babe::" -- = Freifunk + local ula_subnet = uci:get("siit", "ipv6", "ula_subnet") or "0000:0000:0000:4223::" -- = Berlin + local siit_prefix = uci:get("siit", "ipv6", "siit_prefix") or "::ffff:0000:0000" + + -- Find wifi interface + local device = dev:formvalue(section) + + -- + -- Generate ULA + -- + local ula = luci.ip.IPv6("::/64") + + for _, prefix in ipairs({ ula_prefix, ula_global, ula_subnet }) do + ula = ula:add(luci.ip.IPv6(prefix)) + end + + ula = ula:add(find_ll()) + + + -- + -- Gateway mode + -- + -- * wan port is dhcp, lan port is 172.23.1.1/24 + -- * siit0 gets a dummy address: 169.254.42.42 + -- * wl0 gets an ipv6 address, in this case the fdca:ffee:babe::1:1/64 + -- * we do a ::ffff:ffff:0/96 route into siit0, so everything from 6mesh goes into translation. + -- * an HNA6 of ::ffff:ffff:0:0/96 announces the mapped 0.0.0.0/0 ipv4 space. + -- * MTU on WAN, LAN down to 1400, ipv6 headers are slighly larger. + + if value == "gateway" then + + + -- wan mtu + uci:set("network", "wan", "mtu", 1400) + + -- lan settings + uci:tset("network", "lan", { + mtu = 1400, + ipaddr = lan_net:host():string(), + netmask = lan_net:mask():string() + }) + + -- use full siit subnet + siit_route = luci.ip.IPv6(siit_prefix .. "/96") + + -- v4 <-> siit route + uci:delete_all("network", "route", + function(s) return s.interface == "siit0" end) + + uci:section("network", "route", nil, { + interface = "siit0", + target = gv4_net:network():string(), + netmask = gv4_net:mask():string() + }) + + -- + -- Client mode + -- + -- * 172.23.2.1/24 on its lan, fdca:ffee:babe::1:2 on wl0 and the usual dummy address on siit0. + -- * we do a ::ffff:ffff:172.13.2.0/120 to siit0, because in this case, only traffic directed to clients needs to go into translation. + -- * same route as HNA6 announcement to catch the traffic out of the mesh. + -- * Also, MTU on LAN reduced to 1400. + + else + + -- lan settings + uci:tset("network", "lan", { + mtu = 1400, + ipaddr = lan_net:host():string(), + netmask = lan_net:mask():string() + }) + + -- derive siit subnet from lan config + siit_route = luci.ip.IPv6( + siit_prefix .. "/" .. (96 + lan_net:prefix()) + ):add(lan_net[2]) + + -- ipv4 <-> siit route + uci:delete_all("network", "route", + function(s) return s.interface == "siit0" end) + + -- XXX: kind of a catch all, gv4_net would be better + -- but does not cover non-local v4 space + uci:section("network", "route", nil, { + interface = "siit0", + target = "0.0.0.0", + netmask = "0.0.0.0" + }) + end + + -- setup the firewall + uci:delete_all("firewall", "zone", + function(s) return ( + s['.name'] == "siit0" or s.name == "siit0" or + s.network == "siit0" or s['.name'] == wifi_device or + s.name == wifi_device or s.network == wifi_device + ) end) + + uci:delete_all("firewall", "forwarding", + function(s) return ( + s.src == wifi_device and s.dest == "siit0" or + s.dest == wifi_device and s.src == "siit0" or + s.src == "lan" and s.dest == "siit0" or + s.dest == "lan" and s.src == "siit0" + ) end) + + uci:section("firewall", "zone", "siit0", { + name = "siit0", + network = "siit0", + input = "ACCEPT", + output = "ACCEPT", + forward = "ACCEPT" + }) + + uci:section("firewall", "zone", wifi_device, { + name = wifi_device, + network = wifi_device, + input = "ACCEPT", + output = "ACCEPT", + forward = "ACCEPT" + }) + + uci:section("firewall", "forwarding", nil, { + src = wifi_device, + dest = "siit0" + }) + + uci:section("firewall", "forwarding", nil, { + src = "siit0", + dest = wifi_device + }) + + uci:section("firewall", "forwarding", nil, { + src = "lan", + dest = "siit0" + }) + + uci:section("firewall", "forwarding", nil, { + src = "siit0", + dest = "lan" + }) + + -- firewall include + uci:delete_all("firewall", "include", + function(s) return s.path == "/etc/firewall.user" end) + + uci:section("firewall", "include", nil, { + path = "/etc/firewall.user" + }) + + + -- siit0 interface + uci:delete_all("network", "interface", + function(s) return ( s.ifname == "siit0" ) end) + + uci:section("network", "interface", "siit0", { + ifname = "siit0", + proto = "none" + }) + + -- siit0 route + uci:delete_all("network", "route6", + function(s) return siit_route:contains(luci.ip.IPv6(s.target)) end) + + uci:section("network", "route6", nil, { + interface = "siit0", + target = siit_route:string() + }) + + -- create wifi network interface + uci:section("network", "interface", wifi_device, { + proto = "static", + mtu = 1400, + ip6addr = ula:string() + }) + + -- nuke old olsrd interfaces + uci:delete_all("olsrd", "Interface", + function(s) return s.interface == wifi_device end) + + -- configure olsrd interface + uci:foreach("olsrd", "olsrd", + function(s) uci:set("olsrd", s['.name'], "IpVersion", 6) end) + + uci:section("olsrd", "Interface", nil, { + ignore = 0, + interface = wifi_device, + Ip6AddrType = "global" + }) + + -- hna6 + uci:delete_all("olsrd", "Hna6", + function(s) + if s.netaddr and s.prefix then + return siit_route:contains(luci.ip.IPv6(s.netaddr.."/"..s.prefix)) + end + end) + + uci:section("olsrd", "Hna6", nil, { + netaddr = siit_route:host():string(), + prefix = siit_route:prefix() + }) + + -- txtinfo v6 + uci:foreach("olsrd", "LoadPlugin", + function(s) + if s.library == "olsrd_txtinfo.so.0.1" then + uci:set("olsrd", s['.name'], "accept", "::1") + end + end) + + uci:save("wireless") + uci:save("firewall") + uci:save("network") + uci:save("olsrd") +end + +return f diff --git a/applications/luci-siitwizard/root/etc/config/siit b/applications/luci-siitwizard/root/etc/config/siit new file mode 100644 index 0000000000..0fce1eabb9 --- /dev/null +++ b/applications/luci-siitwizard/root/etc/config/siit @@ -0,0 +1,10 @@ +config siit ipv6 + option ula_prefix "fd00::" + option ula_global "00ca:ffee:babe::" + option ula_subnet "0000:0000:0000:dada::" + option siit_prefix "::ffff:0000:0000" + +config siit wifi + option essid "6mesh.freifunk.net" + option bssid "02:ca:ff:ee:ba:be" + option channel "1" diff --git a/contrib/axtls/Makefile b/contrib/axtls/Makefile new file mode 100644 index 0000000000..9ab39b6fea --- /dev/null +++ b/contrib/axtls/Makefile @@ -0,0 +1,62 @@ +# +# Copyright (C) 2008 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id$ + +include $(TOPDIR)/rules.mk + +PKG_NAME:=axtls +PKG_VERSION:=1.2.0 +PKG_RELEASE:=2 + +PKG_BUILD_DIR=$(BUILD_DIR)/axTLS +PKG_SOURCE:=axTLS-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=@SF/axtls +PKG_MD5SUM:=af805c76c0da1dbfc0c5e6b8dbd6706a + +include $(INCLUDE_DIR)/package.mk + +# set to 1 to enable debugging +DEBUG= + +define Package/libaxtls + SECTION:=libs + CATEGORY:=Libraries + TITLE:=axTLS embedded SSL library +endef + +define Package/axhttpd + SUBMENU:=Web + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libaxtls + TITLE:=axTLS embedded http/https server +endef + +define Build/Configure + $(INSTALL_DIR) $(PKG_BUILD_DIR)/config + $(CP) ./files/axtls-config $(PKG_BUILD_DIR)/config/.config + $(CP) ./files/axtls-config.h $(PKG_BUILD_DIR)/config/config.h +endef + +TARGET_CFLAGS += $(FPIC) + +#define Build/Compile +# $(MAKE) -C $(PKG_BUILD_DIR) +#endef + +define Package/libaxtls/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_BUILD_DIR)/_stage/libaxtls.so* $(1)/usr/lib/ +endef + +define Package/axhttpd/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/_stage/axhttpd $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,libaxtls)) +$(eval $(call BuildPackage,axhttpd)) diff --git a/contrib/axtls/files/axtls-config b/contrib/axtls/files/axtls-config new file mode 100644 index 0000000000..f32264e5a9 --- /dev/null +++ b/contrib/axtls/files/axtls-config @@ -0,0 +1,116 @@ +# +# Automatically generated make config: don't edit +# +HAVE_DOT_CONFIG=y +CONFIG_PLATFORM_LINUX=y +# CONFIG_PLATFORM_CYGWIN is not set +# CONFIG_PLATFORM_WIN32 is not set + +# +# General Configuration +# +PREFIX="/usr/local" +# CONFIG_DEBUG is not set +# CONFIG_STRIP_UNWANTED_SECTIONS is not set +# CONFIG_VISUAL_STUDIO_7_0 is not set +# CONFIG_VISUAL_STUDIO_8_0 is not set +CONFIG_VISUAL_STUDIO_7_0_BASE="" +CONFIG_VISUAL_STUDIO_8_0_BASE="" +CONFIG_EXTRA_CFLAGS_OPTIONS="-fPIC" +CONFIG_EXTRA_LDFLAGS_OPTIONS="-lc -lm" + +# +# SSL Library +# +# CONFIG_SSL_SERVER_ONLY is not set +# CONFIG_SSL_CERT_VERIFICATION is not set +# CONFIG_SSL_ENABLE_CLIENT is not set +# CONFIG_SSL_FULL_MODE is not set +CONFIG_SSL_SKELETON_MODE=y +# CONFIG_SSL_PROT_LOW is not set +# CONFIG_SSL_PROT_MEDIUM is not set +# CONFIG_SSL_PROT_HIGH is not set +# CONFIG_SSL_USE_DEFAULT_KEY is not set +CONFIG_SSL_PRIVATE_KEY_LOCATION="" +CONFIG_SSL_PRIVATE_KEY_PASSWORD="" +CONFIG_SSL_X509_CERT_LOCATION="" +# CONFIG_SSL_GENERATE_X509_CERT is not set +CONFIG_SSL_X509_COMMON_NAME="" +CONFIG_SSL_X509_ORGANIZATION_NAME="" +CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME="" +CONFIG_SSL_ENABLE_V23_HANDSHAKE=y +# CONFIG_SSL_HAS_PEM is not set +# CONFIG_SSL_USE_PKCS12 is not set +CONFIG_SSL_EXPIRY_TIME=0 +CONFIG_X509_MAX_CA_CERTS=0 +CONFIG_SSL_MAX_CERTS=2 +# CONFIG_SSL_CTX_MUTEXING is not set +CONFIG_USE_DEV_URANDOM=y +# CONFIG_WIN32_USE_CRYPTO_LIB is not set +# CONFIG_OPENSSL_COMPATIBLE is not set +# CONFIG_PERFORMANCE_TESTING is not set +# CONFIG_SSL_TEST is not set +CONFIG_AXHTTPD=y + +# +# Axhttpd Configuration +# +# CONFIG_HTTP_STATIC_BUILD is not set +CONFIG_HTTP_PORT=80 +CONFIG_HTTP_HTTPS_PORT=443 +CONFIG_HTTP_SESSION_CACHE_SIZE=5 +CONFIG_HTTP_WEBROOT="/www" +CONFIG_HTTP_TIMEOUT=300 + +# +# CGI +# +CONFIG_HTTP_HAS_CGI=y +CONFIG_HTTP_CGI_EXTENSIONS="luci" +# CONFIG_HTTP_ENABLE_LUA is not set +CONFIG_HTTP_LUA_PREFIX="" +CONFIG_HTTP_LUA_CGI_LAUNCHER="" +# CONFIG_HTTP_BUILD_LUA is not set +CONFIG_HTTP_DIRECTORIES=y +# CONFIG_HTTP_HAS_AUTHORIZATION is not set +# CONFIG_HTTP_HAS_IPV6 is not set +# CONFIG_HTTP_ENABLE_DIFFERENT_USER is not set +CONFIG_HTTP_USER="" +# CONFIG_HTTP_VERBOSE is not set +CONFIG_HTTP_IS_DAEMON=y + +# +# Language Bindings +# +# CONFIG_BINDINGS is not set +# CONFIG_CSHARP_BINDINGS is not set +# CONFIG_VBNET_BINDINGS is not set +CONFIG_DOT_NET_FRAMEWORK_BASE="" +# CONFIG_JAVA_BINDINGS is not set +CONFIG_JAVA_HOME="" +# CONFIG_PERL_BINDINGS is not set +CONFIG_PERL_CORE="" +CONFIG_PERL_LIB="" +# CONFIG_LUA_BINDINGS is not set +CONFIG_LUA_CORE="" + +# +# Samples +# +# CONFIG_SAMPLES is not set +# CONFIG_C_SAMPLES is not set +# CONFIG_CSHARP_SAMPLES is not set +# CONFIG_VBNET_SAMPLES is not set +# CONFIG_JAVA_SAMPLES is not set +# CONFIG_PERL_SAMPLES is not set +# CONFIG_LUA_SAMPLES is not set +# CONFIG_BIGINT_CLASSICAL is not set +# CONFIG_BIGINT_MONTGOMERY is not set +# CONFIG_BIGINT_BARRETT is not set +# CONFIG_BIGINT_CRT is not set +# CONFIG_BIGINT_KARATSUBA is not set +MUL_KARATSUBA_THRESH=0 +SQU_KARATSUBA_THRESH=0 +# CONFIG_BIGINT_SLIDING_WINDOW is not set +# CONFIG_BIGINT_SQUARE is not set +# CONFIG_BIGINT_CHECK_ON is not set diff --git a/contrib/axtls/files/axtls-config.h b/contrib/axtls/files/axtls-config.h new file mode 100644 index 0000000000..45cf8b6759 --- /dev/null +++ b/contrib/axtls/files/axtls-config.h @@ -0,0 +1,117 @@ +/* + * Automatically generated header file: don't edit + */ + +#define HAVE_DOT_CONFIG 1 +#define CONFIG_PLATFORM_LINUX 1 +#undef CONFIG_PLATFORM_CYGWIN +#undef CONFIG_PLATFORM_WIN32 + +/* + * General Configuration + */ +#define PREFIX "/usr/local" +#undef CONFIG_DEBUG +#undef CONFIG_STRIP_UNWANTED_SECTIONS +#undef CONFIG_VISUAL_STUDIO_7_0 +#undef CONFIG_VISUAL_STUDIO_8_0 +#define CONFIG_VISUAL_STUDIO_7_0_BASE "" +#define CONFIG_VISUAL_STUDIO_8_0_BASE "" +#define CONFIG_EXTRA_CFLAGS_OPTIONS "-fPIC" +#define CONFIG_EXTRA_LDFLAGS_OPTIONS "-lc -lm" + +/* + * SSL Library + */ +#undef CONFIG_SSL_SERVER_ONLY +#undef CONFIG_SSL_CERT_VERIFICATION +#undef CONFIG_SSL_ENABLE_CLIENT +#undef CONFIG_SSL_FULL_MODE +#define CONFIG_SSL_SKELETON_MODE 1 +#undef CONFIG_SSL_PROT_LOW +#undef CONFIG_SSL_PROT_MEDIUM +#undef CONFIG_SSL_PROT_HIGH +#undef CONFIG_SSL_USE_DEFAULT_KEY +#define CONFIG_SSL_PRIVATE_KEY_LOCATION "" +#define CONFIG_SSL_PRIVATE_KEY_PASSWORD "" +#define CONFIG_SSL_X509_CERT_LOCATION "" +#undef CONFIG_SSL_GENERATE_X509_CERT +#define CONFIG_SSL_X509_COMMON_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_NAME "" +#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME "" +#define CONFIG_SSL_ENABLE_V23_HANDSHAKE 1 +#undef CONFIG_SSL_HAS_PEM +#undef CONFIG_SSL_USE_PKCS12 +#define CONFIG_SSL_EXPIRY_TIME +#define CONFIG_X509_MAX_CA_CERTS +#define CONFIG_SSL_MAX_CERTS 2 +#undef CONFIG_SSL_CTX_MUTEXING +#define CONFIG_USE_DEV_URANDOM 1 +#undef CONFIG_WIN32_USE_CRYPTO_LIB +#undef CONFIG_OPENSSL_COMPATIBLE +#undef CONFIG_PERFORMANCE_TESTING +#undef CONFIG_SSL_TEST +#define CONFIG_AXHTTPD 1 + +/* + * Axhttpd Configuration + */ +#undef CONFIG_HTTP_STATIC_BUILD +#define CONFIG_HTTP_PORT 80 +#define CONFIG_HTTP_HTTPS_PORT 443 +#define CONFIG_HTTP_SESSION_CACHE_SIZE 5 +#define CONFIG_HTTP_WEBROOT "/www" +#define CONFIG_HTTP_TIMEOUT 300 + +/* + * CGI + */ +#define CONFIG_HTTP_HAS_CGI 1 +#define CONFIG_HTTP_CGI_EXTENSIONS "luci" +#undef CONFIG_HTTP_ENABLE_LUA +#define CONFIG_HTTP_LUA_PREFIX "" +#define CONFIG_HTTP_LUA_CGI_LAUNCHER "" +#undef CONFIG_HTTP_BUILD_LUA +#define CONFIG_HTTP_DIRECTORIES 1 +#undef CONFIG_HTTP_HAS_AUTHORIZATION +#undef CONFIG_HTTP_HAS_IPV6 +#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER +#define CONFIG_HTTP_USER "" +#undef CONFIG_HTTP_VERBOSE +#define CONFIG_HTTP_IS_DAEMON 1 + +/* + * Language Bindings + */ +#undef CONFIG_BINDINGS +#undef CONFIG_CSHARP_BINDINGS +#undef CONFIG_VBNET_BINDINGS +#define CONFIG_DOT_NET_FRAMEWORK_BASE "" +#undef CONFIG_JAVA_BINDINGS +#define CONFIG_JAVA_HOME "" +#undef CONFIG_PERL_BINDINGS +#define CONFIG_PERL_CORE "" +#define CONFIG_PERL_LIB "" +#undef CONFIG_LUA_BINDINGS +#define CONFIG_LUA_CORE "" + +/* + * Samples + */ +#undef CONFIG_SAMPLES +#undef CONFIG_C_SAMPLES +#undef CONFIG_CSHARP_SAMPLES +#undef CONFIG_VBNET_SAMPLES +#undef CONFIG_JAVA_SAMPLES +#undef CONFIG_PERL_SAMPLES +#undef CONFIG_LUA_SAMPLES +#undef CONFIG_BIGINT_CLASSICAL +#undef CONFIG_BIGINT_MONTGOMERY +#undef CONFIG_BIGINT_BARRETT +#undef CONFIG_BIGINT_CRT +#undef CONFIG_BIGINT_KARATSUBA +#define MUL_KARATSUBA_THRESH +#define SQU_KARATSUBA_THRESH +#undef CONFIG_BIGINT_SLIDING_WINDOW +#undef CONFIG_BIGINT_SQUARE +#undef CONFIG_BIGINT_CHECK_ON diff --git a/contrib/axtls/patches/001-ld-fix.patch b/contrib/axtls/patches/001-ld-fix.patch new file mode 100644 index 0000000000..2456007055 --- /dev/null +++ b/contrib/axtls/patches/001-ld-fix.patch @@ -0,0 +1,12 @@ +diff -urb axTLS.orig/ssl/Makefile axTLS/ssl/Makefile +--- axTLS.orig/ssl/Makefile 2008-11-09 00:58:43.000000000 +0000 ++++ axTLS/ssl/Makefile 2008-11-09 00:58:57.000000000 +0000 +@@ -96,7 +96,7 @@ + + $(TARGET2) : $(OBJ) + ifndef CONFIG_PLATFORM_CYGWIN +- $(LD) $(LDFLAGS) $(LDSHARED) -Wl,-soname,$(LIBMAJOR) -o $(AXTLS_HOME)/$(STAGE)/$(LIBMINOR) $(CRYPTO_OBJ) $(OBJ) ++ $(LD) $(LDFLAGS) $(LDSHARED) -o $(AXTLS_HOME)/$(STAGE)/$(LIBMINOR) $(CRYPTO_OBJ) $(OBJ) + cd $(AXTLS_HOME)/$(STAGE); ln -sf $(LIBMINOR) $(LIBMAJOR); ln -sf $(LIBMAJOR) $(BASETARGET); cd - + else + $(LD) $(LDFLAGS) $(LDSHARED) -o $(AXTLS_HOME)/$(STAGE)/cygaxtls.dll \ diff --git a/contrib/axtls/patches/002-httpd-fix.patch b/contrib/axtls/patches/002-httpd-fix.patch new file mode 100644 index 0000000000..e6fd152d8a --- /dev/null +++ b/contrib/axtls/patches/002-httpd-fix.patch @@ -0,0 +1,12 @@ +diff -urb axTLS.orig/httpd/Makefile axTLS/httpd/Makefile +--- axTLS.orig/httpd/Makefile 2008-11-09 00:58:44.000000000 +0000 ++++ axTLS/httpd/Makefile 2008-11-09 01:29:55.000000000 +0000 +@@ -95,7 +95,7 @@ + ifndef CONFIG_PLATFORM_WIN32 + + $(TARGET): $(OBJ) $(AXTLS_HOME)/$(STAGE)/libaxtls.a +- $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) ++ $(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) + ifdef CONFIG_STRIP_UNWANTED_SECTIONS + strip --remove-section=.comment $(TARGET) + endif diff --git a/contrib/axtls/patches/003-content-type.patch b/contrib/axtls/patches/003-content-type.patch new file mode 100644 index 0000000000..476890cf16 --- /dev/null +++ b/contrib/axtls/patches/003-content-type.patch @@ -0,0 +1,37 @@ +diff -urb axTLS.orig/httpd/axhttp.h axTLS/httpd/axhttp.h +--- axTLS.orig/httpd/axhttp.h 2008-11-09 00:58:44.000000000 +0000 ++++ axTLS/httpd/axhttp.h 2008-11-09 02:33:44.000000000 +0000 +@@ -91,6 +91,7 @@ + uint8_t is_lua; + #endif + int content_length; ++ char content_type[MAXREQUESTLENGTH]; + char remote_addr[MAXREQUESTLENGTH]; + char uri_request[MAXREQUESTLENGTH]; + char uri_path_info[MAXREQUESTLENGTH]; +diff -urb axTLS.orig/httpd/proc.c axTLS/httpd/proc.c +--- axTLS.orig/httpd/proc.c 2008-11-09 00:58:44.000000000 +0000 ++++ axTLS/httpd/proc.c 2008-11-09 02:43:32.000000000 +0000 +@@ -129,6 +129,10 @@ + + my_strncpy(cn->server_name, value, MAXREQUESTLENGTH); + } ++ else if (strcmp(buf, "Content-Type:") == 0 ) ++ { ++ my_strncpy(cn->content_type, value, MAXREQUESTLENGTH); ++ } + else if (strcmp(buf, "Connection:") == 0 && strcmp(value, "close") == 0) + { + cn->close_when_done = 1; +@@ -673,8 +677,9 @@ + type = "POST"; + sprintf(cgienv[cgi_index++], + "CONTENT_LENGTH=%d", cn->content_length); +- strcpy(cgienv[cgi_index++], /* hard-code? */ +- "CONTENT_TYPE=application/x-www-form-urlencoded"); ++ snprintf(cgienv[cgi_index++], MAXREQUESTLENGTH, ++ "CONTENT_TYPE=%s", cn->content_type); ++ + break; + } + diff --git a/contrib/axtls/patches/004-cgi-nph-mode.patch b/contrib/axtls/patches/004-cgi-nph-mode.patch new file mode 100644 index 0000000000..2b6cc5c434 --- /dev/null +++ b/contrib/axtls/patches/004-cgi-nph-mode.patch @@ -0,0 +1,20 @@ +--- axTLS/httpd/proc.c 2008-11-13 14:05:02.000000000 +0100 ++++ axTLS.new/httpd/proc.c 2008-11-13 16:07:12.000000000 +0100 +@@ -556,13 +556,13 @@ + int tmp_stdout; + #endif + +- snprintf(cgienv[0], MAXREQUESTLENGTH, ++ if (cn->reqtype == TYPE_HEAD) ++ { ++ snprintf(cgienv[0], MAXREQUESTLENGTH, + HTTP_VERSION" 200 OK\nServer: %s\n%s", + server_version, (cn->reqtype == TYPE_HEAD) ? "\n" : ""); +- special_write(cn, cgienv[0], strlen(cgienv[0])); ++ special_write(cn, cgienv[0], strlen(cgienv[0])); + +- if (cn->reqtype == TYPE_HEAD) +- { + removeconnection(cn); + return; + } diff --git a/contrib/package/xrelayd/Makefile b/contrib/package/xrelayd/Makefile new file mode 100644 index 0000000000..639bc59d2e --- /dev/null +++ b/contrib/package/xrelayd/Makefile @@ -0,0 +1,59 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=xrelayd +PKG_VERSION:=0.2.1pre2 +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=http://znerol.ch/files +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_MD5SUM:=05f242295fa864bb3b0b7f0712b4dfa3 + +PKG_CAT:=zcat +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install + +PKG_BUILD_DEPENDS:=libxyssl + +include $(INCLUDE_DIR)/package.mk + +define Package/xrelayd + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libxyssl + TITLE:=stunnel replacement based on xyssl + URL:=http://znerol.ch/ +endef + +define Package/xrelayd/description + stunnel replacement based on xyssl +endef + +define Build/Configure +endef + +define Build/Compile + rm -rf $(PKG_INSTALL_DIR) + mkdir -p $(PKG_INSTALL_DIR) + $(MAKE) -C $(PKG_BUILD_DIR) \ + $(TARGET_CONFIGURE_OPTS) \ + CC="$(TARGET_CC)" \ + LD="$(TARGET_CC)" \ + CFLAGS="$(strip $(TARGET_CFLAGS))" \ + CPPFLAGS="$$$$CPPFLAGS -I$(STAGING_DIR)/usr/include" \ + LDFLAGS="-L$(STAGING_DIR)/usr/lib" \ + prefix="$(PKG_INSTALL_DIR)/usr" + mkdir -p $(PKG_INSTALL_DIR)/usr/bin + $(CP) $(PKG_BUILD_DIR)/xrelayd $(PKG_INSTALL_DIR)/usr/bin +endef + +define Package/xrelayd/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/xrelayd $(1)/usr/bin + $(RSTRIP) $(1)/usr/bin/xrelayd +endef + +#mostlyclean: +# make -C $(PKG_BUILD_DIR) clean +# rm $(PKG_BUILD_DIR)/.built + +$(eval $(call BuildPackage,xrelayd)) diff --git a/modules/freifunk/htdocs/cgi-bin-nodes.html b/libs/httpd/hostfiles/www/index.html similarity index 60% rename from modules/freifunk/htdocs/cgi-bin-nodes.html rename to libs/httpd/hostfiles/www/index.html index d409a7cb67..838da048a4 100644 --- a/modules/freifunk/htdocs/cgi-bin-nodes.html +++ b/libs/httpd/hostfiles/www/index.html @@ -2,9 +2,9 @@ - + -LuCI - Lua Configuration Interface +LuCI - Lua Configuration Interface diff --git a/libs/lucittpd/Makefile b/libs/lucittpd/Makefile new file mode 100644 index 0000000000..3d1a91177e --- /dev/null +++ b/libs/lucittpd/Makefile @@ -0,0 +1,18 @@ +ifeq ($(CFLAGS),) + MYLDFLAGS ?= -L../../../contrib/uci/dist/usr/lib/ +endif + +include ../../build/module.mk +include ../../build/config.mk +include ../../build/gccconfig.mk + +compile: + make -Csrc \ + CFLAGS="$(CFLAGS) $(FPIC) $(LUA_CFLAGS) $(EXTRA_CFLAGS) $(WFLAGS)" \ + LDFLAGS="$(LDFLAGS) $(LUA_SHLIBS) -luci" \ + MYLDFLAGS="$(MYLDFLAGS)" + mkdir -p dist/usr/bin + cp src/lucittpd dist/usr/bin + +clean: luaclean + make -Csrc clean diff --git a/libs/lucittpd/hostfiles/usr/lib/lucittpd/plugins/httpd.lua b/libs/lucittpd/hostfiles/usr/lib/lucittpd/plugins/httpd.lua new file mode 100644 index 0000000000..e40af98fd9 --- /dev/null +++ b/libs/lucittpd/hostfiles/usr/lib/lucittpd/plugins/httpd.lua @@ -0,0 +1,34 @@ +function initialize() + local lucittpd = require "luci.ttpd.server" + server = lucittpd.Server(lucittpd.VHost()) +end + +function register() + local filehnd = require "luci.ttpd.handler.file" + local filehandler = filehnd.Simple(os.getenv("LUCI_SYSROOT") .. "/www") + server:get_default_vhost():set_default_handler(filehandler) +end + +function accept() + server:process({ + _read = function(...) + local chunk, err = webuci_read(...) + return chunk or (err and error(err, 0)) + end, + + _write = function(...) + local chunk, err = webuci_write(...) + return chunk or (err and error(err, 0)) + end, + + _close = function(...) + local chunk, err = webuci_close(...) + return chunk or (err and error(err, 0)) + end, + + _sendfile = function(...) + local chunk, err = webuci_sendfile(...) + return chunk or (err and error(err, 0)) + end + }) +end \ No newline at end of file diff --git a/libs/lucittpd/ipkg/postinst b/libs/lucittpd/ipkg/postinst new file mode 100755 index 0000000000..d3890aa0e9 --- /dev/null +++ b/libs/lucittpd/ipkg/postinst @@ -0,0 +1,6 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + /etc/init.d/lucittpd enabled || /etc/init.d/lucittpd enable + /etc/init.d/lucittpd start || true +} + diff --git a/libs/lucittpd/luasrc/ttpd/handler/file.lua b/libs/lucittpd/luasrc/ttpd/handler/file.lua new file mode 100644 index 0000000000..e1f707c628 --- /dev/null +++ b/libs/lucittpd/luasrc/ttpd/handler/file.lua @@ -0,0 +1,252 @@ +--[[ + +HTTP server implementation for LuCI - file handler +(c) 2008 Steven Barth +(c) 2008 Freifunk Leipzig / Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +]]-- + +local ipairs, type, tonumber = ipairs, type, tonumber +local io = require "io" +local os = require "os" +local fs = require "luci.fs" +local util = require "luci.util" +local ltn12 = require "luci.ltn12" +local mod = require "luci.ttpd.module" +local srv = require "luci.ttpd.server" +local string = require "string" + +local prot = require "luci.http.protocol" +local date = require "luci.http.protocol.date" +local mime = require "luci.http.protocol.mime" +local cond = require "luci.http.protocol.conditionals" + +module "luci.ttpd.handler.file" + +Simple = util.class(mod.Handler) +Response = mod.Response + +function Simple.__init__(self, docroot, dirlist) + mod.Handler.__init__(self) + self.docroot = docroot + self.dirlist = dirlist and true or false +end + +function Simple.parse_range(self, request, size) + if not request.headers.Range then + return true + end + + local from, to = request.headers.Range:match("bytes=([0-9]*)-([0-9]*)") + if not (from or to) then + return true + end + + from, to = tonumber(from), tonumber(to) + if not (from or to) then + return true + elseif not from then + from, to = size - to, size - 1 + elseif not to then + to = size - 1 + end + + -- Not satisfiable + if from >= size then + return false + end + + -- Normalize + if to >= size then + to = size - 1 + end + + local range = "bytes " .. from .. "-" .. to .. "/" .. size + return from, (1 + to - from), range +end + +function Simple.getfile(self, uri) + local file = self.docroot .. uri:gsub("%.%./+", "") + local stat = fs.stat(file) + + return file, stat +end + +function Simple.handle_get(self, request, sourcein, sinkerr) + local file, stat = self:getfile( prot.urldecode( request.env.PATH_INFO, true ) ) + + if stat then + if stat.type == "regular" then + + -- Generate Entity Tag + local etag = cond.mk_etag( stat ) + + -- Check conditionals + local ok, code, hdrs + + ok, code, hdrs = cond.if_modified_since( request, stat ) + if ok then + ok, code, hdrs = cond.if_match( request, stat ) + if ok then + ok, code, hdrs = cond.if_unmodified_since( request, stat ) + if ok then + ok, code, hdrs = cond.if_none_match( request, stat ) + if ok then + local f, err = io.open(file) + + if f then + local code = 200 + local o, s, r = self:parse_range(request, stat.size) + + if not o then + return self:failure(416, "Invalid Range") + end + + local headers = { + ["Last-Modified"] = date.to_http( stat.mtime ), + ["Content-Type"] = mime.to_mime( file ), + ["ETag"] = etag, + ["Accept-Ranges"] = "bytes", + } + + if o == true then + o = 0 + s = stat.size + else + code = 206 + headers["Content-Range"] = r + end + + headers["Content-Length"] = s + + -- Send Response + return Response(code, headers), + srv.IOResource(f, o, s) + else + return self:failure( 403, err:gsub("^.+: ", "") ) + end + else + return Response( code, hdrs or { } ) + end + else + return Response( code, hdrs or { } ) + end + else + return Response( code, hdrs or { } ) + end + else + return Response( code, hdrs or { } ) + end + + elseif stat.type == "directory" then + + local ruri = request.request_uri:gsub("/$","") + local duri = prot.urldecode( ruri, true ) + local root = self.docroot:gsub("/$","") + + -- check for index files + local index_candidates = { + "index.html", "index.htm", "default.html", "default.htm", + "index.txt", "default.txt" + } + + -- try to find an index file and redirect to it + for i, candidate in ipairs( index_candidates ) do + local istat = fs.stat( + root .. "/" .. duri .. "/" .. candidate + ) + + if istat ~= nil and istat.type == "regular" then + return Response( 302, { + ["Location"] = ruri .. "/" .. candidate + } ) + end + end + + + local html = string.format( + '\n' .. + '\n' .. + '\n' .. + '\n' .. + 'Index of %s/\n' .. + '

Index of %s/


    ', + duri, duri + ) + + local entries = fs.dir( file ) + + if type(entries) == "table" then + for i, e in util.spairs( + entries, function(a,b) + if entries[a] == '..' then + return true + elseif entries[b] == '..' then + return false + else + return ( entries[a] < entries[b] ) + end + end + ) do + if e ~= '.' and ( e == '..' or e:sub(1,1) ~= '.' ) then + local estat = fs.stat( file .. "/" .. e ) + + if estat.type == "directory" then + html = html .. string.format( + '
  • %s/ ' .. + '(directory)
    ' .. + 'Changed: %s

  • ', + ruri, prot.urlencode( e ), e, + date.to_http( estat.mtime ) + ) + else + html = html .. string.format( + '
  • %s ' .. + '(%s)
    ' .. + 'Size: %i Bytes | ' .. + 'Changed: %s

  • ', + ruri, prot.urlencode( e ), e, + mime.to_mime( e ), + estat.size, date.to_http( estat.mtime ) + ) + end + end + end + + html = html .. '

' + + return Response( + 200, { + ["Date"] = date.to_http( os.time() ); + ["Content-Type"] = "text/html; charset=ISO-8859-15"; + } + ), ltn12.source.string(html) + else + return self:failure(403, "Permission denied") + end + else + return self:failure(403, "Unable to transmit " .. stat.type .. " " .. file) + end + else + return self:failure(404, "No such file: " .. file) + end +end + +function Simple.handle_head(self, ...) + return (self:handle_get(...)) +end diff --git a/libs/lucittpd/luasrc/ttpd/module.lua b/libs/lucittpd/luasrc/ttpd/module.lua new file mode 100644 index 0000000000..1a7c574733 --- /dev/null +++ b/libs/lucittpd/luasrc/ttpd/module.lua @@ -0,0 +1,121 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local pcall, ipairs, tonumber, type, next = pcall, ipairs, tonumber, type, next +local util = require "luci.util" +local http = require "luci.http.protocol" +local ltn12 = require "luci.ltn12" +local table = require "table" + +module "luci.ttpd.module" + + +-- Server handler implementation +Handler = util.class() + +-- Constructor +function Handler.__init__(self) + self.handler = {} + self.filters = {} + self.modifiers = {} +end + +-- Add a filter +function Handler.setfilter(self, filter, key) + self.filters[(key) or (#self.filters+1)] = filter +end + +-- Add a modifier +function Handler.setmodifier(self, modifier, key) + self.modifiers[(pos) or (#self.modifiers+1)] = modifier +end + +-- Creates a failure reply +function Handler.failure(self, code, message) + local response = Response(code, { ["Content-Type"] = "text/plain" }) + local sourceout = ltn12.source.string(message) + + return response, sourceout +end + +-- Processes a request +function Handler.process(self, request, sourcein, sinkerr) + local stat, response, sourceout + + -- Detect request Method + local hname = "handle_" .. request.request_method + if self[hname] then + local t = { + processor = self[hname], + handler = self, + request = request, + sourcein = sourcein, + sinkerr = sinkerr + } + + if next(self.modifiers) then + for _, mod in util.kspairs(self.modifiers) do + mod(t) + end + end + + -- Run the handler + stat, response, sourceout = pcall( + t.processor, t.handler, t.request, t.sourcein, t.sinkerr + ) + + -- Check for any errors + if not stat then + response, sourceout = self:failure(500, response) + elseif next(self.filters) then + local t = { + response = response, + sourceout = sourceout, + sinkerr = t.sinkerr + } + + for _, filter in util.kspairs(self.filters) do + filter(t) + end + + response = t.response + sourceout = t.sourceout + end + else + response, sourceout = self:failure(405, http.protocol.statusmsg[405]) + end + + -- Check data + if not util.instanceof(response, Response) then + response, sourceout = self:failure(500, "Core error: Invalid module response!") + end + + return response, sourceout +end + +-- Handler Response +Response = util.class() + +function Response.__init__(self, status, headers) + self.status = tonumber(status) or 200 + self.headers = (type(headers) == "table") and headers or {} +end + +function Response.addheader(self, key, value) + self.headers[key] = value +end + +function Response.setstatus(self, status) + self.status = status +end \ No newline at end of file diff --git a/libs/lucittpd/luasrc/ttpd/server.lua b/libs/lucittpd/luasrc/ttpd/server.lua new file mode 100644 index 0000000000..a2c7ffcb29 --- /dev/null +++ b/libs/lucittpd/luasrc/ttpd/server.lua @@ -0,0 +1,444 @@ +--[[ +LuCIttpd +(c) 2008 Steven Barth +(c) 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local ipairs, pairs = ipairs, pairs +local tostring, tonumber = tostring, tonumber +local pcall, assert = pcall, assert + +local os = require "os" +local io = require "io" +local uci = require "luci.model.uci" +local util = require "luci.util" +local ltn12 = require "luci.ltn12" +local proto = require "luci.http.protocol" +local string = require "string" +local date = require "luci.http.protocol.date" + +module "luci.ttpd.server" + +BUFSIZE = 4096 +VERSION = 0.91 + + +-- File Resource +IOResource = util.class() + +function IOResource.__init__(self, fd, offset, len) + self.fd, self.offset, self.len = fd, offset, len +end + + +VHost = util.class() + +function VHost.__init__(self, handler) + self.handler = handler + self.dhandler = {} +end + +function VHost.process(self, request, sourcein, sinkerr, ...) + local handler = self.handler + + local uri = request.env.REQUEST_URI:match("^([^?]*)") + + -- SCRIPT_NAME + request.env.SCRIPT_NAME = "" + + -- Call URI part + request.env.PATH_INFO = uri + + for k, dhandler in pairs(self.dhandler) do + if k == uri or k.."/" == uri:sub(1, #k+1) then + handler = dhandler + request.env.SCRIPT_NAME = k + request.env.PATH_INFO = uri:sub(#k+1) + break; + end + end + + if handler then + return handler:process(request, sourcein, sinkerr, ...) + end +end + +function VHost.get_default_handler(self) + return self.handler +end + +function VHost.set_default_handler(self, handler) + self.handler = handler +end + +function VHost.get_handlers(self) + return self.dhandler +end + +function VHost.set_handler(self, match, handler) + self.dhandler[match] = handler +end + + + +Server = util.class() + +function Server.__init__(self, host) + self.uci = uci.cursor() + self.host = host + self.vhosts = {} + + self.rbuf = "" + self.wbuf = "" +end + +function Server.get_default_vhost(self) + return self.host +end + +function Server.set_default_vhost(self, vhost) + self.host = vhost +end + +function Server.get_vhosts(self) + return self.vhosts +end + +function Server.set_vhost(self, name, vhost) + self.vhosts[name] = vhost +end + +function Server.flush(self) + if #self.wbuf > 0 then + self._write(self.wbuf) + self.wbuf = "" + end +end + +function Server.read(self, len) + while #self.rbuf < len do + self.rbuf = self.rbuf .. self._read(len - #self.rbuf) + end + + local chunk = self.rbuf:sub(1, len) + self.rbuf = self.rbuf:sub(len + 1) + return chunk +end + +function Server.limitsource(self, limit) + limit = limit or 0 + + return function() + if limit < 1 then + return nil + else + local read = (limit > BUFSIZE) and BUFSIZE or limit + limit = limit - read + return self:read(read) + end + end +end + +-- Adapted from Luaposix +function Server.receiveheaders(self) + local line, name, value, err + local headers = {} + -- get first line + line, err = self:readline() + if err then return nil, err end + -- headers go until a blank line is found + while line do + -- get field-name and value + _, _, name, value = line:find("^(.-):%s*(.*)") + if not (name and value) then return nil, "malformed reponse headers" end + name = name:lower() + -- get next line (value might be folded) + line, err = self:readline() + if err then return nil, err end + -- unfold any folded values + while line:find("^%s") do + value = value .. line + line = self:readline() + if err then return nil, err end + end + -- save pair in table + if headers[name] then headers[name] = headers[name] .. ", " .. value + else headers[name] = value end + end + return headers +end + +function Server.readchunk(self) + -- get chunk size, skip extention + local line, err = self:readline() + if err then return nil, err end + local size = tonumber(line:gsub(";.*", ""), 16) + if not size then return nil, "invalid chunk size" end + -- was it the last chunk? + if size > 0 then + -- if not, get chunk and skip terminating CRLF + local chunk, err, part = self:read(size) + if chunk then self:readline() end + return chunk, err + else + -- if it was, read trailers into headers table + headers, err = self:receiveheaders() + if not headers then return nil, err end + end +end + +function Server.readline(self) + if #self.rbuf < 1 then + self.rbuf = self._read(BUFSIZE) + end + + while true do + local le = self.rbuf:find("\r\n", nil, true) + if le then + if le == 1 then -- EoH + self.rbuf = self.rbuf:sub(le + 2) + return nil + else -- Header + local line = self.rbuf:sub(1, le - 1) + self.rbuf = self.rbuf:sub(le + 2) + return line + end + else + if #self.rbuf >= BUFSIZE then + return nil, "Invalid Request" + end + self.rbuf = self.rbuf .. self._read(BUFSIZE-#self.rbuf) + end + end +end + +function Server.sink(self) + return function(chunk, err) + if err then + return nil, err + elseif chunk then + local stat, err = pcall(self.write, self, chunk) + if stat then + return stat + else + return nil, err + end + else + return true + end + end +end + +function Server.chunksink(self) + return function(chunk, err) + local stat, err = pcall(self.writechunk, self, chunk) + if stat then + return stat + else + return nil, err + end + end +end + +function Server.writechunk(self, chunk, err) + self:flush() + if not chunk then return self._write("0\r\n\r\n") end + local size = string.format("%X\r\n", #chunk) + return self._write(size .. chunk .. "\r\n") +end + +function Server.write(self, chunk) + while #chunk > 0 do + local missing = BUFSIZE - #self.wbuf + self.wbuf = self.wbuf .. chunk:sub(1, missing) + chunk = chunk:sub(missing + 1) + if #self.wbuf == BUFSIZE then + assert(self._write(self.wbuf)) + self.wbuf = "" + end + end +end + +function Server.close(self) + self:flush() + self._close() +end + +function Server.sendfile(self, fd, offset, len) + self:flush() + self._sendfile(fd, offset, len) +end + + +function Server.error(self, code, msg) + hcode = tostring(code) + + self:write( "HTTP/1.0 " .. hcode .. " " .. + proto.statusmsg[code] .. "\r\n" ) + self:write( "Connection: close\r\n" ) + self:write( "Content-Type: text/plain\r\n\r\n" ) + + if msg then + self:write( "HTTP-Error " .. code .. ": " .. msg .. "\r\n" ) + end +end + + +function Server.process(self, functions) + util.update(self, functions) + + local sourcein = ltn12.source.empty() + local sourcehdr = function() return self:readline() or "" end + local sinkerr = ltn12.sink.file( io.stderr ) + local sinkout = self:sink() + + local close = false + local stat, message, err + + repeat + -- parse headers + stat, message, err = pcall(proto.parse_message_header, sourcehdr) + + -- remote socket closed + if not stat and message == 0 then + break + end + + -- remote timeout + if not stat and message == 11 then + --self:error(408) + break + end + + -- any other error + if not stat or not message then + self:error(400, err) + break + end + + -- keep-alive + if message.http_version == 1.1 then + close = (message.env.HTTP_CONNECTION == "close") + else + close = not message.env.HTTP_CONNECTION or message.env.HTTP_CONNECTION == "close" + end + -- Uncomment this to disable keep-alive + close = not (self.uci:get("lucittpd", "lucittpd", "keepalive") == "1") + + if message.request_method == "get" or message.request_method == "head" then + -- Be happy + + elseif message.request_method == "post" then + -- If we have a HTTP/1.1 client and an Expect: 100-continue header then + -- respond with HTTP 100 Continue message + if message.http_version == 1.1 and message.headers['Expect'] and + message.headers['Expect'] == '100-continue' + then + self:write("HTTP/1.1 100 Continue\r\n\r\n") + end + + if message.headers['Transfer-Encoding'] and + message.headers['Transfer-Encoding'] ~= "identity" then + sourcein = function() return self:readchunk() end + elseif message.env.CONTENT_LENGTH then + sourcein = self:limitsource( + tonumber(message.env.CONTENT_LENGTH) + ) + else + self:error( 411, proto.statusmsg[411] ) + break + end + else + self:error( 405, proto.statusmsg[405] ) + break + + end + + + local host = self.vhosts[message.env.HTTP_HOST] or self.host + if not host then + self:error( 500, "Unable to find matching host" ) + break; + end + + local response, sourceout = host:process( + message, sourcein, sinkerr, + client, io.stderr + ) + if not response then + self:error( 500, "Error processing handler" ) + end + + -- Post process response + if sourceout then + if util.instanceof(sourceout, IOResource) then + if not response.headers["Content-Length"] then + response.headers["Content-Length"] = sourceout.len + end + end + if not response.headers["Content-Length"] then + if message.http_version == 1.1 then + response.headers["Transfer-Encoding"] = "chunked" + sinkout = self:chunksink() + else + close = true + end + end + elseif message.request_method ~= "head" then + response.headers["Content-Length"] = 0 + end + + if close then + response.headers["Connection"] = "close" + end + + response.headers["Date"] = date.to_http(os.time()) + + local header = + message.env.SERVER_PROTOCOL .. " " .. + tostring(response.status) .. " " .. + proto.statusmsg[response.status] .. "\r\n" + + header = header .. "Server: LuCIttpd/" .. tostring(VERSION) .. "\r\n" + + + for k,v in pairs(response.headers) do + header = header .. k .. ": " .. v .. "\r\n" + end + + -- Output + local stat, err = pcall(function() + self:write(header .. "\r\n") + + if sourceout then + if util.instanceof(sourceout, IOResource) then + self:sendfile(sourceout.fd, sourceout.offset, sourceout.len) + else + ltn12.pump.all(sourceout, sinkout) + end + end + + self:flush() + end) + + -- Write errors + if not stat then + if err == 107 then + -- Remote end closed the socket, so do we + elseif err then + io.stderr:write("Error sending data: " .. err .. "\n") + end + break + end + until close + + self:close() +end diff --git a/libs/lucittpd/root/etc/config/lucittpd b/libs/lucittpd/root/etc/config/lucittpd new file mode 100644 index 0000000000..803a6e50ca --- /dev/null +++ b/libs/lucittpd/root/etc/config/lucittpd @@ -0,0 +1,6 @@ +config lucittpd lucittpd + option port 80 + option timeout 90 + option keepalive 0 + option path /usr/lib/lucittpd/plugins/ + option root /www diff --git a/libs/lucittpd/root/etc/init.d/lucittpd b/libs/lucittpd/root/etc/init.d/lucittpd new file mode 100755 index 0000000000..a7f78e003a --- /dev/null +++ b/libs/lucittpd/root/etc/init.d/lucittpd @@ -0,0 +1,44 @@ +#!/bin/sh /etc/rc.common +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/lucittpd +NAME=lucittpd +DESC="HTTP server" +START=49 + +test -x $DAEMON || exit 0 +set -e + +start() { + echo -n "Starting $DESC: $NAME" + start-stop-daemon -b -S -q -x $DAEMON + echo "." +} + +stop() { + echo -n "Stopping $DESC: $NAME" + start-stop-daemon -K -q -x $DAEMON + echo "." +} + +restart() { + # echo -n "Restarting $DESC: $NAME... " + # start-stop-daemon -K -s HUP -q -x $DAEMON + # echo "done." + stop + sleep 3 + start +} + +reload() { + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + # echo -n "Reloading $DESC configuration... " + # start-stop-daemon -K -s 1 -q -x $DAEMON + # echo "done." + restart +} diff --git a/libs/lucittpd/root/usr/lib/lucittpd/plugins/httpd.lua b/libs/lucittpd/root/usr/lib/lucittpd/plugins/httpd.lua new file mode 100644 index 0000000000..2d3a9d8c87 --- /dev/null +++ b/libs/lucittpd/root/usr/lib/lucittpd/plugins/httpd.lua @@ -0,0 +1,35 @@ +function initialize() + local lucittpd = require "luci.ttpd.server" + server = lucittpd.Server(lucittpd.VHost()) +end + +function register() + local filehnd = require "luci.ttpd.handler.file" + local uci = require "luci.model.uci".cursor() + local filehandler = filehnd.Simple((uci:get("lucittpd", "lucittpd", "root") or "/www")) + server:get_default_vhost():set_default_handler(filehandler) +end + +function accept() + server:process({ + _read = function(...) + local chunk, err = webuci_read(...) + return chunk or (err and error(err, 0)) + end, + + _write = function(...) + local chunk, err = webuci_write(...) + return chunk or (err and error(err, 0)) + end, + + _close = function(...) + local chunk, err = webuci_close(...) + return chunk or (err and error(err, 0)) + end, + + _sendfile = function(...) + local chunk, err = webuci_sendfile(...) + return chunk or (err and error(err, 0)) + end + }) +end diff --git a/libs/lucittpd/src/.gitignore b/libs/lucittpd/src/.gitignore new file mode 100644 index 0000000000..882c68cb08 --- /dev/null +++ b/libs/lucittpd/src/.gitignore @@ -0,0 +1 @@ +lucittpd diff --git a/libs/lucittpd/src/Makefile b/libs/lucittpd/src/Makefile new file mode 100644 index 0000000000..1e70faffe4 --- /dev/null +++ b/libs/lucittpd/src/Makefile @@ -0,0 +1,20 @@ +PROGS=lucittpd +STRIP?=strip +CFLAGS?= +CFLAGS+=-pedantic -Werror -Wall -std=gnu99 -I/usr/include/lua5.1/ +CPPFLAGS=-I./include +LDFLAGS?= +LDFLAGS+=-luci -llua5.1 +OBJS=main.o lib/log.o lib/signal.o lib/uci.o lib/luaplugin.o + +all: $(PROGS) + +$(PROGS): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(MYLDFLAGS) $^ -o $@ + #$(CC) $(CFLAGS) -shared -Wl,-soname,gdata $(LDFLAGS) $^ -o $@ + +clean: + rm -f $(PROGS) *.o *.so lib/*.o + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(MYCFLAGS) -c $^ -o $@ diff --git a/libs/lucittpd/src/include/lib/list.h b/libs/lucittpd/src/include/lib/list.h new file mode 100644 index 0000000000..2959a061d3 --- /dev/null +++ b/libs/lucittpd/src/include/lib/list.h @@ -0,0 +1,601 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#ifndef container_of +#define container_of(ptr, type, member) ( \ + (type *)( (char *)ptr - offsetof(type,member) )) +#endif + + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = NULL; + n->pprev = NULL; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos; pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif diff --git a/libs/lucittpd/src/include/lib/log.h b/libs/lucittpd/src/include/lib/log.h new file mode 100644 index 0000000000..1199578d10 --- /dev/null +++ b/libs/lucittpd/src/include/lib/log.h @@ -0,0 +1,24 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Provided by fon.com + * Copyright (C) 2008 John Crispin + */ + +#ifndef _LOG_H__ +#define _LOG_H__ +void log_printf(char *fmt, ...); +void log_start(int daemon); +#endif diff --git a/libs/lucittpd/src/include/lib/luaplugin.h b/libs/lucittpd/src/include/lib/luaplugin.h new file mode 100644 index 0000000000..fca6cb7f2c --- /dev/null +++ b/libs/lucittpd/src/include/lib/luaplugin.h @@ -0,0 +1,71 @@ +/* + * luaplugin - fast lua plugin indexing + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __LUAPLUGIN_H +#define __LUAPLUGIN_H + +#include +#include +#include +#include +#include "list.h" + +struct luaplugin_entry { + struct luaplugin_ctx *ctx; + struct list_head list; + time_t timestamp; + int checked; + bool loaded; + bool reload; + char *name; + char *module; + + /* privdata for the caller */ + void *priv; +}; + +struct luaplugin_ctx { + const char *path; + const struct luaplugin_ops *ops; + lua_State *L; + int checked; + struct list_head *last; + struct list_head entries; +}; + +/** luaplugin_init: + * initialize the luaplugin context (allocates a new lua context) + */ +extern int luaplugin_init(struct luaplugin_ctx *ctx, const char *path); + +/** luaplugin_scan: + * rescan the plugin cache + */ +extern void luaplugin_scan(struct luaplugin_ctx *ctx); + +/** luaplugin_call: + * call out to a lua function. + * to be able to use this, you need to push the function name on the lua stack (ctx->L) + * and then narg function arguments afterwards. + * this call pops (narg + 1) arguments from the stack + * returns -ENOENT if the function was not found + */ +extern int luaplugin_call(struct luaplugin_entry *e, int narg); + +/** luaplugin_done: + * drop the luaplugin context (and associated lua context) + * frees all memory allocated by the library + */ +extern void luaplugin_done(struct luaplugin_ctx *ctx); + +#endif diff --git a/libs/lucittpd/src/include/lib/signal.h b/libs/lucittpd/src/include/lib/signal.h new file mode 100644 index 0000000000..cfcce0a167 --- /dev/null +++ b/libs/lucittpd/src/include/lib/signal.h @@ -0,0 +1,25 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Provided by fon.com + * Copyright (C) 2008 John Crispin + */ + +#ifndef _SIGNAL_H__ +#define _SIGNAL_H__ + +void setup_signals(void); + +#endif diff --git a/libs/lucittpd/src/include/lib/uci.h b/libs/lucittpd/src/include/lib/uci.h new file mode 100644 index 0000000000..4a1a01c09c --- /dev/null +++ b/libs/lucittpd/src/include/lib/uci.h @@ -0,0 +1,54 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2008 John Crispin + */ + +#ifndef _UCI_H__ +#define _UCI_H__ +#include +#include + +struct ucilist { + struct list_head list; + char *val; +}; + +struct uci_context* ucix_init(const char *config_file); +struct uci_context* ucix_init_path(const char *path, const char *config_file); +void ucix_cleanup(struct uci_context *ctx); +void ucix_save(struct uci_context *ctx); +void ucix_save_state(struct uci_context *ctx); +const char* ucix_get_option(struct uci_context *ctx, + const char *p, const char *s, const char *o); +int ucix_get_option_list(struct uci_context *ctx, const char *p, + const char *s, const char *o, struct list_head *l); +int ucix_get_option_int(struct uci_context *ctx, + const char *p, const char *s, const char *o, int def); +void ucix_add_section(struct uci_context *ctx, + const char *p, const char *s, const char *t); +void ucix_add_option(struct uci_context *ctx, + const char *p, const char *s, const char *o, const char *t); +void ucix_add_option_int(struct uci_context *ctx, + const char *p, const char *s, const char *o, int t); +void ucix_for_each_section_type(struct uci_context *ctx, + const char *p, const char *t, + void (*cb)(const char*, void*), void *priv); +int ucix_commit(struct uci_context *ctx, const char *p); +void ucix_revert(struct uci_context *ctx, + const char *p, const char *s, const char *o); +void ucix_del(struct uci_context *ctx, const char *p, + const char *s, const char *o); +#endif diff --git a/libs/lucittpd/src/include/uci.h b/libs/lucittpd/src/include/uci.h new file mode 100644 index 0000000000..d48ea7cef1 --- /dev/null +++ b/libs/lucittpd/src/include/uci.h @@ -0,0 +1,543 @@ +/* + * libuci - Library for the Unified Configuration Interface + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LIBUCI_H +#define __LIBUCI_H + +#include "uci_config.h" + +/* + * you can use these defines to enable debugging behavior for + * apps compiled against libuci: + * + * #define UCI_DEBUG_TYPECAST: + * enable uci_element typecast checking at run time + * + */ + +#include +#include +#include + +#define UCI_CONFDIR "/etc/config" +#define UCI_SAVEDIR "/tmp/.uci" +#define UCI_DIRMODE 0700 +#define UCI_FILEMODE 0600 + +enum +{ + UCI_OK = 0, + UCI_ERR_MEM, + UCI_ERR_INVAL, + UCI_ERR_NOTFOUND, + UCI_ERR_IO, + UCI_ERR_PARSE, + UCI_ERR_DUPLICATE, + UCI_ERR_UNKNOWN, + UCI_ERR_LAST +}; + +struct uci_list; +struct uci_list +{ + struct uci_list *next; + struct uci_list *prev; +}; + +struct uci_ptr; +struct uci_element; +struct uci_package; +struct uci_section; +struct uci_option; +struct uci_history; +struct uci_context; +struct uci_backend; +struct uci_parse_context; + + +/** + * uci_alloc_context: Allocate a new uci context + */ +extern struct uci_context *uci_alloc_context(void); + +/** + * uci_free_context: Free the uci context including all of its data + */ +extern void uci_free_context(struct uci_context *ctx); + +/** + * uci_perror: Print the last uci error that occured + * @ctx: uci context + * @str: string to print before the error message + */ +extern void uci_perror(struct uci_context *ctx, const char *str); + +/** + * uci_geterror: Get an error string for the last uci error + * @ctx: uci context + * @dest: target pointer for the string + * @str: prefix for the error message + * + * Note: string must be freed by the caller + */ +extern void uci_get_errorstr(struct uci_context *ctx, char **dest, const char *str); + +/** + * uci_import: Import uci config data from a stream + * @ctx: uci context + * @stream: file stream to import from + * @name: (optional) assume the config has the given name + * @package: (optional) store the last parsed config package in this variable + * @single: ignore the 'package' keyword and parse everything into a single package + * + * the name parameter is for config files that don't explicitly use the 'package <...>' keyword + * if 'package' points to a non-null struct pointer, enable history tracking and merge + */ +extern int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single); + +/** + * uci_export: Export one or all uci config packages + * @ctx: uci context + * @stream: output stream + * @package: (optional) uci config package to export + * @header: include the package header + */ +extern int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header); + +/** + * uci_load: Parse an uci config file and store it in the uci context + * + * @ctx: uci context + * @name: name of the config file (relative to the config directory) + * @package: store the loaded config package in this variable + */ +extern int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package); + +/** + * uci_unload: Unload a config file from the uci context + * + * @ctx: uci context + * @package: pointer to the uci_package struct + */ +extern int uci_unload(struct uci_context *ctx, struct uci_package *p); + +/** + * uci_lookup_ptr: Split an uci tuple string and look up an element tree + * @ctx: uci context + * @ptr: lookup result struct + * @str: uci tuple string to look up + * @extended: allow extended syntax lookup + * + * if extended is set to true, uci_lookup_ptr supports the following + * extended syntax: + * + * Examples: + * network.@interface[0].ifname ('ifname' option of the first interface section) + * network.@interface[-1] (last interface section) + * Note: uci_lookup_ext will automatically load a config package if necessary + */ +extern int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended); + +/** + * uci_add_section: Add an unnamed section + * @ctx: uci context + * @p: package to add the section to + * @type: section type + * @res: pointer to store a reference to the new section in + */ +extern int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res); + +/** + * uci_set: Set an element's value; create the element if necessary + * @ctx: uci context + * @ptr: uci pointer + * + * The updated/created element is stored in ptr->last + */ +extern int uci_set(struct uci_context *ctx, struct uci_ptr *ptr); + +/** + * uci_add_list: Append a string to an element list + * @ctx: uci context + * @ptr: uci pointer (with value) + * + * Note: if the given option already contains a string value, + * it will be converted to an 1-element-list before appending the next element + */ +extern int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr); + +/** + * uci_rename: Rename an element + * @ctx: uci context + * @ptr: uci pointer (with value) + */ +extern int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr); + +/** + * uci_delete: Delete a section or option + * @ctx: uci context + * @ptr: uci pointer + */ +extern int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr); + +/** + * uci_save: save change history for a package + * @ctx: uci context + * @p: uci_package struct + */ +extern int uci_save(struct uci_context *ctx, struct uci_package *p); + +/** + * uci_commit: commit changes to a package + * @ctx: uci context + * @p: uci_package struct pointer + * @overwrite: overwrite existing config data and flush history + * + * committing may reload the whole uci_package data, + * the supplied pointer is updated accordingly + */ +extern int uci_commit(struct uci_context *ctx, struct uci_package **p, bool overwrite); + +/** + * uci_list_configs: List available uci config files + * @ctx: uci context + * + * caller is responsible for freeing the allocated memory behind list + */ +extern int uci_list_configs(struct uci_context *ctx, char ***list); + +/** + * uci_set_savedir: override the default history save directory + * @ctx: uci context + * @dir: directory name + */ +extern int uci_set_savedir(struct uci_context *ctx, const char *dir); + +/** + * uci_set_savedir: override the default config storage directory + * @ctx: uci context + * @dir: directory name + */ +extern int uci_set_confdir(struct uci_context *ctx, const char *dir); + +/** + * uci_add_history_path: add a directory to the search path for change history files + * @ctx: uci context + * @dir: directory name + * + * This function allows you to add directories, which contain 'overlays' + * for the active config, that will never be committed. + */ +extern int uci_add_history_path(struct uci_context *ctx, const char *dir); + +/** + * uci_revert: revert all changes to a config item + * @ctx: uci context + * @ptr: uci pointer + */ +extern int uci_revert(struct uci_context *ctx, struct uci_ptr *ptr); + +/** + * uci_parse_argument: parse a shell-style argument, with an arbitrary quoting style + * @ctx: uci context + * @stream: input stream + * @str: pointer to the current line (use NULL for parsing the next line) + * @result: pointer for the result + */ +extern int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result); + +/** + * uci_set_backend: change the default backend + * @ctx: uci context + * @name: name of the backend + * + * The default backend is "file", which uses /etc/config for config storage + */ +extern int uci_set_backend(struct uci_context *ctx, const char *name); + +/** + * uci_validate_text: validate a value string for uci options + * @str: value + * + * this function checks whether a given string is acceptable as value + * for uci options + */ +extern bool uci_validate_text(const char *str); + +/* UCI data structures */ +enum uci_type { + UCI_TYPE_UNSPEC = 0, + UCI_TYPE_HISTORY = 1, + UCI_TYPE_PACKAGE = 2, + UCI_TYPE_SECTION = 3, + UCI_TYPE_OPTION = 4, + UCI_TYPE_PATH = 5, + UCI_TYPE_BACKEND = 6, + UCI_TYPE_ITEM = 7, +}; + +enum uci_option_type { + UCI_TYPE_STRING = 0, + UCI_TYPE_LIST = 1, +}; + +enum uci_flags { + UCI_FLAG_STRICT = (1 << 0), /* strict mode for the parser */ + UCI_FLAG_PERROR = (1 << 1), /* print parser error messages */ + UCI_FLAG_EXPORT_NAME = (1 << 2), /* when exporting, name unnamed sections */ + UCI_FLAG_SAVED_HISTORY = (1 << 3), /* store the saved history in memory as well */ +}; + +struct uci_element +{ + struct uci_list list; + enum uci_type type; + char *name; +}; + +struct uci_backend +{ + struct uci_element e; + char **(*list_configs)(struct uci_context *ctx); + struct uci_package *(*load)(struct uci_context *ctx, const char *name); + void (*commit)(struct uci_context *ctx, struct uci_package **p, bool overwrite); + + /* private: */ + const void *ptr; + void *priv; +}; + +struct uci_context +{ + /* list of config packages */ + struct uci_list root; + + /* parser context, use for error handling only */ + struct uci_parse_context *pctx; + + /* backend for import and export */ + struct uci_backend *backend; + struct uci_list backends; + + /* uci runtime flags */ + enum uci_flags flags; + + char *confdir; + char *savedir; + + /* search path for history files */ + struct uci_list history_path; + + /* private: */ + int err; + const char *func; + jmp_buf trap; + bool internal, nested; + char *buf; + int bufsz; +}; + +struct uci_package +{ + struct uci_element e; + struct uci_list sections; + struct uci_context *ctx; + bool has_history; + char *path; + + /* private: */ + struct uci_backend *backend; + void *priv; + int n_section; + struct uci_list history; + struct uci_list saved_history; +}; + +struct uci_section +{ + struct uci_element e; + struct uci_list options; + struct uci_package *package; + bool anonymous; + char *type; +}; + +struct uci_option +{ + struct uci_element e; + struct uci_section *section; + enum uci_option_type type; + union { + struct uci_list list; + char *string; + } v; +}; + +enum uci_command { + UCI_CMD_ADD, + UCI_CMD_REMOVE, + UCI_CMD_CHANGE, + UCI_CMD_RENAME, + UCI_CMD_LIST_ADD, +}; + +struct uci_history +{ + struct uci_element e; + enum uci_command cmd; + char *section; + char *value; +}; + +struct uci_ptr +{ + enum uci_type target; + enum { + UCI_LOOKUP_DONE = (1 << 0), + UCI_LOOKUP_COMPLETE = (1 << 1), + UCI_LOOKUP_EXTENDED = (1 << 2), + } flags; + + struct uci_package *p; + struct uci_section *s; + struct uci_option *o; + struct uci_element *last; + + const char *package; + const char *section; + const char *option; + const char *value; +}; + + +/* linked list handling */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + */ +#define container_of(ptr, type, member) \ + ((type *) ((char *)ptr - offsetof(type,member))) + + +/** + * uci_list_entry: casts an uci_list pointer to the containing struct. + * @_type: config, section or option + * @_ptr: pointer to the uci_list struct + */ +#define list_to_element(ptr) \ + container_of(ptr, struct uci_element, list) + +/** + * uci_foreach_entry: loop through a list of uci elements + * @_list: pointer to the uci_list struct + * @_ptr: iteration variable, struct uci_element + * + * use like a for loop, e.g: + * uci_foreach(&list, p) { + * ... + * } + */ +#define uci_foreach_element(_list, _ptr) \ + for(_ptr = list_to_element((_list)->next); \ + &_ptr->list != (_list); \ + _ptr = list_to_element(_ptr->list.next)) + +/** + * uci_foreach_entry_safe: like uci_foreach_safe, but safe for deletion + * @_list: pointer to the uci_list struct + * @_tmp: temporary variable, struct uci_element * + * @_ptr: iteration variable, struct uci_element * + * + * use like a for loop, e.g: + * uci_foreach(&list, p) { + * ... + * } + */ +#define uci_foreach_element_safe(_list, _tmp, _ptr) \ + for(_ptr = list_to_element((_list)->next), \ + _tmp = list_to_element(_ptr->list.next); \ + &_ptr->list != (_list); \ + _ptr = _tmp, _tmp = list_to_element(_ptr->list.next)) + +/** + * uci_list_empty: returns true if a list is empty + * @list: list head + */ +#define uci_list_empty(list) ((list)->next == (list)) + +/* wrappers for dynamic type handling */ +#define uci_type_backend UCI_TYPE_BACKEND +#define uci_type_history UCI_TYPE_HISTORY +#define uci_type_package UCI_TYPE_PACKAGE +#define uci_type_section UCI_TYPE_SECTION +#define uci_type_option UCI_TYPE_OPTION + +/* element typecasting */ +#ifdef UCI_DEBUG_TYPECAST +static const char *uci_typestr[] = { + [uci_type_backend] = "backend", + [uci_type_history] = "history", + [uci_type_package] = "package", + [uci_type_section] = "section", + [uci_type_option] = "option", +}; + +static void uci_typecast_error(int from, int to) +{ + fprintf(stderr, "Invalid typecast from '%s' to '%s'\n", uci_typestr[from], uci_typestr[to]); +} + +#define BUILD_CAST(_type) \ + static inline struct uci_ ## _type *uci_to_ ## _type (struct uci_element *e) \ + { \ + if (e->type != uci_type_ ## _type) { \ + uci_typecast_error(e->type, uci_type_ ## _type); \ + } \ + return (struct uci_ ## _type *) e; \ + } + +BUILD_CAST(backend) +BUILD_CAST(history) +BUILD_CAST(package) +BUILD_CAST(section) +BUILD_CAST(option) + +#else +#define uci_to_backend(ptr) container_of(ptr, struct uci_backend, e) +#define uci_to_history(ptr) container_of(ptr, struct uci_history, e) +#define uci_to_package(ptr) container_of(ptr, struct uci_package, e) +#define uci_to_section(ptr) container_of(ptr, struct uci_section, e) +#define uci_to_option(ptr) container_of(ptr, struct uci_option, e) +#endif + +/** + * uci_alloc_element: allocate a generic uci_element, reserve a buffer and typecast + * @ctx: uci context + * @type: {package,section,option} + * @name: string containing the name of the element + * @datasize: additional buffer size to reserve at the end of the struct + */ +#define uci_alloc_element(ctx, type, name, datasize) \ + uci_to_ ## type (uci_alloc_generic(ctx, uci_type_ ## type, name, sizeof(struct uci_ ## type) + datasize)) + +#define uci_dataptr(ptr) \ + (((char *) ptr) + sizeof(*ptr)) + +#endif diff --git a/libs/lucittpd/src/include/uci_config.h b/libs/lucittpd/src/include/uci_config.h new file mode 100644 index 0000000000..0dd76cc399 --- /dev/null +++ b/libs/lucittpd/src/include/uci_config.h @@ -0,0 +1,3 @@ +#define UCI_PLUGIN_SUPPORT 1 +#undef UCI_DEBUG +#undef UCI_DEBUG_TYPECAST diff --git a/libs/lucittpd/src/lib/log.c b/libs/lucittpd/src/lib/log.c new file mode 100644 index 0000000000..b6ce8c28e6 --- /dev/null +++ b/libs/lucittpd/src/lib/log.c @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Provided by fon.com + * Copyright (C) 2008 John Crispin + */ + +#include +#include +#include + +static int daemonize = 0; + +void log_start(int daemon) +{ + daemonize = daemon; + openlog("lucittpd", 0, 0); +} + +void log_printf(char *fmt, ...) +{ + char p[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(p, 256, fmt, ap); + va_end(ap); + + if(daemonize) + syslog(10, p); + else + printf(p); +} diff --git a/libs/lucittpd/src/lib/luaplugin.c b/libs/lucittpd/src/lib/luaplugin.c new file mode 100644 index 0000000000..6a0e1caad7 --- /dev/null +++ b/libs/lucittpd/src/lib/luaplugin.c @@ -0,0 +1,383 @@ +/* + * luaplugin - fast lua plugin indexing + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE /* XXX: portability hack for timestamp */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define DEBUG 1 +#ifdef DEBUG +#define DPRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DPRINTF(...) do {} while (0) +#endif + +/** + * list_for_each_offset - iterate over a list, start with the provided pointer + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_offset(pos, head, offset) \ + for (pos = (offset)->next; pos != (offset); \ + pos = ((pos->next == (head)) && ((offset) != (head)) ? (head)->next : pos->next)) + +static char pbuf[PATH_MAX]; +static void load_module(struct luaplugin_ctx *ctx, struct luaplugin_entry *e); + +static struct luaplugin_entry * +find_entry(struct luaplugin_ctx *ctx, const char *name, bool modname) +{ + struct list_head *p; + + if (!ctx->last) + ctx->last = &ctx->entries; + + list_for_each_offset(p, &ctx->entries, ctx->last) { + struct luaplugin_entry *e; + const char *cmp; + + e = container_of(p, struct luaplugin_entry, list); + if (modname) + cmp = e->module; + else + cmp = e->name; + + if (!strcmp(cmp, name)) + return e; + } + return NULL; +} + +static struct luaplugin_entry * +new_entry(struct luaplugin_ctx *ctx, const char *name, const char *modname) +{ + struct luaplugin_entry *e; + char *c; + + e = malloc(sizeof(struct luaplugin_entry)); + if (!e) + goto error; + + memset(e, 0, sizeof(struct luaplugin_entry)); + INIT_LIST_HEAD(&e->list); + e->ctx = ctx; + e->loaded = false; + + e->name = strdup(name); + if (!e->name) + goto error1; + + e->module = strdup(modname); + if (!e->module) + goto error2; + + /* strip filename extension */ + c = strrchr(e->module, '.'); + if (c) + *c = 0; + + /* lua namespace: replace / with . */ + c = e->module; + while ((c = strchr(c, '/')) != NULL) { + *c = '.'; + } + return e; + +error2: + free(e->name); +error1: + free(e); +error: + return NULL; +} + +static const char *module_loader = +"loader = function (newgt, filename)\n" +" setmetatable(newgt, { __index = _G })\n" +" local f = loadfile(filename)\n" +" if (type(f) == \"function\") then\n" +" setfenv(f, newgt)\n" +" f()\n" +" else\n" +" error(f)\n" +" end\n" +"end\n"; + +static void +access_plugin_table (lua_State *L, const char *modname, bool set) +{ + const char *e; + + lua_pushvalue(L, LUA_GLOBALSINDEX); + do { + bool _set = true; + + e = strchr(modname, '.'); + if (e == NULL) { + e = modname + strlen(modname); + _set = set; + } + + lua_pushlstring(L, modname, e - modname); + lua_rawget(L, -2); + if (lua_isnil(L, -1) || + /* no such field or last field */ + (lua_istable(L, -1) && (*e != '.'))) { + lua_pop(L, 1); /* remove this result */ + + if (_set) { + if (*e != '.') + lua_pushvalue(L, -2); /* use table from given index */ + else + lua_createtable(L, 0, 1); /* new table for field */ + } + + lua_pushlstring(L, modname, e - modname); + + if (_set) { + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } else { + lua_gettable(L, -2); + } + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2 + !!set); /* remove table and values */ + return; + } + lua_remove(L, -2); /* remove previous table */ + modname = e + 1; + } while (*e == '.'); + if (set) + lua_pop(L, 2); +} + + +static void +load_module(struct luaplugin_ctx *ctx, struct luaplugin_entry *e) +{ + lua_State *L = ctx->L; + int ret; + + /* grab the loader wrapper function */ + ret = luaL_dostring(L, module_loader); + if (ret) + return; + + lua_getglobal(L, "loader"); + lua_pushnil(L); + lua_setglobal(L, "loader"); + + e->loaded = true; + e->reload = false; + + /* new environment table for function call */ + lua_newtable(L); + + /* register the table globally */ + lua_pushvalue(L, -1); + access_plugin_table(L, e->module, true); + + lua_pushstring(L, e->name); + + if (lua_pcall(L, 2, 0, 0) != 0) { + const char *err = "unknown error"; + + if (lua_isstring(L, -1)) + err = lua_tostring(L, -1); + + fprintf(stderr, err); + } +} + +static void +free_entry(struct luaplugin_ctx *ctx, struct luaplugin_entry *e) +{ + lua_State *L = ctx->L; + + if (e->loaded && L) { + /* allow the gc to free the module */ + lua_pushnil(L); + access_plugin_table(L, e->module, true); + } + list_del(&e->list); + free(e->name); + free(e->module); + free(e); +} + +static void +__luaplugin_scan(struct luaplugin_ctx *ctx, int base_len, int rec) +{ + int gl_flags = GLOB_NOESCAPE | GLOB_NOSORT | GLOB_MARK; + glob_t gl; + int i; + + strncpy(pbuf + base_len, "*.lua", PATH_MAX - base_len); + if (glob(pbuf, gl_flags, NULL, &gl) < 0) { + globfree(&gl); + return; + } + + for (i = 0; i < gl.gl_pathc; i++) { + const char *entry = gl.gl_pathv[i]; + struct luaplugin_entry *e; + struct stat st; + int elen; + + elen = strlen(entry); + + /* should not happen */ + if ((elen <= base_len) || (strncmp(entry, pbuf, base_len) != 0)) { + fprintf(stderr, "[%s] sanity check failed in %s(%d)!\n", __FILE__, __func__, __LINE__); + continue; + } + + /* descend into subdirectories */ + if (entry[elen - 1] == '/') { + strncpy(pbuf + base_len, entry + base_len, PATH_MAX - base_len); + __luaplugin_scan(ctx, base_len, rec + 1); + pbuf[base_len] = '\0'; + continue; + } + + if (stat(gl.gl_pathv[i], &st)) + continue; + + if ((st.st_mode & S_IFMT) != S_IFREG) + continue; + + e = find_entry(ctx, entry + base_len, false); + if (!e) { + e = new_entry(ctx, entry, entry + base_len); + list_add_tail(&e->list, &ctx->entries); + } + if (!e) + continue; + + e->checked = ctx->checked; + e->reload = (e->timestamp < st.st_mtime); + e->timestamp = st.st_mtime; + } + globfree(&gl); +} + +int +luaplugin_call(struct luaplugin_entry *e, int narg) +{ + struct luaplugin_ctx *ctx = e->ctx; + lua_State *L = ctx->L; + const char *func; + int ret; + + func = luaL_checkstring(L, -1 - narg); + + /* grab a reference to the plugin's table */ + access_plugin_table(L, e->module, false); + lua_getfield(L, -1, func); + if (!lua_isfunction(L, -1)) { + lua_pop(L, narg + 1); + ret = -ENOENT; + goto done; + } + + /* replace function name with a ref to the function */ + lua_replace(L, -3 - narg); + + /* pop the table */ + lua_pop(L, 1); + ret = lua_pcall(L, narg, 0, 0); + + if (ret != 0) { + fprintf(stderr, lua_tostring(L, -1)); + } + +done: + return ret; +} + +void +luaplugin_scan(struct luaplugin_ctx *ctx) +{ + struct list_head *tmp, *p; + + sprintf(pbuf, "%s/", ctx->path); + + ctx->checked++; + __luaplugin_scan(ctx, strlen(pbuf), 0); + + /* expire old entries */ + list_for_each_safe(p, tmp, &ctx->entries) { + struct luaplugin_entry *e = container_of(p, struct luaplugin_entry, list); + if (e->checked < ctx->checked) + free_entry(ctx, e); + else if (e->reload) + load_module(ctx, e); + } +} + +int +luaplugin_init(struct luaplugin_ctx *ctx, const char *path) +{ + memset(ctx, 0, sizeof(struct luaplugin_ctx)); + INIT_LIST_HEAD(&ctx->entries); + ctx->path = path; + + ctx->L = luaL_newstate(); + if (!ctx->L) + return -ENOMEM; + + luaL_openlibs(ctx->L); + + /* disable the module functionality, a plugin is restricted to its own environment */ + /* + lua_pushcfunction(ctx->L, luaplugin_module); + lua_setfield(ctx->L, LUA_GLOBALSINDEX, "module"); + */ + + return 0; +} + +void +luaplugin_done(struct luaplugin_ctx *ctx) +{ + struct list_head *p, *tmp; + + lua_close(ctx->L); + ctx->L = NULL; + + list_for_each_safe(p, tmp, &ctx->entries) { + struct luaplugin_entry *e; + e = container_of(p, struct luaplugin_entry, list); + free_entry(ctx, e); + } +} diff --git a/libs/lucittpd/src/lib/signal.c b/libs/lucittpd/src/lib/signal.c new file mode 100644 index 0000000000..2b11f47cbb --- /dev/null +++ b/libs/lucittpd/src/lib/signal.c @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Provided by fon.com + * Copyright (C) 2008 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +void handler_INT(int signo) +{ + log_printf("away we go\n"); + exit(0); +} + +void handler_CHLD(int signo) +{ + while(waitpid(-1, NULL, WNOHANG) > 0); +} + +void setup_signals(void) +{ + struct sigaction s1, s2, s3; + s1.sa_handler = handler_INT; + s1.sa_flags = 0; + sigaction(SIGINT, &s1, NULL); + s2.sa_handler = handler_INT; + s2.sa_flags = 0; + sigaction(SIGTERM, &s2, NULL); + s3.sa_handler = handler_CHLD; + s3.sa_flags = SA_RESTART; + sigaction(SIGCHLD, &s3, NULL); +} diff --git a/libs/lucittpd/src/lib/uci.c b/libs/lucittpd/src/lib/uci.c new file mode 100644 index 0000000000..33254ee5e2 --- /dev/null +++ b/libs/lucittpd/src/lib/uci.c @@ -0,0 +1,206 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2008 John Crispin + */ + +#include +#include + +#include +#include +#include +#include + +static struct uci_ptr ptr; +static struct uci_package *p = NULL; + +static inline int ucix_get_ptr(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t) +{ + memset(&ptr, 0, sizeof(ptr)); + ptr.package = p; + ptr.section = s; + ptr.option = o; + ptr.value = t; + return uci_lookup_ptr(ctx, &ptr, NULL, true); +} + +struct uci_context* ucix_init(const char *config_file) +{ + struct uci_context *ctx = uci_alloc_context(); + uci_add_history_path(ctx, "/var/state"); + uci_set_savedir(ctx, "/var/state/"); + if(uci_load(ctx, config_file, &p) != UCI_OK) + { + log_printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file); + return NULL; + } + return ctx; +} + +struct uci_context* ucix_init_path(const char *path, const char *config_file) +{ + struct uci_context *ctx = uci_alloc_context(); + if(path) + uci_set_confdir(ctx, path); + if(uci_load(ctx, config_file, NULL) != UCI_OK) + { + log_printf("%s/%s is missing or corrupt\n", ctx->savedir, config_file); + return NULL; + } + return ctx; +} + +void ucix_cleanup(struct uci_context *ctx) +{ + uci_free_context(ctx); +} + +void ucix_save(struct uci_context *ctx) +{ + uci_set_savedir(ctx, "/tmp/.uci"); + uci_save(ctx, p); +} + +void ucix_save_state(struct uci_context *ctx) +{ + uci_save(ctx, p); +} + +int ucix_get_option_list(struct uci_context *ctx, const char *p, + const char *s, const char *o, struct list_head *l) +{ + struct uci_element *e = NULL; + if(ucix_get_ptr(ctx, p, s, o, NULL)) + return 1; + if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) + return 1; + e = ptr.last; + switch (e->type) + { + case UCI_TYPE_OPTION: + switch(ptr.o->type) { + case UCI_TYPE_LIST: + uci_foreach_element(&ptr.o->v.list, e) + { + struct ucilist *ul = malloc(sizeof(struct ucilist)); + ul->val = strdup((e->name)?(e->name):("")); + INIT_LIST_HEAD(&ul->list); + list_add(&ul->list, l); + } + break; + default: + break; + } + break; + default: + return 1; + } + + return 0; +} + +const char* ucix_get_option(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + struct uci_element *e = NULL; + const char *value = NULL; + if(ucix_get_ptr(ctx, p, s, o, NULL)) + return NULL; + if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) + return NULL; + e = ptr.last; + switch (e->type) + { + case UCI_TYPE_SECTION: + value = uci_to_section(e)->type; + break; + case UCI_TYPE_OPTION: + switch(ptr.o->type) { + case UCI_TYPE_STRING: + value = ptr.o->v.string; + break; + default: + value = NULL; + break; + } + break; + default: + return 0; + } + + return value; +} + +int ucix_get_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int def) +{ + const char *tmp = ucix_get_option(ctx, p, s, o); + int ret = def; + + if (tmp) + ret = atoi(tmp); + return ret; +} + +void ucix_add_section(struct uci_context *ctx, const char *p, const char *s, const char *t) +{ + if(ucix_get_ptr(ctx, p, s, NULL, t)) + return; + uci_set(ctx, &ptr); +} + +void ucix_add_option(struct uci_context *ctx, const char *p, const char *s, const char *o, const char *t) +{ + if(ucix_get_ptr(ctx, p, s, o, (t)?(t):(""))) + return; + uci_set(ctx, &ptr); +} + +void ucix_add_option_int(struct uci_context *ctx, const char *p, const char *s, const char *o, int t) +{ + char tmp[64]; + snprintf(tmp, 64, "%d", t); + ucix_add_option(ctx, p, s, o, tmp); +} + +void ucix_del(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + if(!ucix_get_ptr(ctx, p, s, o, NULL)) + uci_delete(ctx, &ptr); +} + +void ucix_revert(struct uci_context *ctx, const char *p, const char *s, const char *o) +{ + if(!ucix_get_ptr(ctx, p, s, o, NULL)) + uci_revert(ctx, &ptr); +} + +void ucix_for_each_section_type(struct uci_context *ctx, + const char *p, const char *t, + void (*cb)(const char*, void*), void *priv) +{ + struct uci_element *e; + if(ucix_get_ptr(ctx, p, NULL, NULL, NULL)) + return; + uci_foreach_element(&ptr.p->sections, e) + if (!strcmp(t, uci_to_section(e)->type)) + cb(e->name, priv); +} + +int ucix_commit(struct uci_context *ctx, const char *p) +{ + if(ucix_get_ptr(ctx, p, NULL, NULL, NULL)) + return 1; + return uci_commit(ctx, &ptr.p, false); +} diff --git a/libs/lucittpd/src/main.c b/libs/lucittpd/src/main.c new file mode 100644 index 0000000000..3ee5506a8a --- /dev/null +++ b/libs/lucittpd/src/main.c @@ -0,0 +1,333 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2008 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef __UCLIBC__ +#include +#endif + +#define BACKLOG 10 + +static int port = 0; +static const char *plugin_path = NULL; +static struct luaplugin_ctx ctx; +static struct luaplugin_entry *e; +static struct timeval timeout; + +static void load_config(void) +{ + timeout.tv_usec = 0; + + static struct uci_context* uci = 0; + uci = ucix_init("lucittpd"); + if(uci) + { + plugin_path = ucix_get_option(uci, "lucittpd", "lucittpd", "path"); + port = ucix_get_option_int(uci, "lucittpd", "lucittpd", "port", 80); + timeout.tv_sec = ucix_get_option_int(uci, "lucittpd", "lucittpd", "timeout", 90); + } else { + port = 8080; + timeout.tv_sec = 90; + } + if(!plugin_path) + plugin_path = strdup("/usr/lib/lucittpd/plugins/"); + + // ToDo: Check why below command segfaults in uci_free_context + //ucix_cleanup(uci); +} + +static int webuci_read(lua_State *L) +{ + int len = luaL_checkinteger(L, 1); + if (len <= 0) { + return luaL_argerror(L, 1, "too low"); + } + + char *buffer = malloc(len); + if (!buffer) { + return luaL_error(L, "malloc() failed"); + } + + int sockfd = lua_tointeger(L, lua_upvalueindex(1)); + + len = read(sockfd, buffer, len); + if (len > 0) { + lua_pushlstring(L, buffer, len); + free(buffer); + } else { + free(buffer); + lua_pushnil(L); + lua_pushinteger(L, (len == 0) ? 0 : errno); + return 2; + } + + /* fprintf(stderr, "%s:%s[%d] %d %d\n", __FILE__, __func__, __LINE__, sockfd, len); */ + + return 1; +} + +static int webuci_close(lua_State *L) +{ + int sockfd = lua_tointeger(L, lua_upvalueindex(1)); + int result = shutdown(sockfd, SHUT_RDWR); + close(sockfd); + /*log_printf("%s:%s[%d] %d %d\n", __FILE__, __func__, __LINE__, sockfd, result);*/ + + if (result < 0) { + lua_pushnil(L); + lua_pushinteger(L, errno); + return 2; + } else { + lua_pushboolean(L, 1); + return 1; + } +} + +static int webuci_write(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TSTRING); + + size_t len; + const char *data = lua_tolstring(L, 1, &len); + int sockfd = lua_tointeger(L, lua_upvalueindex(1)); + + len = send(sockfd, data, len, 0); + /*log_printf("%s:%s[%d] %d %d - %s\n", __FILE__, __func__, __LINE__, sockfd, len, data);*/ + if (len < 0) { + lua_pushnil(L); + lua_pushinteger(L, errno); + return 2; + } else { + lua_pushinteger(L, len); + return 1; + } +} + +static int webuci_sendfile(lua_State *L) +{ + FILE **fp = (FILE **)luaL_checkudata(L, 1, LUA_FILEHANDLE); + if (*fp == NULL) { + return luaL_error(L, "attempt to use a closed file"); + } + + off_t offset = luaL_checkinteger(L, 2); + size_t size = luaL_checkinteger(L, 3); + + int sockfd = lua_tointeger(L, lua_upvalueindex(1)); + + int cork = 1; + setsockopt(sockfd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); + +#ifdef __UCLIBC__ + // uclibc is teh sux, it does not implement sendfile correctly + char tmp[1024]; + size_t c, toread = size, oldpos = ftell(*fp); + + fseek(*fp, offset, SEEK_SET); + + while(toread > 0 && (c = fread(tmp, 1, (toread < 1024) ? toread : 1024, *fp)) > 0) + { + size += c; + toread -= c; + write(sockfd, tmp, c); + } + + fseek(*fp, oldpos, SEEK_SET); +#else + size = sendfile(sockfd, fileno(*fp), &offset, size); + /*log_printf("%s:%s[%d] %d %d - %d\n", __FILE__, __func__, __LINE__, sockfd, fileno(*fp), size);*/ +#endif + + cork = 0; + setsockopt(sockfd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); + + if (size < 1) { + lua_pushnil(L); + lua_pushinteger(L, errno); + } else { + lua_pushinteger(L, size); + lua_pushinteger(L, offset); + } + + return 2; +} + + +static void load_luci(const char *plugindir) +{ + luaplugin_init(&ctx, plugindir); + luaplugin_scan(&ctx); + + list_for_each_entry(e, &ctx.entries, list) + { + lua_pushstring(ctx.L, "initialize"); + luaplugin_call(e, 0); + } + + list_for_each_entry(e, &ctx.entries, list) + { + lua_pushstring(ctx.L, "register"); + luaplugin_call(e, 0); + } + + list_for_each_entry(e, &ctx.entries, list) + { + lua_pushstring(ctx.L, "filter"); + luaplugin_call(e, 0); + } +} + +static void run_luci(int sockfd) +{ + lua_pushinteger(ctx.L, sockfd); + lua_pushcclosure(ctx.L, webuci_read, 1); + lua_setfield(ctx.L, LUA_GLOBALSINDEX, "webuci_read"); + + lua_pushinteger(ctx.L, sockfd); + lua_pushcclosure(ctx.L, webuci_write, 1); + lua_setfield(ctx.L, LUA_GLOBALSINDEX, "webuci_write"); + + lua_pushinteger(ctx.L, sockfd); + lua_pushcclosure(ctx.L, webuci_close, 1); + lua_setfield(ctx.L, LUA_GLOBALSINDEX, "webuci_close"); + + lua_pushinteger(ctx.L, sockfd); + lua_pushcclosure(ctx.L, webuci_sendfile, 1); + lua_setfield(ctx.L, LUA_GLOBALSINDEX, "webuci_sendfile"); + + list_for_each_entry(e, &ctx.entries, list) + { + lua_pushstring(ctx.L, "accept"); + luaplugin_call(e, 0); + } +} + +static void cleanup_luci(void) +{ + luaplugin_done(&ctx); +} + +int main(int argc, char **argv) +{ + int sockfd, new_fd; + struct sockaddr_storage their_addr; + socklen_t sin_size; + int yes = 1; + struct sockaddr_in myaddr; + + log_start(1); + + load_config(); + + setup_signals(); + + /* used by sdk to override plugin dir */ + if(argc != 2) + { + load_luci(plugin_path); + } else { + load_luci(argv[1]); + port = 8080; + } + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(port); + //inet_pton(AF_INET, "63.161.169.137", &myaddr.sin_addr.s_addr); + myaddr.sin_addr.s_addr = INADDR_ANY; + + sockfd = socket(PF_INET, SOCK_STREAM, 0); + + if(sockfd == -1) + { + perror("server: socket"); + exit(1); + } + + if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + { + perror("setsockopt"); + exit(1); + } + + if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) + { + close(sockfd); + perror("server: bind"); + exit(1); + } + + if(listen(sockfd, BACKLOG) == -1) + { + perror("listen"); + exit(1); + } + + /*log_printf("server: waiting for connections...\n");*/ + + while(1) + { + sin_size = sizeof their_addr; + new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); + if(new_fd == -1) + { + perror("accept"); + continue; + } + + /*inet_ntop(their_addr.ss_family, + (void*)&((struct sockaddr_in*)&their_addr)->sin_addr, s, sizeof s); + log_printf("server: got connection from %s\n", s);*/ + + if(!fork()) + { + /* child */ + close(sockfd); + + setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + + run_luci(new_fd); + cleanup_luci(); + close(new_fd); + + exit(0); + } + close(new_fd); + } + + return 0; +} diff --git a/libs/sgi-luci/hostfiles/usr/lib/lucittpd/plugins/luci-webui.lua b/libs/sgi-luci/hostfiles/usr/lib/lucittpd/plugins/luci-webui.lua new file mode 100644 index 0000000000..073e567c0a --- /dev/null +++ b/libs/sgi-luci/hostfiles/usr/lib/lucittpd/plugins/luci-webui.lua @@ -0,0 +1,29 @@ +function initialize() + pcall(function() + local SYSROOT = os.getenv("LUCI_SYSROOT") + require "uci" + require "luci.model.uci".cursor = function(config, save) + return uci.cursor(config or SYSROOT .. "/etc/config", save or SYSROOT .. "/tmp/.uci") + end + + local x = require "luci.uvl".UVL.__init__ + require "luci.uvl".UVL.__init__ = function(self, schemedir) + x(self, schemedir or SYSROOT .. "/lib/uci/schema") + end + + require("luci.sys") + luci.sys.user.checkpasswd = function() return true end + + require "luci.dispatcher" + require "luci.uvl" + require "luci.cbi" + require "luci.template" + require "luci.json" + end) +end + +-- Initialize LuCI +function register() + local lucihnd = require "luci.ttpd.handler.luci" + httpd.server:get_default_vhost():set_handler("/luci", lucihnd.Luci()) +end \ No newline at end of file diff --git a/libs/sgi-luci/luasrc/ttpd/handler/luci.lua b/libs/sgi-luci/luasrc/ttpd/handler/luci.lua new file mode 100644 index 0000000000..eb60625211 --- /dev/null +++ b/libs/sgi-luci/luasrc/ttpd/handler/luci.lua @@ -0,0 +1,92 @@ +--[[ + +HTTP server implementation for LuCI - luci handler +(c) 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +]]-- +local dsp = require "luci.dispatcher" +local util = require "luci.util" +local http = require "luci.http" +local ltn12 = require "luci.ltn12" +local mod = require "luci.ttpd.module" +local table = require "table" +local coroutine = require "coroutine" + +module "luci.ttpd.handler.luci" + +Luci = util.class(mod.Handler) +Response = mod.Response + +function Luci.__init__(self, limit) + mod.Handler.__init__(self) +end + +function Luci.handle_head(self, ...) + return (self:handle_get(...)) +end + +function Luci.handle_post(self, ...) + return self:handle_get(...) +end + +function Luci.handle_get(self, request, sourcein, sinkerr) + local r = http.Request( + request.env, + sourcein, + sinkerr + ) + + local res, id, data1, data2 = true, 0, nil, nil + local headers = {} + local status = 200 + local active = true + + local x = coroutine.create(dsp.httpdispatch) + while not id or id < 3 do + res, id, data1, data2 = coroutine.resume(x, r) + + if not res then + status = 500 + headers["Content-Type"] = "text/plain" + local err = {id} + return Response( status, headers ), function() return table.remove(err) end + end + + if id == 1 then + status = data1 + elseif id == 2 then + headers[data1] = data2 + end + end + + local function iter() + local res, id, data = coroutine.resume(x) + if not res then + return nil, id + elseif not id or not active then + return true + elseif id == 5 then + active = false + + while (coroutine.resume(x)) do + end + + return nil + elseif id == 4 then + return data + end + if coroutine.status(x) == "dead" then + return nil + end + end + + return Response(status, headers), iter +end diff --git a/libs/sgi-luci/root/etc/init.d/luci-httpd b/libs/sgi-luci/root/etc/init.d/luci-httpd deleted file mode 100755 index ef61d7bacb..0000000000 --- a/libs/sgi-luci/root/etc/init.d/luci-httpd +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh /etc/rc.common -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/bin/luci-httpd -NAME=luci-httpd -DESC="HTTP server" -START=49 - -test -x $DAEMON || exit 0 - -set -e - -start() { - echo -n "Starting $DESC: $NAME" - start-stop-daemon -S -b -q -x $DAEMON - echo "." -} - -stop() { - echo -n "Stopping $DESC: $NAME" - start-stop-daemon -K -q -x $DAEMON - echo "." -} diff --git a/libs/sgi-luci/root/usr/bin/luci-httpd b/libs/sgi-luci/root/usr/bin/luci-httpd deleted file mode 100755 index 091e38b21b..0000000000 --- a/libs/sgi-luci/root/usr/bin/luci-httpd +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/lua -require("luci.httpd") -require("luci.httpd.server") -require("luci.httpd.handler.file") -require("luci.httpd.handler.luci") - -DOCROOT = "/www" -PORT = 8080 - -collectgarbage("setpause", 150) - -serversocket = luci.httpd.Socket("0.0.0.0", PORT) - - -server = luci.httpd.server.Server() -vhost = luci.httpd.server.VHost() - -server:set_default_vhost(vhost) - - -filehandler = luci.httpd.handler.file.Simple(DOCROOT) -vhost:set_default_handler(filehandler) - -lucihandler = luci.httpd.handler.luci.Luci() -vhost:set_handler("/luci", lucihandler) - -io.stderr:write("Starting LuCI HTTPD on port " .. PORT .. "...\n") -io.stderr:write("Point your browser to http://localhost:" .. PORT .. "/luci\n") - -luci.httpd.register(serversocket, server:create_daemon_handlers()) -luci.httpd.run() diff --git a/libs/sgi-luci/root/usr/lib/lucittpd/plugins/luci-webui.lua b/libs/sgi-luci/root/usr/lib/lucittpd/plugins/luci-webui.lua new file mode 100644 index 0000000000..1204667892 --- /dev/null +++ b/libs/sgi-luci/root/usr/lib/lucittpd/plugins/luci-webui.lua @@ -0,0 +1,17 @@ +-- Initialize LuCI +function initialize() + pcall(function() + require "luci.dispatcher" + require "luci.uvl" + require "luci.cbi" + require "luci.template" + require "luci.json" + end) +end + +-- Register luci +function register() + local lucihnd = require "luci.ttpd.handler.luci".Luci() + httpd.server:get_default_vhost():set_handler("/luci", lucihnd) + httpd.server:get_default_vhost():set_handler("/cgi-bin/luci", lucihnd) +end diff --git a/libs/uvldoc/Makefile b/libs/uvldoc/Makefile new file mode 100644 index 0000000000..81a96f6a83 --- /dev/null +++ b/libs/uvldoc/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/footer.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/footer.xml new file mode 100644 index 0000000000..4b974693b9 --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/footer.xml @@ -0,0 +1,11 @@ + +
+
+generated on <%=require "os".date("%c")%> with LuCI UVLDoc - written by Steven Barth and Jo-Philipp Wich +
+ + +
 
+ + + \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/header.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/header.xml new file mode 100644 index 0000000000..f4a89b56d6 --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/header.xml @@ -0,0 +1,15 @@ + + + + + + + <% if title then %><%=title%> - <% end %>LuCI UVLDoc + + + + + +
diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/index.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/index.xml new file mode 100644 index 0000000000..a90500481b --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/index.xml @@ -0,0 +1,12 @@ +<%+header.xml%> +

UCI Documentation

+

Schemes

+ +<% for k, v in luci.util.kspairs(self.schemes) do %> + + + + +<% end %> +
<%=k%><%=self.schemes[k].title%>
+<%+footer.xml%> \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/menu.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/menu.xml new file mode 100644 index 0000000000..c0ad3da1b5 --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/menu.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/scheme.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/scheme.xml new file mode 100644 index 0000000000..f4fe22e75e --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/scheme.xml @@ -0,0 +1,16 @@ +<%- title = scheme -%> +<%+header.xml%> +

<%=scheme-%> +<%-if package.title then%> - <%=package.title%><%end%>

+
<%=package.description%>
+ +

Sections:

+ +<% for k, v in luci.util.kspairs(package.sections) do %> + + + + +<% end %> +
<%=k%><%=v.title%>
+<%+footer.xml%> \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/section.xml b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/section.xml new file mode 100644 index 0000000000..691fde4a18 --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/section.xml @@ -0,0 +1,198 @@ +<%- title = scheme .. "." .. type -%> +<%+header.xml%> +<% +local table = require "table" + +types = { + list = "List", + variable = "Variable", + lazylist = "Mixed", + enum = "Enumerator", + reference = "Reference" +} + +datatypes = { + boolean = "Boolean", + string = "String", + uint = "Unsigned Integer", + integer = "Integer", + float = "Real Number", + ipaddr = "IP-Address", + ip4addr = "IPv4-Address", + ip6addr = "IPv6-Address", + ip4prefix = "IPv4-Prefix", + ip6prefix = "IPv6-Prefix", + hostname = "Hostname", + host = "Host (Hostname or IP-Address)", + directory = "Filesystem path (to directory)", + file = "Filesystem path (to file)", + macaddr = "MAC-Address", + port = "Port", + portrange = "Single Port or Portrange (First-Last)" +} + +function _parse_ref( r ) + local k, v, h = r:match("([^.]+)%.([^.]+)%.([^.]+)") + if not k then + k, v = r:match("([^.]+)%.([^.]+)") + end + if k then + if h then + return self:_variable_target(k, v, h), true + else + return self:_section_filename(k, v) + end + end +end + +function _parse_dep( r, c, s, o ) + local ref = { } + local vars = { + config = c, + section = s, + option = o + } + + for v in r:gmatch("[^.]+") do + ref[#ref+1] = (v:gsub( "%$(.+)", vars )) + end + + if #ref < 2 then + table.insert(ref, 1, s or '$section') + end + if #ref < 3 then + table.insert(ref, 1, c or '$config') + end + + return self:_variable_target(unpack(ref)) +end + +%> + +

<%=scheme-%> +<%-if package.title then%> - <%=package.title%><%end%>

+

<%=type-%> +<%-if section.title then%> - <%=section.title%><%end%>

+
<%=section.description%>
+ +

Attributes:

+
    +<%- +if section.required then %> +
  • required: A section of this type is required.
  • +<% end +if section.unique then %> +
  • unique: There can be only one section of this type.
  • +<%- else -%> +
  • multiple: There can be more than one section of this type.
  • +<% end +if section.dynamic then %> +
  • dynamic: Sections of this type may contain user-defined options.
  • +<% end +if section.named then %> +
  • named: Sections of this type require a name.
  • +<% end -%> +
+ +<% if section.depends then %> +

Requirements (one of):

+
    + <% for i, d in ipairs(section.depends) do + local nf = false%> +
  • + <% for k2, v in luci.util.kspairs(d) do + local t = _parse_dep(k2, scheme, type) + %> + <% if nf then %>and<% end %> + <%if t then%><%end%><%=k2%><%if t then%><%end%><%if v~=true then%>=<%=v%><%end%> + <% nf = true + end %> +
  • + <% end %> +
+<% end %> + +

Variable Overview:

+ +<% for k, v in luci.util.kspairs(package.variables[type]) do +if v.required then%> + + + + +<% end end +for k, v in luci.util.kspairs(package.variables[type]) do +if not v.required then%> + + + + +<% end end %> +
<%=k%><%=v.title%>
<%=k%><%=v.title%>
+ +

Options:

+<%- +for i=0, 1 do +for k, v in luci.util.kspairs(package.variables[type]) do +if (i==0) == v.required then +%> +
+
+ +

<%=k-%> + <%-if v.title then%> - <%=v.title%><%end%>

+
+
<%=v.description%>
+
Attributes:
+
    + <% if v.required then %> +
  • required
  • + <% end %> +
  • Type: <%=types[v.type] or v.type%>
  • +
  • Datatype: <%=datatypes[v.datatype] or v.datatype%>
  • + <% if v.multival then %> +
  • multiple values: space-separated
  • + <% end %> +
+ <% if v.depends then %> +
Dependencies (one of):
+
    + <% for i, d in ipairs(v.depends) do + local nf = false %> +
  • + <% for k2, v in luci.util.kspairs(d) do + local t = _parse_dep(k2, scheme, type, k) + %> + <% if nf then %>and<% end %> + <%if t then%><%end%><%=k2%><%if t then%><%end%><%if v~=true then%>=<%=v%><%end%> + <% nf = true + end %> +
  • + <% end %> +
+ <% end %> + <% if v.type == "enum" then %> +
Possible Values:
+
    + <% for k, d in pairs(v.values) do %> +
  • <%=k%><%if d then%> (<%=d%>)<%end%>
  • + <% end %> +
+ <% elseif v.type == "reference" then %> +
Value references:
+
    + <% for k, d in ipairs(v.valueof) do %> +
  • + <% local t, x = _parse_ref(d) + if t then %><%=x and "Value of" or "Section of type"%> <% end %> + <%=d%> + <% if t then%><% end %> +
  • + <% end %> +
+ <% end %> +
+ +
+<% end end end -%> +<%+footer.xml%> \ No newline at end of file diff --git a/libs/uvldoc/luasrc/uvldoc/proto/xhtml/uvldoc.css b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/uvldoc.css new file mode 100644 index 0000000000..32a5e96b55 --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/proto/xhtml/uvldoc.css @@ -0,0 +1,135 @@ +body { + font-family: sans-serif; + font-size: 0.85em; + color: #101010; +} + +h1, h2, h3, h4, h5, h6 { + margin-top: 0; + font-weight: bold; +} + +h1 { + font-size: 1.5em; +} + +h2 { + font-size: 1.4em; +} + +h3 { + font-size: 1.2em; +} + +h4 { + font-size: 1.1em; +} + +h5 { + font-size: 1.0em; +} + +dfn { + font-weight: normal; + font-size: 0.9em; +} + +table { + border-collapse: collapse; +} + +tr, td, th { + border: 1px solid #e0e0ff; + padding: 3px; +} + +th { + background-color: #f0f0ff; + text-align: left; +} + + +hr { + border: none; + background-color: #cccccc; + height: 1px; +} + +ul, li { + margin-top: 0; +} + +div.clear { + clear: both; +} + +div.variable-declaration { + padding-left: 2em; +} + +div.variable-description { + margin-bottom: 1em; +} + +h3.section-variables { + margin-top: 2em; +} + +h4.variable-title { + margin-bottom: 0; +} + +div#menu { + float: left; + background-color: #f0f0ff; + margin: 0; + padding: 0; + border: 1px solid #e0e0ff; + width: 11.5em; +} + +#menu ul { + list-style-type: none; + margin-bottom: 0.5em; + padding-left: 1em; +} +#menu ul li { + margin-left: 0; + +} + +div.menu-title { + background-color: #e0e0ff; + color: #000000; + font-weight: bold; + padding: 2px; +} + +div#content { + margin-top: 0; + padding-top: 0; + margin-left: 12.5em; +} + +div#copy { + margin-top: 2.5em; + font-size: 0.7em; + text-align: center; + font-size: bold; +} + +a:link { + font-weight: bold; + color: #004080; + text-decoration: none; +} + +a:visited { + font-weight:bold; + color: #006699; + text-decoration: none; +} + +a:hover { + text-decoration:underline; +} diff --git a/libs/uvldoc/luasrc/uvldoc/renderer.lua b/libs/uvldoc/luasrc/uvldoc/renderer.lua new file mode 100644 index 0000000000..d005ba315f --- /dev/null +++ b/libs/uvldoc/luasrc/uvldoc/renderer.lua @@ -0,0 +1,124 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +local io = require "io" +local fs = require "luci.fs" +local uvl = require "luci.uvl" +local util = require "luci.util" +local ltn12 = require "luci.ltn12" +local template = require "luci.template" + +local ipairs, getfenv, pairs, require, unpack = ipairs, getfenv, pairs, require, unpack +local luci = luci + +module "luci.uvldoc.renderer" + + +Generator = util.class() + +function Generator.__init__(self, schemes, output, uvlpath) + self.names = schemes + self.output = output or "doc" + self.schemes = {} + self.uvl = uvl.UVL() + + self.extension = ".xml" + self.additionals = {"uvldoc.css"} + self.sourcedir = util.libpath() .. "/uvldoc/proto/xhtml/" +end + + +function Generator.make(self) + for i, scheme in ipairs(self.names) do + self.schemes[scheme] = self.uvl:get_scheme(scheme) + end + + fs.mkdir(self.output) + + for i, file in ipairs(self.additionals) do + fs.copy(self.sourcedir .. file, self.output .. "/" .. file) + end + + template.compiler_mode = "memory" + template.viewdir = self.sourcedir + template.context.viewns = { + include = function(name) template.Template(name):render(getfenv(2)) end, + pairs = pairs, + ipairs = ipairs, + unpack = unpack, + luci = luci, + require = require + } + + self:_make_index() + + for scheme, package in pairs(self.schemes) do + self:_make_package(scheme) + for type, section in pairs(package.sections) do + self:_make_section(scheme, type) + end + end +end + +function Generator._make_index(self) + local t = template.Template("index.xml") + local sink = ltn12.sink.file( + io.open(self.output .. "/" .. self:_index_filename(), "w") + ) + t:render({self = self, write = sink}) + sink() +end + +function Generator._make_package(self, scheme) + local t = template.Template("scheme.xml") + local sink = ltn12.sink.file( + io.open(self.output .. "/" .. self:_scheme_filename(scheme), "w") + ) + t:render({self = self, package = self.schemes[scheme], scheme = scheme, write = sink}) + sink() +end + +function Generator._make_section(self, scheme, section) + local t = template.Template("section.xml") + local sink = ltn12.sink.file( + io.open(self.output .. "/" .. self:_section_filename(scheme, section), "w") + ) + local pkg = self.schemes[scheme] + t:render({self = self, package = pkg, + scheme = scheme, type=section, section=pkg.sections[section], + write = sink}) + sink() +end + +function Generator._index_filename(self) + return "index%s" % self.extension +end + +function Generator._scheme_filename(self, scheme) + return "scheme.%s%s" % {scheme, self.extension} +end + +function Generator._section_filename(self, scheme, section) + if self.schemes[scheme] and self.schemes[scheme].sections[section] then + return "section.%s.%s%s" % {scheme, section, self.extension} + end +end + +function Generator._variable_target(self, scheme, section, variable) + if self.schemes[scheme] and self.schemes[scheme].variables[section] and + self.schemes[scheme].variables[section][variable] then + return "section.%s.%s%s#variable.%s" % {scheme, section, self.extension, variable} + end +end \ No newline at end of file diff --git a/modules/freifunk/luasrc/view/public_status/index.htm b/modules/freifunk/luasrc/view/public_status/index.htm deleted file mode 100644 index aa56834ba1..0000000000 --- a/modules/freifunk/luasrc/view/public_status/index.htm +++ /dev/null @@ -1,97 +0,0 @@ -<%# -LuCI - Lua Configuration Interface -Copyright 2008 Steven Barth -Copyright 2008 Jo-Philipp Wich - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -$Id$ - --%> -<%+header%> -

<%:status%>

-

<%:system%>

- -
- - - - - - - - - - - - - -
<%:system_type%>:<%=system%>
<%:cpu%>:<%=model%>
<%:ram%>:
<%:total%>/<%:cached%>/<%:buffers%>/<%:free%>
<%=memtotal%> / <%=memcached%> / <%=membuffers%> / <%=memfree%> KB
-
-
-
-
-
-
-

- -

<%:wifi%>

-
- - - - - - - - - - - - - -<%for k, v in pairs(luci.sys.wifi.getiwconfig()) do -%> - - - - - - - - - - - - - - - - -<%end%> -
<%:name%><%:protocol%><%:frequency%><%:power%><%:bitrate%><%:rts%><%:frag%><%:link%><%:signal%><%:noise%>
<%=k%><%=v[1]%><%=v.Frequency%><%=v["Tx-Power"]%><%=v["Bit Rate"]%><%=v["RTS thr"]%><%=v["Fragment thr"]%><%=v["Link Quality"]%><%=v["Signal level"]%><%=v["Noise level"]%>
ESSID: <%=v.ESSID%>BSSID: <%=(v.Cell or v["Access Point"])%>
-
-
-

<%:defroutes%>

-
- - - - - - -<% -for i, rt in pairs(routes) do -%> - - -<% end %> -
<%:gateway%><%:metric%><%:iface%>
<%=luci.ip.Hex(rt.Gateway, 32):string()%> -<%=rt.Metric%> -<%=rt.Iface%> -
-<%+footer%> \ No newline at end of file diff --git a/themes/freifunk-bno/Makefile b/themes/freifunk-bno/Makefile new file mode 100644 index 0000000000..81a96f6a83 --- /dev/null +++ b/themes/freifunk-bno/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/cascade.css b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/cascade.css new file mode 100644 index 0000000000..3507777572 --- /dev/null +++ b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/cascade.css @@ -0,0 +1,726 @@ +* { + margin: 0; + padding: 0; +} + +body { + background-color: #ffffff; + color: #ffffff; + font-family: Verdana, Arial, sans-serif; + font-size: 100%; + line-height: 100%; + background-image: url(images/main-back.png); + background-repeat: repeat-x; + background-position: left bottom; + } +#all { + margin: 0px; + padding: 0px; + min-height: 800px; +} + +code { + font-family: monospace; + white-space: pre; +} + +a:link, a:visited { + color:#000000; + font-weight:bold; + text-decoration:none; + } +a:hover { + color:#333333; + font-weight:bold; + } + +/* Custom*/ + #wrapper +{ + width: 95%; + color: #333333; + margin-left: auto; + margin-right: auto; +/* background-image: url(images/corner-left.gif); */ +/* background-repeat: no-repeat; */ +/* background-position: left bottom; */ + background-color: #FffdF4; + min-width: 710px; + min-height: 710px; +} +#main { + clear: both; + width: 100%; + margin: 0; + padding: 0; + color: #333333; +/* background-image: url(images/corner-right.gif); */ +/* background-repeat: no-repeat; */ +/* background-position: right bottom; */ + min-height: 710px; +} + +div#maincontent ul { + margin-left: 2em; +} + +.warning { + color: red !important; + font-weight: bold; +} + +.clear { + clear: both; + height: 1px; +} + +.hidden { + display: none; +} + +.error { + color: #ff0000; +} + +#header +{ + padding: 0px; + height: 100px; +} +#headerleft +{ + height: 100px; + background-color: #FFFfff; + background-image: url(images/header-left.gif); + background-repeat: no-repeat; + background-position: left top; +} +#headerright +{ + height: 100px; + background-color: #FFfffF; + + margin-left: 5px; + background-image: url(images/header-right.gif); + background-repeat: no-repeat; + background-position: right top; +} + +#headerback +{ + margin-right: 5px; + height: 100px; + background-color: #FFfffF; + background-image: url(images/header-back.gif); + background-repeat: repeat-x; + background-position: left top; +} +#schriftzug { + font-size : 1.5em; + text-align:left; + margin-bottom: 7px; + margin-top: 7px; + float:left; + width: 450px; +} + +#schriftzug a:hover{ + background-color:transparent; +} +#logo{ + margin-top: 5px; + float:right; + width: 115px; +} + +.pathbar { + display: none; +} + +.menubar { + width: 100%; + min-height: 1.8em; + background: #ffffff; + color: #000000; + border-top:0.4em solid #DC0067; +} + +.mainmenu { + float: left; + width: auto; + min-height: 1.8em; + background: #ffffff; + color: #000000; +} +.modemenu li { + border-top:0.3em solid #DC0067; + margin-left: 0.3em; + margin-top: -0.3em; +} +.mainmenu div { + float: left; + border-top:0.3em solid #DC0067; + margin-right: 0.3em; + margin-top: -0.3em; +} +.mainmenu div.preactive { + border-top: 0.3em solid #FFCB05; + margin-top: -0.2em; +} + +.mainmenu li { + white-space: nowrap; +} + +.mainmenu div ul { + display: none; + position: absolute; + background: #ffffff; + color: #000000; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #444444; + list-style-type: none; +} + +.mainmenu ul li:hover > ul, +.mainmenu div:hover > ul { + display: block; +} + +.mainmenu ul li > ul { + left: 100%; + margin-top: -1.8em; + border-width: 1px; +} + +.modemenu a, +.mainmenu a { + display: block; + padding: 0.2em; + color: #000000; + text-decoration: none; + font-size: 70%; + font-weight: bold; +} + + +.modemenu .active a { + color: #000000; + font-weight: bold; + border-top:0.3em solid #FFCB05; + margin-top: -0.2em; +} +.mainmenu .active a{ + color: #000000; + font-weight: bold; + border-top:0.2em solid #FFCB05; +} +.mainmenu li > span:active { + background-color: #FFE990; +} + +.mainmenu li:hover > span > a, +.mainmenu div:hover > a { +color: #ffffff; +background-color: #FFCB05; +} + + +.modemenu a:focus, +.mainmenu a:focus { + color: #000000; +} + +.mainmenu a:hover, +.modemenu a:hover { +color: #ffffff; +background-color: #FFCB05; +} + +.mainmenu div.preactive > a { + color: #DC0067; + font-weight: bold; +} +.mainmenu div.preactive > a:hover, +.mainmenu div.preactive > a:focus { + color: #ffffff; + font-weight: bold; +} + +.modemenu ul { + width: auto; + background: #000000; + color: #ffffff; + list-style-type: none; +} + +.modemenu li { + float: right; + +} + +#maincontent { + clear: both; + width: 98%; + margin: 0 auto; + padding: 0.5em; + background: #FFF4BE; + color: #000000; + font-size: 80%; + border-top:1px solid #D2A800; +} + +#maincontent h2 { + margin: 0.25em 0 0.5em 0; + font-size: 150%; + font-weight: normal; +} + +#maincontent h3 { + margin: 0.5em 0; + font-size: 120%; + font-weight: normal; + text-decoration: underline; +} + +#maincontent p { + margin-bottom: 1em; +} + +.cbi-section { + margin-bottom: 0.5em; + padding: 0.5em 1em; + border: 1px dotted #D2A800; + background-color: #FFE990; +} + +.cbi-section legend { + font-size: 110%; + font-weight: bold; + height: 1em; + padding: 0 0.25em; + color: #555555; +} + +.cbi-section h2 { + margin: 0em 0 0.5em -0.5em !important; +} + +.cbi-section h3 { + height: 1.5em; + font-size: 90%; + color: #555555; +} + +.cbi-section-descr { + margin-bottom: 0.5em; + font-size: 95%; +} + +.cbi-title-ref { + color: inherit; + text-decoration: none; + padding-right: 18px; + background: url('../resources/cbi/link.gif') no-repeat scroll right center; + background-color: inherit; +} + +input[type=submit], +input[type=reset], +input[type=image], +label { + cursor: pointer; +} + +select, +input, +textarea { + background: #FffdF4; + color: #000000; + border-width: 1px; + border-color: #000000; +} + +input[type=image] { + border: none; +} + + +input:focus, +input:hover, +select:focus, +select:hover, +textarea:focus, +textarea:hover { + background-color: #FFF4BE; +} + +select, +input[type=text], +input[type=password] { + width: 20em; +} + +td select, +td input[type=text], +td input[type=password] { + width: 99%; +} + +input.cbi-input-user { + background: url('../resources/cbi/user.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-password { + background: url('../resources/cbi/key.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-find { + background: url('../resources/cbi/find.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-reload { + background: url('../resources/cbi/reload.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-add, +input.cbi-button-add { + background: url('../resources/cbi/add.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-fieldadd, +input.cbi-button-fieldadd { + background: url(../resources/cbi/fieldadd.gif) no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-reset, +input.cbi-button-reset { + background: url('../resources/cbi/reset.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-save, +input.cbi-button-save { + background: url('../resources/cbi/save.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-apply, +input.cbi-button-apply { + background: url('../resources/cbi/apply.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-remove, +div.cbi-section-remove input { + background: url('../resources/cbi/remove.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +div.cbi-section-remove input { + border-bottom: none; +} + +textarea { + margin-left: -1px; + margin-bottom: 0.5em; +} + +form > div > input[type=submit], +form > div > input[type=reset] { + float: right; + margin-left: 0.5em; +} + +table.smalltext { +background-color: #FFCB05; + border-top: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + font-size: 90%; + width: 80%; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +table.smalltext tr:hover td { +background-color: #FFE990; +} + +table.smalltext tr th { + padding: 0 0.25em; + border-left: 1px solid #666666; + text-align: left; +} + +table.smalltext tr td { + padding: 0 0.25em; + border-top: 1px solid #666666; + border-left: 1px solid #666666; +} + +.cbi-rowstyle-1 { + background-color: #FFF4BE; +} + +.cbi-rowstyle-2 { +} + +div.cbi-value { + clear: left; + vertical-align: middle; + padding-left: 0.25em; + border-bottom: 1px dotted #FFCB05; +} + +div.cbi-value:hover { + background: #FFF4BE; +} + +div.cbi-value:last-child { + border: none; +} + +.cbi-value-title { + float: left; + width: 40%; +} + +div.cbi-value-field { + width: 58%; + margin: 0.25em 0 0.25em 40%; +} + +div.cbi-value-description { + font-size: 90%; +} + +div.cbi-value-field > div.cbi-value-description { + display: none; +} + +div.cbi-value:hover div.cbi-value-field > div.cbi-value-description { + display: block; + color: #ffffff; + background-color: #FFCB05; +} + +option:active, +option:before, +option:after, +option:focus, +option:hover { + color: #ffffff; + background-color: #EEBA00; + background: url(images/bgoption.png); +} + +div.cbi-section-create { + clear: left; + white-space: nowrap; +} + +div.cbi-map-descr { + margin-bottom: 1em; +} + +div.cbi-optionals { + margin: 0.5em 0; + padding: 0 0.25em; +} + +div.cbi-section-remove { + float: right; +} + +.cbi-section-node { + clear: both; + border: 1px dotted #FFCB05; + padding-bottom: 0; +} + +.cbi-section-node div.cbi-section-table-row { + margin: 0.25em; +} + +table.cbi-section-table { + width: 100%; + font-size: 95%; +} + +table.cbi-section-table th, +table.cbi-section-table td { + text-align: center; +} + +tr.cbi-section-table-descr th { + font-weight: normal; + font-size: 90%; +} + +td.cbi-section-table-optionals { + text-align: left !important; + padding-top: 1em; +} + +.cbi-value-helpicon img { + vertical-align: bottom; +} + +div.cbi-error { + font-size: 95%; + font-weight: bold; + color: #FF0000; +} + +td.cbi-value-error { + border-color: red !important; +} + +.cbi-value-error input, +.cbi-value-error select { + color: red !important; + background-color: #FFCCCC; +} + +.cbi-section-error { + color: red; + font-size: 95%; + border: 1px dotted red; + margin: 3px; + padding: 3px; +} + +ul.cbi-apply { + font-size: 90%; +} + +.right { + text-align: right; +} + +.luci { + position: fixed; + bottom: 0; + left: 0; + text-align: right; +} + +.luci a { + color: #666666; + text-decoration: none; + font-size: 70%; +} + +.inline { + display: inline; +} + +.error500 { + white-space: normal; + border: 1px dotted #FF0000; + background-color: #FFFFFF; + padding: 0.5em; +} + +#memorybar { + width:200px; + height:8px; + border:1px solid #bbb; + background-color:red +} + +#memfree, #membuffers, #memcached { + float:right; + border:1px solid #bbb; + height:6px; +} + +#memfree { + background-color:green; +} + +#membuffers { + background-color:yellow; +} + +#memcached { + background-color:orange; +} + + +/* obligatory IE6 Voodoo Code */ +* html body { + padding-left: 50% !important; +} + +* html div#header { + margin-left: -100% !important; +} + +* html div.menubar { + margin-left: -100% !important; + width: 200% !important; +} + +* html div#maincontent { + margin-left: -80% !important; + width: 160% !important; +} + +* html div.mainmenu div.hover ul, +* html div.mainmenu div li.hover ul, +* html div.mainmenu div li li.hover ul, +* html div.mainmenu div li li li.hover ul, +* html div.mainmenu div li li li li.hover ul { + display: block !important; + margin-left: 3em; +} + +* html div.mainmenu div.hover ul { + margin-left: 0; +} + +* html div.mainmenu .hover ul ul, +* html div.mainmenu .hover ul ul ul, +* html div.mainmenu .hover ul ul ul ul, +* html div.mainmenu .hover ul ul ul ul ul { + display: none !important; +} + +* html div.mainmenu li { + height: 1em !important; + width: 10em !important; +} + +* html .mainmenu { + height: 1.8em; +} + +* html div.cbi-value-description { + margin-left: 40%; +} diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/bgoption.png b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/bgoption.png new file mode 100644 index 0000000000000000000000000000000000000000..6fd1e2f34787b200eb425e42fb98c75b039163e2 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}K#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*yMv=#_6DqH@!17xt5c>21s-{2Gz=HriQFMb9T;`MZK4B@z*T(N!D bLwg3cy-YKE&k4N(N-%i3`njxgN@xNAizFlF literal 0 HcmV?d00001 diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/favicon.ico b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7247cfac5fe279cf3e12c965f53483196bfb0e2f GIT binary patch literal 5310 zcmeHJd2AGA6n}uYe@I#)M*vMg2#O-0f)-FIh+q(ng4H&}NJygr4G0#oh0<*)Edo`b z6iWb+044>R6hb106t=XbT-CN%OS^OJebMf2ce|avW_;6GrrVuqHT-FIc4qVDeQ$o> zo8P+zU=aQ$OaS~J17#xtMgzbUyif)6@e=fpc7y`lUuE9%751GY^f^H10)yvPp!bY7 zXmXv8h8g|T!Iw-MfY=O_1TJpzEs)haT+x<~CX-iu8-XkYW(P3adrp*5$OM8nge6Q% zga7Co7U^~X!P?}fD!Zc%vVeO1V`|z;Ds?(NH=P-`k4c$KEto_sG1w)uf+uttKq7CF zMp0-z-}Ma;89<1ur)}PaT3gm`TlO^l?LF@OqYT@D&I9UJzN`6+_pH}fY;+epI|~jt za)4Y1T769)$K+eoAMX4L+O`1o>j+ax*t1>dYV8V0X2%v-aS8o&>3Ws-J^rU=wWbUw z8ovHd;jlIMGl7JI#Hlq730V}*u5ut(815K-cSGPnvUwzB^oDvP5@Qp6n_b(U^{PHv zBg)qcUEcvI#}`+RSUiQg$SWM0Wj?;hDn~%gXDtpg6jWTgSLVgE%mhkt6_uK;*M*_ z(KBXh19ar2q8~J}LC`QzNy48D+@awjF|>;53@UiSySev96B|YeuYj-!ekRS1<&P!# zK@z=gnK2qxlmlT7E@p3czc=TI9_i5#iz!(sWiR@Pn zSxNO~sHA$4r7f;dOPdsuq%PC>;bg&KgcZTDWnp`nl13WJeR6-`5((G(IxlX4%HK)3 zJyYRZI+ZMV*lERni1-PcNar=b+#W6w{o>=2?C3bp!d~rGAh9uGK8yJIKrbCb+OD%Q zb4+U{mVD9wtMssHoq|0;NxjQb%bM=6Efrn33-+|lK+buMXs=W7f1kmP2@}gdl5>GL zY4s}N7n$6W-gKAs+In)bQOEHL`GA(6G~0y~s-&T+=frSd&|;-aAkjhyLC`>U+;Fq^ zJPQ7chLs(@7w($iA_bS}m+Q@VD+7oqE*^K^2`k_PdA`v4FFm$lowFwOL4U}o=Uv<~ zX!{a~qjM}sezYa84Z$I8`FvZnGDfc5?W)@|kPjzPY*0ZJ0ge6Vb71En)e z*e(iydUJRi|3FYG9yow%cJ_-OXbCPFOKcg6Gp6jLmQ68(s9Ou>W-ZLSZug_&3%!iTHI)D>L<|pTK0N@GXAc?I#nr!b&3Ur z{l9G4Ks=Z7-WBP3wkdYdxOBm)Z3_4sQjCkIl0QD|2{=X->6Mh{-m#C(AU}GXIK9Ni zTYJNS4O64;kjzk^e8F7CIlJBZ6X>y_;b$1~+-X*5^3qd{$2~Y?am=lMl3w^0^_ZF{ znrN)q;xwQ1@jQQPtKk3N6RY3gmWBYgfjy9 z%u>-SC(-Xtr{J*mfY-C;2MgRJ_n&BAHJHeFzEA)8<7bb(S)sDzyI^!M0WgPg7fiN% z;iSLsVU?;7DmUC7Mprii;Woy`NRFnc!Re1fABzIV98MzKt8kd$t-U!ie35M=WZ*ne zM2=D73@uNy;|KZPXN2i#x*ehSMv=SWm?z}#jeg97;w`U9Xyv4$)s|=i4lgFv^gzGM+9>UGb xQE>^Gst_zl41wwwZqP!WAC%7Xx^(4+t>|f78D}8QK%9X%191l84E$dh_y^c+g?9h| literal 0 HcmV?d00001 diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-back.gif b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-back.gif new file mode 100644 index 0000000000000000000000000000000000000000..21fe02b1e9af89e64fea086b438e20e68b391927 GIT binary patch literal 127 zcmZ?wbhEHbWMxQU*v!E2|NsA=KYzY?^XA5l8~@KR?A^O}&YU?-O-*@ud5MXM3>ZN1 zCku-R!+!=HkPOHS1{R$OCp=g0wRnAY_x}WqzLd;)8LQUic&i!oocWx1+ijk>jr||{ P#sCQoF-DIR76xkomfbH1 literal 0 HcmV?d00001 diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-left.gif b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/header-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..a3258ccb6d2f6809c591cdcf5694b6d9557c0feb GIT binary patch literal 293 zcmZ?wbhEHbWMxQUxXQrr|Ns9#fByXb{rlIiUq65T{Qmv>=g*%%eE9JG{rh+C-o1JA z=EaK_PoF-0`0(M~yLWHiym{lsjk9OZ{y)QT^ytweM~)mgaA51!ty{KiS+Qcp!i5Vb zO`0@u;>7m$_J)Rr($dnBl9G&!3P#h)xJA`Jf-bU>DX{KUZKkR+M{QLX+`uh6$`T6(v_x1Jl^z`)e^YifV z@b2#J?Ck96>FMa`=;h_*$$O;Js L%*+7K&p`k?3O3Jl literal 0 HcmV?d00001 diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/logo.gif b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff00d6ddb8051a28a4430977069e240b8a0a741b GIT binary patch literal 2415 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 literal 0 HcmV?d00001 diff --git a/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/main-back.png b/themes/freifunk-bno/htdocs/luci-static/freifunk-bno/images/main-back.png new file mode 100644 index 0000000000000000000000000000000000000000..34aca44e01c12fa9f63dcce8d5c6fa529133f7b2 GIT binary patch literal 404 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 +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: footer.htm 3464 2008-09-29 19:10:51Z jow $ + +-%> +
+
+ + + + +
+
+ + + + + + + diff --git a/themes/freifunk-bno/luasrc/view/themes/freifunk-bno/header.htm b/themes/freifunk-bno/luasrc/view/themes/freifunk-bno/header.htm new file mode 100644 index 0000000000..8ea30587e0 --- /dev/null +++ b/themes/freifunk-bno/luasrc/view/themes/freifunk-bno/header.htm @@ -0,0 +1,196 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: header.htm 3529 2008-10-07 13:10:24Z jow $ + +-%> +<% +require("luci.sys") +local load1, load5, load15 = luci.sys.loadavg() +local request = require("luci.dispatcher").context.path +local category = request[1] +local tree = luci.dispatcher.node() +local cattree = category and luci.dispatcher.node(category) +local node = luci.dispatcher.context.dispatched +local hostname = luci.sys.hostname() + +local c = tree +for i,r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end +end + +require("luci.i18n").loadc("default") +require("luci.http").prepare_content("text/html") + +-%> + + + + + + + <% if node and node.css then %><% end %> + + + + <%=striptags( hostname .. ( (node and node.title) and ' - ' .. node.title or '')) %> - LuCI + + + + +
+
+ +
+
+ + + + +
+<%:path%>: <% +local c = tree +local url = controller +for k,v in pairs(request) do + if c.nodes and c.nodes[v] then + c = c.nodes[v] + url = url .. "/" .. v + %><%=c.title or v%> <% if k ~= #request then %>» <% end + end +end +%> +
+ + +
+
    <% + for k,node in pairs(tree.nodes) do + if node.title and not node.hidden then %> + class="active"<%end%>><%=node.title%> +<% end + end%> +
+
+ + <% + if tree.nodes[category] and tree.nodes[category].ucidata then + local ucic = 0 + + for i, j in pairs(require("luci.model.uci").cursor():changes()) do + for k, l in pairs(j) do + for m, n in pairs(l) do + ucic = ucic + 1; + end + end + end + %> + + <% end %> + +
+
+
diff --git a/themes/freifunk-bno/root/etc/uci-defaults/luci-theme-freifunk-bno b/themes/freifunk-bno/root/etc/uci-defaults/luci-theme-freifunk-bno new file mode 100755 index 0000000000..e5fb8a12dc --- /dev/null +++ b/themes/freifunk-bno/root/etc/uci-defaults/luci-theme-freifunk-bno @@ -0,0 +1,6 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.Freifunk_BNO=/luci-static/freifunk-bno + commit luci +EOF + diff --git a/themes/freifunk/Makefile b/themes/freifunk/Makefile new file mode 100644 index 0000000000..81a96f6a83 --- /dev/null +++ b/themes/freifunk/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/themes/freifunk/htdocs/luci-static/freifunk/cascade.css b/themes/freifunk/htdocs/luci-static/freifunk/cascade.css new file mode 100644 index 0000000000..3507777572 --- /dev/null +++ b/themes/freifunk/htdocs/luci-static/freifunk/cascade.css @@ -0,0 +1,726 @@ +* { + margin: 0; + padding: 0; +} + +body { + background-color: #ffffff; + color: #ffffff; + font-family: Verdana, Arial, sans-serif; + font-size: 100%; + line-height: 100%; + background-image: url(images/main-back.png); + background-repeat: repeat-x; + background-position: left bottom; + } +#all { + margin: 0px; + padding: 0px; + min-height: 800px; +} + +code { + font-family: monospace; + white-space: pre; +} + +a:link, a:visited { + color:#000000; + font-weight:bold; + text-decoration:none; + } +a:hover { + color:#333333; + font-weight:bold; + } + +/* Custom*/ + #wrapper +{ + width: 95%; + color: #333333; + margin-left: auto; + margin-right: auto; +/* background-image: url(images/corner-left.gif); */ +/* background-repeat: no-repeat; */ +/* background-position: left bottom; */ + background-color: #FffdF4; + min-width: 710px; + min-height: 710px; +} +#main { + clear: both; + width: 100%; + margin: 0; + padding: 0; + color: #333333; +/* background-image: url(images/corner-right.gif); */ +/* background-repeat: no-repeat; */ +/* background-position: right bottom; */ + min-height: 710px; +} + +div#maincontent ul { + margin-left: 2em; +} + +.warning { + color: red !important; + font-weight: bold; +} + +.clear { + clear: both; + height: 1px; +} + +.hidden { + display: none; +} + +.error { + color: #ff0000; +} + +#header +{ + padding: 0px; + height: 100px; +} +#headerleft +{ + height: 100px; + background-color: #FFFfff; + background-image: url(images/header-left.gif); + background-repeat: no-repeat; + background-position: left top; +} +#headerright +{ + height: 100px; + background-color: #FFfffF; + + margin-left: 5px; + background-image: url(images/header-right.gif); + background-repeat: no-repeat; + background-position: right top; +} + +#headerback +{ + margin-right: 5px; + height: 100px; + background-color: #FFfffF; + background-image: url(images/header-back.gif); + background-repeat: repeat-x; + background-position: left top; +} +#schriftzug { + font-size : 1.5em; + text-align:left; + margin-bottom: 7px; + margin-top: 7px; + float:left; + width: 450px; +} + +#schriftzug a:hover{ + background-color:transparent; +} +#logo{ + margin-top: 5px; + float:right; + width: 115px; +} + +.pathbar { + display: none; +} + +.menubar { + width: 100%; + min-height: 1.8em; + background: #ffffff; + color: #000000; + border-top:0.4em solid #DC0067; +} + +.mainmenu { + float: left; + width: auto; + min-height: 1.8em; + background: #ffffff; + color: #000000; +} +.modemenu li { + border-top:0.3em solid #DC0067; + margin-left: 0.3em; + margin-top: -0.3em; +} +.mainmenu div { + float: left; + border-top:0.3em solid #DC0067; + margin-right: 0.3em; + margin-top: -0.3em; +} +.mainmenu div.preactive { + border-top: 0.3em solid #FFCB05; + margin-top: -0.2em; +} + +.mainmenu li { + white-space: nowrap; +} + +.mainmenu div ul { + display: none; + position: absolute; + background: #ffffff; + color: #000000; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #444444; + list-style-type: none; +} + +.mainmenu ul li:hover > ul, +.mainmenu div:hover > ul { + display: block; +} + +.mainmenu ul li > ul { + left: 100%; + margin-top: -1.8em; + border-width: 1px; +} + +.modemenu a, +.mainmenu a { + display: block; + padding: 0.2em; + color: #000000; + text-decoration: none; + font-size: 70%; + font-weight: bold; +} + + +.modemenu .active a { + color: #000000; + font-weight: bold; + border-top:0.3em solid #FFCB05; + margin-top: -0.2em; +} +.mainmenu .active a{ + color: #000000; + font-weight: bold; + border-top:0.2em solid #FFCB05; +} +.mainmenu li > span:active { + background-color: #FFE990; +} + +.mainmenu li:hover > span > a, +.mainmenu div:hover > a { +color: #ffffff; +background-color: #FFCB05; +} + + +.modemenu a:focus, +.mainmenu a:focus { + color: #000000; +} + +.mainmenu a:hover, +.modemenu a:hover { +color: #ffffff; +background-color: #FFCB05; +} + +.mainmenu div.preactive > a { + color: #DC0067; + font-weight: bold; +} +.mainmenu div.preactive > a:hover, +.mainmenu div.preactive > a:focus { + color: #ffffff; + font-weight: bold; +} + +.modemenu ul { + width: auto; + background: #000000; + color: #ffffff; + list-style-type: none; +} + +.modemenu li { + float: right; + +} + +#maincontent { + clear: both; + width: 98%; + margin: 0 auto; + padding: 0.5em; + background: #FFF4BE; + color: #000000; + font-size: 80%; + border-top:1px solid #D2A800; +} + +#maincontent h2 { + margin: 0.25em 0 0.5em 0; + font-size: 150%; + font-weight: normal; +} + +#maincontent h3 { + margin: 0.5em 0; + font-size: 120%; + font-weight: normal; + text-decoration: underline; +} + +#maincontent p { + margin-bottom: 1em; +} + +.cbi-section { + margin-bottom: 0.5em; + padding: 0.5em 1em; + border: 1px dotted #D2A800; + background-color: #FFE990; +} + +.cbi-section legend { + font-size: 110%; + font-weight: bold; + height: 1em; + padding: 0 0.25em; + color: #555555; +} + +.cbi-section h2 { + margin: 0em 0 0.5em -0.5em !important; +} + +.cbi-section h3 { + height: 1.5em; + font-size: 90%; + color: #555555; +} + +.cbi-section-descr { + margin-bottom: 0.5em; + font-size: 95%; +} + +.cbi-title-ref { + color: inherit; + text-decoration: none; + padding-right: 18px; + background: url('../resources/cbi/link.gif') no-repeat scroll right center; + background-color: inherit; +} + +input[type=submit], +input[type=reset], +input[type=image], +label { + cursor: pointer; +} + +select, +input, +textarea { + background: #FffdF4; + color: #000000; + border-width: 1px; + border-color: #000000; +} + +input[type=image] { + border: none; +} + + +input:focus, +input:hover, +select:focus, +select:hover, +textarea:focus, +textarea:hover { + background-color: #FFF4BE; +} + +select, +input[type=text], +input[type=password] { + width: 20em; +} + +td select, +td input[type=text], +td input[type=password] { + width: 99%; +} + +input.cbi-input-user { + background: url('../resources/cbi/user.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-password { + background: url('../resources/cbi/key.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-find { + background: url('../resources/cbi/find.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-reload { + background: url('../resources/cbi/reload.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; +} + +input.cbi-input-add, +input.cbi-button-add { + background: url('../resources/cbi/add.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-fieldadd, +input.cbi-button-fieldadd { + background: url(../resources/cbi/fieldadd.gif) no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-reset, +input.cbi-button-reset { + background: url('../resources/cbi/reset.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-save, +input.cbi-button-save { + background: url('../resources/cbi/save.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-apply, +input.cbi-button-apply { + background: url('../resources/cbi/apply.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-remove, +div.cbi-section-remove input { + background: url('../resources/cbi/remove.gif') no-repeat scroll 1px center; + background-color: inherit; + padding-left: 17px; + padding-right: 1px; +} + +div.cbi-section-remove input { + border-bottom: none; +} + +textarea { + margin-left: -1px; + margin-bottom: 0.5em; +} + +form > div > input[type=submit], +form > div > input[type=reset] { + float: right; + margin-left: 0.5em; +} + +table.smalltext { +background-color: #FFCB05; + border-top: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + font-size: 90%; + width: 80%; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +table.smalltext tr:hover td { +background-color: #FFE990; +} + +table.smalltext tr th { + padding: 0 0.25em; + border-left: 1px solid #666666; + text-align: left; +} + +table.smalltext tr td { + padding: 0 0.25em; + border-top: 1px solid #666666; + border-left: 1px solid #666666; +} + +.cbi-rowstyle-1 { + background-color: #FFF4BE; +} + +.cbi-rowstyle-2 { +} + +div.cbi-value { + clear: left; + vertical-align: middle; + padding-left: 0.25em; + border-bottom: 1px dotted #FFCB05; +} + +div.cbi-value:hover { + background: #FFF4BE; +} + +div.cbi-value:last-child { + border: none; +} + +.cbi-value-title { + float: left; + width: 40%; +} + +div.cbi-value-field { + width: 58%; + margin: 0.25em 0 0.25em 40%; +} + +div.cbi-value-description { + font-size: 90%; +} + +div.cbi-value-field > div.cbi-value-description { + display: none; +} + +div.cbi-value:hover div.cbi-value-field > div.cbi-value-description { + display: block; + color: #ffffff; + background-color: #FFCB05; +} + +option:active, +option:before, +option:after, +option:focus, +option:hover { + color: #ffffff; + background-color: #EEBA00; + background: url(images/bgoption.png); +} + +div.cbi-section-create { + clear: left; + white-space: nowrap; +} + +div.cbi-map-descr { + margin-bottom: 1em; +} + +div.cbi-optionals { + margin: 0.5em 0; + padding: 0 0.25em; +} + +div.cbi-section-remove { + float: right; +} + +.cbi-section-node { + clear: both; + border: 1px dotted #FFCB05; + padding-bottom: 0; +} + +.cbi-section-node div.cbi-section-table-row { + margin: 0.25em; +} + +table.cbi-section-table { + width: 100%; + font-size: 95%; +} + +table.cbi-section-table th, +table.cbi-section-table td { + text-align: center; +} + +tr.cbi-section-table-descr th { + font-weight: normal; + font-size: 90%; +} + +td.cbi-section-table-optionals { + text-align: left !important; + padding-top: 1em; +} + +.cbi-value-helpicon img { + vertical-align: bottom; +} + +div.cbi-error { + font-size: 95%; + font-weight: bold; + color: #FF0000; +} + +td.cbi-value-error { + border-color: red !important; +} + +.cbi-value-error input, +.cbi-value-error select { + color: red !important; + background-color: #FFCCCC; +} + +.cbi-section-error { + color: red; + font-size: 95%; + border: 1px dotted red; + margin: 3px; + padding: 3px; +} + +ul.cbi-apply { + font-size: 90%; +} + +.right { + text-align: right; +} + +.luci { + position: fixed; + bottom: 0; + left: 0; + text-align: right; +} + +.luci a { + color: #666666; + text-decoration: none; + font-size: 70%; +} + +.inline { + display: inline; +} + +.error500 { + white-space: normal; + border: 1px dotted #FF0000; + background-color: #FFFFFF; + padding: 0.5em; +} + +#memorybar { + width:200px; + height:8px; + border:1px solid #bbb; + background-color:red +} + +#memfree, #membuffers, #memcached { + float:right; + border:1px solid #bbb; + height:6px; +} + +#memfree { + background-color:green; +} + +#membuffers { + background-color:yellow; +} + +#memcached { + background-color:orange; +} + + +/* obligatory IE6 Voodoo Code */ +* html body { + padding-left: 50% !important; +} + +* html div#header { + margin-left: -100% !important; +} + +* html div.menubar { + margin-left: -100% !important; + width: 200% !important; +} + +* html div#maincontent { + margin-left: -80% !important; + width: 160% !important; +} + +* html div.mainmenu div.hover ul, +* html div.mainmenu div li.hover ul, +* html div.mainmenu div li li.hover ul, +* html div.mainmenu div li li li.hover ul, +* html div.mainmenu div li li li li.hover ul { + display: block !important; + margin-left: 3em; +} + +* html div.mainmenu div.hover ul { + margin-left: 0; +} + +* html div.mainmenu .hover ul ul, +* html div.mainmenu .hover ul ul ul, +* html div.mainmenu .hover ul ul ul ul, +* html div.mainmenu .hover ul ul ul ul ul { + display: none !important; +} + +* html div.mainmenu li { + height: 1em !important; + width: 10em !important; +} + +* html .mainmenu { + height: 1.8em; +} + +* html div.cbi-value-description { + margin-left: 40%; +} diff --git a/themes/freifunk/htdocs/luci-static/freifunk/images/bgoption.png b/themes/freifunk/htdocs/luci-static/freifunk/images/bgoption.png new file mode 100644 index 0000000000000000000000000000000000000000..6fd1e2f34787b200eb425e42fb98c75b039163e2 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k92}K#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*yMv=#_6DqH@!17xt5c>21s-{2Gz=HriQFMb9T;`MZK4B@z*T(N!D bLwg3cy-YKE&k4N(N-%i3`njxgN@xNAizFlF literal 0 HcmV?d00001 diff --git a/themes/freifunk/htdocs/luci-static/freifunk/images/favicon.ico b/themes/freifunk/htdocs/luci-static/freifunk/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f785830ff77a700ac1dbf153a11f638f32481171 GIT binary patch literal 4286 zcmeI0d2Ccw6o=0U6l@SdA_`?0cBpnGExS`F`x<0Xs31~6N;@qeDp9Z{7SM>4 z9ykpb;V(D@AAlF`g>bz{<3wa$fYH#rmi%43_l4(RXz-i-{s2xbDtWK2HFuKtC7^gC z`R>kqKD5s1V#p8qP^Pc4t;x zX$H^7&so9|#}a>bEY9cHsKN`D7gG|7vkP+N zApNzl5LUngl9@5^WFY3$9aZ(9L9ef`MUPlJQg&7=-qGk)fCC4hBUs`g#|FMrVcFeFqrDw{i_q%` zIuEk-IPrTk2b{E&UDfsRITW46ARDI=4>|+Jd(T>4>k{>VP|U3vPouWRlD8hC3(8%I zzc}NNFAwTTcNc7e4|^0lo7vMg6SJ@rQ!)zOUJ$C`4cJ&PeOOr(a*dOVo#W_~K_xio zt;N3lzZ&$vfoB}_r`D#=jXTz+_g7W*lYVk`Nd8779CngMynNB}+W77#?s4dk2-@3+ z9rd-O^mSJZxn|gy02kTA&&g}k%(Rm_hns`)`8;*T2V!R?`L91@&1GZ#vFIEL^S_Pp zBFKlu)J2QoD=%7ZTVFJK+P^+f1?rbE)W*}ZQ;*-#@3TsaKjI`)JHz9Db)rTtqyAe5 z>i=Wpl>hmV2CJdZJkHF7?6dN3Sx|g{>JEO{p#gf|0$?BW1Y#T+n0@8%dGg)K;QGW5BS#iLXiJrcm>q60ycHF`h8ld zvllqG_`Lp9Tq!%NEYrgta>me6-x~vCLH71Q$iJSw*`I~PFqyj0KF5RVbrned4{(F} ziE^o&+7m;|tnb#!z*&<|!PyC*{R!@&>`#OwSOc=R9>V==datK?JP)$5-DtxIc`?}N|?Zsf1_d`o1HgLFTFHt;Oy zuC0;97yEXd;Cx%2TDNL$GE{?XOoiG$ZuPEwscxme5p=g^z#Q;^eCcjbtO=lRx@Wq9 z{Dtmd^)VOR%3q}K3(%8)aR5{c>glSJX`u5t9aQ7$mEv6p>3qRB8Y0=g-8tp)Oqfmm z9kvXnfa>yL$OY}wB?$Rm$5=h!cKzH;PG@2ZsE38@-{@J4jB;}`d;j%YEOwW`m+%{0 z0QI%+;dK}aQ4rC7q`%4Q=IS!=e`Ua__2X}1p6?3n?p1zk*zUa5^Z3o>DVp!fFY*`7 zFW6p`R=|HIfV-f;-E8T0|JzIb{@pJ+e!t7{pLaP${1!Mx`MjCSLEovchR!u>=Q!r6 IZN1 zCku-R!+!=HkPOHS1{R$OCp=g0wRnAY_x}WqzLd;)8LQUic&i!oocWx1+ijk>jr||{ P#sCQoF-DIR76xkomfbH1 literal 0 HcmV?d00001 diff --git a/themes/freifunk/htdocs/luci-static/freifunk/images/header-left.gif b/themes/freifunk/htdocs/luci-static/freifunk/images/header-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..a3258ccb6d2f6809c591cdcf5694b6d9557c0feb GIT binary patch literal 293 zcmZ?wbhEHbWMxQUxXQrr|Ns9#fByXb{rlIiUq65T{Qmv>=g*%%eE9JG{rh+C-o1JA z=EaK_PoF-0`0(M~yLWHiym{lsjk9OZ{y)QT^ytweM~)mgaA51!ty{KiS+Qcp!i5Vb zO`0@u;>7m$_J)Rr($dnBl9G&!3P#h)xJA`Jf-bU>DX{KUZKkR+M{QLX+`uh6$`T6(v_x1Jl^z`)e^YifV z@b2#J?Ck96>FMa`=;h_*$$O;Js L%*+7K&p`k?3O3Jl literal 0 HcmV?d00001 diff --git a/themes/freifunk/htdocs/luci-static/freifunk/images/logo.png b/themes/freifunk/htdocs/luci-static/freifunk/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0beeb2fad1c99c2477c00b5ab5214f9a82769797 GIT binary patch literal 6400 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 Z`v1Ohi~S#mD^>si002ovPDHLkV1fesfFl3^ literal 0 HcmV?d00001 diff --git a/themes/freifunk/ipkg/postinst b/themes/freifunk/ipkg/postinst new file mode 100755 index 0000000000..f5d35c9ab0 --- /dev/null +++ b/themes/freifunk/ipkg/postinst @@ -0,0 +1,4 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + ( . /etc/uci-defaults/luci-theme-freifunk ) && rm -f /etc/uci-defaults/luci-theme-freifunk +} diff --git a/themes/freifunk/luasrc/view/themes/freifunk/footer.htm b/themes/freifunk/luasrc/view/themes/freifunk/footer.htm new file mode 100644 index 0000000000..3566dab1d8 --- /dev/null +++ b/themes/freifunk/luasrc/view/themes/freifunk/footer.htm @@ -0,0 +1,29 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: footer.htm 3464 2008-09-29 19:10:51Z jow $ + +-%> +
+
+
+ + + +
+
+ + + + + + + diff --git a/themes/freifunk/luasrc/view/themes/freifunk/header.htm b/themes/freifunk/luasrc/view/themes/freifunk/header.htm new file mode 100644 index 0000000000..13e35fab46 --- /dev/null +++ b/themes/freifunk/luasrc/view/themes/freifunk/header.htm @@ -0,0 +1,196 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id: header.htm 3529 2008-10-07 13:10:24Z jow $ + +-%> +<% +require("luci.sys") +local load1, load5, load15 = luci.sys.loadavg() +local request = require("luci.dispatcher").context.path +local category = request[1] +local tree = luci.dispatcher.node() +local cattree = category and luci.dispatcher.node(category) +local node = luci.dispatcher.context.dispatched +local hostname = luci.sys.hostname() + +local c = tree +for i,r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end +end + +require("luci.i18n").loadc("default") +require("luci.http").prepare_content("text/html") + +-%> + + + + + + + <% if node and node.css then %><% end %> + + + + <%=striptags( hostname .. ( (node and node.title) and ' - ' .. node.title or '')) %> - LuCI + + + + +
+
+ +
+
+ + + + +
+<%:path%>: <% +local c = tree +local url = controller +for k,v in pairs(request) do + if c.nodes and c.nodes[v] then + c = c.nodes[v] + url = url .. "/" .. v + %><%=c.title or v%> <% if k ~= #request then %>» <% end + end +end +%> +
+ + +
+
    <% + for k,node in pairs(tree.nodes) do + if node.title and not node.hidden then %> + class="active"<%end%>><%=node.title%> +<% end + end%> +
+
+ + <% + if tree.nodes[category] and tree.nodes[category].ucidata then + local ucic = 0 + + for i, j in pairs(require("luci.model.uci").cursor():changes()) do + for k, l in pairs(j) do + for m, n in pairs(l) do + ucic = ucic + 1; + end + end + end + %> + + <% end %> + +
+
+
diff --git a/themes/freifunk/root/etc/uci-defaults/luci-theme-freifunk b/themes/freifunk/root/etc/uci-defaults/luci-theme-freifunk new file mode 100755 index 0000000000..eb038f0acc --- /dev/null +++ b/themes/freifunk/root/etc/uci-defaults/luci-theme-freifunk @@ -0,0 +1,6 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.Freifunk=/luci-static/freifunk + commit luci +EOF + diff --git a/themes/openwrt.org-oxygen/Makefile b/themes/openwrt.org-oxygen/Makefile new file mode 100644 index 0000000000..81a96f6a83 --- /dev/null +++ b/themes/openwrt.org-oxygen/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/bg.jpg b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dece957dfd82acae201397ebb04f7b3be93a5fd8 GIT binary patch literal 40537 zcmeFZc{r49|36Np&GyV~7o(a=qNE`^X|dgwJIa=b2}!bNiP5bh>yXM$i%2F*D>V^= zDaKy3C}t)kg)w9s{Lb^5QQgny`5wRHa~$8}_xtDRzRh)A=kk8P-mmv^o-=b@v-ozg zkLO>eh9-tQyu7?T#^67m#Sc9Dc$P0)2LA{DR)GKcR`c<#Si!e;)vA@N1=b1(@UP|P z7Zm#AUxGp?A%6aUiT?{FA}S^(CLk;!DK0Achp3n+6vDe4%vr&=hL3NJs35PiP z;tL+s>ScDTmo4Yr$g>Q^yBx*4SjQvF!^^WA{?E&^^pAJh@)avrt>#+;x}E>U%d?DU z#flZnmapO$;$Owb%ftJ}vgIg|6?_L>R<7D$pyGGq{sU3*jen<=fJs27-1q@E_+49$?FV z{`Y_E_~-EDCaTVR4y#JE@u{XBXy!E++#JCxs_H1V4_p`o?6KZ=U_zBoP@=6(w8LCN zHJNj*nrh;_5A>Nh?-6ZlkKp;M-Isfe5afk3_Z@g)Z6X1rNvQIvB1a$qj1)u^@K~Gk zK~+#H@~6tjH^FPZ2}lAm9Z?1W28TKhfEHv#TZgSG%3M`~?=RSIqU!il5)ixz!GQor zt{@(W#TVGnCaQ|`n%nXkaPR?4z)qyq0Ahh!fx(-A#12~shGQUv0!=r8syGUuIlvTE zM?O`=41^Y7+0o7XUrwx*-mxr`|I4!I%T?zTu2<$qWg1srSGaL=R(e^cF>I=eK35Pm z%To|FaIPRa{)^}O8#ntv>p6v+fma_wh9Em!M)&Rc3#tWpP>>NpXf}X~kOSZ&T`T@_ z-e+)#V;x``u?29&C-}=W!Oe*C0L=(R+#x_$Ds(6x_)}HAickz_0HdI%pa@_h#9{(m z2zp_UNInr*sGOgs2lmEH?BkTlvMLY zFBD59D)6n(cL(QD2@O}GQreL7i$7bEE^gRL^)y!CH-@ikkXJs8%I)>}qHuijL*&&8 zD{ZxQ@4@trWGivdkkro+d4VG)1-7p>#F-ixkHC@ISCTFwBDO>A8x)XNPw*<+XaGhT z?M=P{0dYWFxCNC3J0R0dp&kPc2+nwT{>5r7(vA#)1C9KX5iEZonzclKNkfcG=74~b zF*l4y9wOEwLpc+~Ie?)|BY#f&Z?+zU*8K5X0|zVuGjQu~EJ1*4p+N@5NV9C$PaP>e z`P&f&I3)fuHxO{}@0Q9oLL_@TICv1n2nNU~u=L8W7RY@RhrFbVhH+7 zOF{D+a1I&=#7<5uA=Yvu>L+a=x_&$V&FP2_gB3WI1akuF7aDFPMS-~>zBePpLlb3d zQ(SJF-X}I(-6k+0edrE$>95Vx>N@rJzxLav=XFN0?TKmiAzJJ*)K+`&vJn$v|eBak6%@Rtd@fBjh{08j^W&zoKaamF3n!JRJb1VY{Lom6~OCSK>KLJ1smnN8E0W(}y zfkF;nfadmsWDfHGAOJxRhARGhEad-AX$@CjDV1-+^g~4FlO9ot{9wag-$TwmmBxI0 zKju=Scn!ip?Laydq?biaL?y4~?|hxVEQ%S0deS2%kuQ4gFDG9EWU6RV-}UF~LEi)@ zoIsQaoNZwI8k`0x@LYe6*$XCjXlF�HIdk{QH!GEIfw_#6OH=f|-eH_iR-*mS1r; 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/cascade.css b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/cascade.css new file mode 100644 index 0000000000..8aea909995 --- /dev/null +++ b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/cascade.css @@ -0,0 +1,803 @@ +@charset "utf-8"; + +@media all { + +html, +body { + background-color: #4a6b7c; + background-image: url(bg.jpg); + background-position: bottom center; + background-attachment: fixed; + background-repeat: repeat-x; + color: #ffffff; +} + +body { + font-family: Verdana, Arial, sans-serif; + font-size: 101%; + line-height: 100%; +} + +* { + margin: 0; + padding: 0; +} + +abbr, +acronym { + font-style: normal; + font-variant: normal; +} + +abbr[title], +acronym[title] { + border-bottom: 1px dotted; + cursor: help; +} + +a:link abbr[title], +a:visited abbr[title], +a:link acronym[title], +a:visited acronym[title] { + cursor: pointer; +} + +code { + font-family: monospace; + white-space: pre; +} + +#maincontent ul { + margin-left: 2em; +} + +.warning { + color: red; + background-color: white; + font-weight: bold; +} + +.clear { + clear: both; +} + +.skiplink, +.navigation, +.hidden { + position: absolute; + left: -1000px; + top: -1000px; + width: 0px; + height: 0px; + overflow: hidden; + display: inline; +} + +.error { + color: #ff0000; + background-color: white; +} + +#header { + min-height: 98px; + background-image: url(header.png); + background-repeat: no-repeat; + background-position: left center; + background-color: #557788; + color: #ffffff; + text-align: right; +} + +#header h1 { + padding: 1em 1em 0 1em; +} + +#header p { + padding: 0 1em 1em 1em; +} + +#header h1, +#header p { + font-size: 70%; + font-weight: normal; + line-height: 160%; + text-align: right; +} + +ul.dropdowns { + float: left; + margin: 0; + padding: 0; + width: auto; + list-style: none; +} + +html>body ul.dropdowns { + position: relative; +} + +ul.dropdowns li, +ul.dropdowns ul { + margin: 0; + padding: 0; + list-style: none; +} + +ul.dropdowns li { + float: left; + position: relative; + white-space: nowrap; +} + +ul.dropdowns li ul { + position: absolute; + z-index: 1000; + top: auto; + min-width: 10em; +} + +ul.dropdowns li li { + float: none; + position: relative; +} + +ul.dropdowns li a { + display: block; +} + +ul.dropdowns ul li ul { + top: 0; +} + +ul.dropdowns li ul, +ul.dropdowns li.over ul ul, +ul.dropdowns li.focus ul ul, +ul.dropdowns li:hover ul ul, +ul.dropdowns li.over ul ul ul, +ul.dropdowns li.focus ul ul ul, +ul.dropdowns li:hover ul ul ul, +ul.dropdowns li.over ul ul ul ul, +ul.dropdowns li.focus ul ul ul ul, +ul.dropdowns li:hover ul ul ul ul { + left: -3000px; +} + +ul.dropdowns li.over ul, +ul.dropdowns li.focus ul, +ul.dropdowns li:hover ul { + left: 0; +} + +ul.dropdowns ul li.over ul, +ul.dropdowns ul li.focus ul, +ul.dropdowns ul li:hover ul, +ul.dropdowns ul ul li.over ul, +ul.dropdowns ul ul li.focus ul, +ul.dropdowns ul ul li:hover ul, +ul.dropdowns ul ul ul li.over ul, +ul.dropdowns ul ul ul li.focus ul, +ul.dropdowns ul ul ul li:hover ul { + left: 100%; +} + +#menubar { + position: relative; + width: 100%; + background: #000000; + color: #ffffff; +} + +#menubar .warning { + color: red; + background-color: #557788; +} + +#menubar ul.dropdowns { + min-height: 1.8em; + background: #000000; + color: #ffffff; +} + +#menubar ul.dropdowns li ul { + background: #000000; + color: #ffffff; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #444444; +} + +#menubar ul.dropdowns ul li ul { + border-width: 1px; +} + +html #menubar a:link, +html #menubar a:visited { + position: relative; + display: block; + padding: 0.5em; + background: #000000; + color: #ffffff; + text-decoration: none; + font-size: 80%; + font-weight: normal; +} + + +html #menubar a:link:hover, +html #menubar a:visited:hover, +html #menubar a:link:active, +html #menubar a:visited:active, +#menubar a:link:focus, +#menubar a:visited:focus { + background: #000000; + color: #ffff00; + font-weight: bold; +} + +html #menubar a:link.active, +html #menubar a:visited.active, +html #menubar a:link.preactive, +html #menubar a:visited.preactive { + background: #000000; + color: #ffff00; + font-weight: bold; +} + +html #menubar a:link.warning, +html #menubar a:visited.warning { + background: #000000; + color: red; + font-weight: bold; +} + +#menubar ul.dropdowns li.over>a, +#menubar ul.dropdowns li.focus>a, +#menubar ul.dropdowns li:hover>a { + font-weight: bold; +} + +.lang_de #submenu_mini_system { min-width: 13.3em; } +* html .lang_de #submenu_mini_system { width: 13.3em; } + +.lang_pt-br #submenu_mini_network { min-width: 14em; } +* html .lang_pt-br #submenu_mini_network { width: 14em; } + +.lang_pt-br #submenu_mini_system { min-width: 11.5em; } +* html .lang_pt-br #submenu_mini_system { width: 11.5em; } + +.lang_ru #submenu_mini_system { min-width: 18em; } +* html .lang_ru #submenu_mini_system { width: 18em; } + +.lang_pt-br #submenu_admin_index { min-width: 11em; } +* html .lang_pt-br #submenu_admin_index { width: 11em; } + +.lang_ru #submenu_admin_index { min-width: 15.5em; } +* html .lang_ru #submenu_admin_index { width: 15.5em; } + +.lang_ru #submenu_admin_status { min-width: 10.5em; } +* html .lang_ru #submenu_admin_status { width: 10.5em; } + +.lang_de #submenu_admin_system { min-width: 13.3em; } +* html .lang_de #submenu_admin_system { width: 13.3em; } + +.lang_fr #submenu_admin_system { min-width: 14.5em; } +* html .lang_fr #submenu_admin_system { width: 14.5em; } + +.lang_pt-br #submenu_admin_system { min-width: 11.5em; } +* html .lang_pt-br #submenu_admin_system { width: 11.5em; } + +.lang_ru #submenu_admin_system { min-width: 18em; } +* html .lang_ru #submenu_admin_system { width: 18em; } + +#submenu_admin_services_chillispot { min-width: 15.5em; } +* html #submenu_admin_services_chillispot { width: 15.5em; } + +#submenu_admin_services_coovachilli { min-width: 15em; } +* html #submenu_admin_services_coovachilli { width: 15em; } + +.lang_ru #submenu_admin_network_routes { min-width: 15.3em; } +* html .lang_ru #submenu_admin_network_routes { width: 15.3em; } + +#submenu_admin_network_firewall { min-width: 14em; } +* html #submenu_admin_network_firewall { width: 14em; } + +.lang_de #submenu_admin_network_firewall { min-width: 16.5em; } +* html .lang_de #submenu_admin_network_firewall { width: 16.5em; } + +.lang_pt-br #submenu_admin_network_firewall { min-width: 15em; } +* html .lang_pt-br #submenu_admin_network_firewall { width: 15em; } + +#modemenu { + width: auto; + background: #000000; + color: #ffffff; + list-style: none; + margin-right: 1px; +} + +#modemenu li { + float: right; + list-style: none; +} + +#savemenu { + float: right; + margin-right: 2em; +} + +.lang_de #submenu_admin_uci { + width: 12em; +} + +.lang_ru #submenu_admin_uci { + width: 11.5em; +} + +textarea#syslog { + width: 98%; + min-height: 500px; + border: 3px solid #cccccc; + padding: 5px; + font-family: monospace; +} + +#maincontent { + clear: both; + width: 80%; + margin: 0 auto; + padding: 0.5em; + background: #f5f5f5; + color: #000000; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #444444; + font-size: 80%; +} + +#maincontent h2 { + font-size: 150%; + font-family: Trebuchet MS, Verdana, sans-serif; + font-weight: bold; + margin: 0.25em 0 0.7em 0; + border-bottom: 1px solid; + padding-top: 10px; + padding-bottom: 4px; +} + +#maincontent h3 { + margin: 0.5em 0 1.1em 0; + font-size: 125%; + font-weight: bold; + font-style: italic; + font-family: Trebuchet MS, Verdana, sans-serif; + color: #27408B; +} + +#maincontent p { + margin-bottom: 1em; +} + +.cbi-section { + margin-bottom: 0.5em; + padding: 0.5em 1em; + border: 1px dotted #555555; + background-color: #ffffff; + color: #000000; +} + +.cbi-section legend { + font-size: 110%; + font-weight: bold; + height: 1em; + padding: 0 0.25em; + background-color: transparent; + color: #555555; +} + +.cbi-section h2 { + margin: 0em 0 0.5em -0.5em !important; +} + +.cbi-section h3 { + text-decoration: none !important; + font-weight: bold !important; + color: #555555 !important; + margin: 0.25em !important; + font-size: 100% !important; +} + +.cbi-section-descr { + margin-bottom: 0.5em; + font-size: 95%; +} + +.cbi-title-ref { + color: inherit; + text-decoration: none; + padding-right: 18px; + background: url('../resources/cbi/link.gif') no-repeat scroll right center; + background-color: inherit; +} + +ul.cbi-apply { + font-size: 90%; +} + +input[type=submit], +input[type=reset], +input[type=image] { + cursor: pointer; +} + + +select, +input, +textarea { + background: #eeeeee; + color: #000000; + border-width: 1px; + border-color: #000000; +} + +input[type=image] { + border: none; +} + +input:focus, +input:hover, +select:focus, +select:hover, +textarea:focus, +textarea:hover { + background-color: #ffffff; + color: #000000; +} + +select, +input[type=text], +input[type=password] { + width: 20em; +} + +td select, +td input[type=text], +td input[type=password] { + width: 99%; +} + +input.cbi-input-user { + background: url('../resources/cbi/user.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + text-indent: 17px; +} + +input.cbi-input-password { + background: url('../resources/cbi/key.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + text-indent: 17px; +} + +input.cbi-input-find { + background: url('../resources/cbi/find.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-reload { + background: url('../resources/cbi/reload.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-add, +input.cbi-button-add { + background: url('../resources/cbi/add.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-fieldadd, +input.cbi-button-fieldadd { + background: url(../resources/cbi/fieldadd.gif) no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-reset, +input.cbi-button-reset { + background: url('../resources/cbi/reset.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-save, +input.cbi-button-save { + background: url('../resources/cbi/save.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-apply, +input.cbi-button-apply { + background: url('../resources/cbi/apply.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-remove, +div.cbi-section-remove input { + background: url('../resources/cbi/remove.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +div.cbi-section-remove input { + border-bottom: none; +} + +textarea { + margin-left: -1px; + margin-bottom: 0.5em; +} + +form > div > input[type=submit], +form > div > input[type=reset] { + float: right; + margin-left: 0.5em; +} + +table td, +table th { + color: #000000; +} + +table.smalltext { + background: #f5f5f5; + color: #000000; + border-top: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + font-size: 90%; + width: 80%; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +table.smalltext tr:hover td { + background-color: #bbddee; + color: #000000; +} + +table.smalltext tr th { + padding: 0 0.25em; + border-left: 1px solid #666666; + text-align: left; +} + +table.smalltext tr td { + padding: 0 0.25em; + border-top: 1px solid #666666; + border-left: 1px solid #666666; +} + +table.cbi-section-table .cbi-rowstyle-1, +table.cbi-section-table .cbi-rowstyle-1 * { + background-color: #eeeeff; + color: #000000; +} + +.cbi-section .cbi-rowstyle-1 h3 { + background-color: #eeeeff; + color: #555555; +} + +.cbi-rowstyle-2 { + color: #000000; +} + +div.cbi-value { + clear: left; + vertical-align: middle; + padding-left: 0.25em; + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-value:hover { + background: #f8f8f8; + color: #000000; +} + +.cbi-value-title { + float: left; + width: 40%; + line-height: 1.8em; +} + +div.cbi-value-field { + width: 58%; + margin-left: 40%; + padding: 0.25em 0; +} + +div.cbi-value-description { + font-size: 90%; + display: inline; +} + +div.cbi-section-create { + clear: left; + white-space: nowrap; + vertical-align: top; +} + +div.cbi-tblsection-create { + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-section-create .cbi-button { + margin: 0.25em; +} + +input.cbi-section-create-name { + margin-right: -0.25em; +} + +div.cbi-map-descr { + margin-bottom: 1em; +} + +div.cbi-optionals { + padding: 0.25em; + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-section-remove { + float: right; +} + +.cbi-section-node { + clear: both; + border-top: 1px dotted #bbbbbb; + border-left: 1px dotted #bbbbbb; + border-right: 1px dotted #bbbbbb; + border-bottom: none; + padding-bottom: 0; +} + +.cbi-section-node table div { + padding-bottom: 0; + border-bottom: none; +} + +.cbi-section-node div.cbi-section-table-row { + margin: 0.25em; +} + +table.cbi-section-table { + width: 100%; + font-size: 95%; +} + +table.cbi-section-table th, +table.cbi-section-table td { + text-align: center; +} + +tr.cbi-section-table-descr th { + font-weight: normal; + font-size: 90%; +} + +td.cbi-section-table-optionals { + text-align: left !important; + padding-top: 1em; +} + +.cbi-value-helpicon img { + vertical-align: bottom; +} + +div.cbi-error { + font-size: 95%; + font-weight: bold; + color: #ff0000; + background-color: #ffffff; +} + +td.cbi-value-error { + border-color: red; +} + +.cbi-value-error input, +.cbi-value-error select { + color: red; + background-color: #ffcccc; +} + +.cbi-section-error { + color: red; + background-color: white; + font-size: 95%; + border: 1px dotted red; + margin: 3px; + padding: 3px; +} + +.right { + text-align: right; +} + +.luci { + position: fixed; + bottom: 0; + left: 0; + text-align: right; +} + +.luci a:link, +.luci a:visited { + background-color: transparent; + color: #666666; + text-decoration: none; + font-size: 70%; +} + +.inline { + display: inline; +} + +.error500 { + white-space: normal; + border: 1px dotted #ff0000; + background-color: #ffffff; + color: #000000; + padding: 0.5em; +} + +#memorybar { + width: 200px; + height: 8px; + border: 1px solid #bbb; + color: black; + background-color: red; +} + +#memfree, #membuffers, #memcached { + float: right; + border: 1px solid #bbb; + height: 6px; +} + +#memfree { + background-color: green; + color: black; +} + +#membuffers { + background-color: yellow; + color: black; +} + +#memcached { + background-color: #ffa500; + color: black; +} + +} diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/dashboard.css b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/dashboard.css new file mode 100644 index 0000000000..ba9691e5c5 --- /dev/null +++ b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/dashboard.css @@ -0,0 +1,99 @@ +@charset "utf-8"; + +@media all { + +div.dashicon { + float: left; +} + +div.dashicon a { + background-image: url(icons/default.png); + background-repeat: no-repeat; + background-position: top; + display: block; + width: 70px; + padding-top: 70px; + color: #000000; + text-decoration: none; + text-align: center; + margin: 2em; + font-weight: bold; +} + +div.di_network a { + background-image: url(icons/network.png); +} + +div.di_luci a { + background-image: url(icons/desktop.png); +} + +div.di_index a { + background-image: url(icons/overview.png); +} + +div.di_logout a { + background-image: url(icons/logout.png); +} + +div.di_freifunk a { + background-image: url(icons/freifunk.png); +} + +div.di_status a { + background-image: url(icons/status.png); +} + +div.di_system a { + background-image: url(icons/system.png); +} + +div.di_syslog a { + background-image: url(icons/shell.png); +} + +div.di_ntpc a { + background-image: url(icons/datetime.png); +} + +div.di_leds a { + background-image: url(icons/lightbulb.png); +} + +div.di_reboot a { + background-image: url(icons/restart.png); +} + +div.di_passwd a { + background-image: url(icons/login.png); +} + +div.di_statistics a { + background-image: url(icons/stats.png); +} + +div.di_packages a { + background-image: url(icons/package.png); +} + +div.di_sshkeys a { + background-image: url(icons/key.png); +} + +div.di_upgrade a { + background-image: url(icons/flash.png); +} + +div.di_services a { + background-image: url(icons/worker.png); +} + +div.di_backup a { + background-image: url(icons/switch.png); +} + +div.di_fstab a { + background-image: url(icons/harddisk.png); +} + +} \ No newline at end of file diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/header.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/header.png new file mode 100644 index 0000000000000000000000000000000000000000..5a7c9a10d99fa7b005f8ea3cec34fed279cf4d53 GIT binary patch literal 33244 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 W3tk86V&WM90000 + Copyright (C) 2007 Johann Ollivier Lapeyre + Copyright (C) 2007 Kenneth Wimer + Copyright (C) 2007 Nuno Fernades Pinheiro + Copyright (C) 2007 Riccardo Iaconelli + Copyright (C) 2007 David Miller + +and others + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library. If not, see . + +Clarification: + + The GNU Lesser General Public License or LGPL is written for + software libraries in the first place. We expressly want the LGPL to + be valid for this artwork library too. + + KDE Oxygen theme icons is a special kind of software library, it is an + artwork library, it's elements can be used in a Graphical User Interface, or + GUI. + + Source code, for this library means: + - where they exist, SVG; + - otherwise, if applicable, the multi-layered formats xcf or psd, or + otherwise png. + + The LGPL in some sections obliges you to make the files carry + notices. With images this is in some cases impossible or hardly useful. + + With this library a notice is placed at a prominent place in the directory + containing the elements. You may follow this practice. + + The exception in section 5 of the GNU Lesser General Public License covers + the use of elements of this art library in a GUI. + + kde-artists [at] kde.org diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/datetime.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/datetime.png new file mode 100644 index 0000000000000000000000000000000000000000..641653c07025465c8b090a2eff56f1557a26e88c GIT binary patch literal 5250 zcmV-|6n*Q7P)K~#9!&07hO9MyULW~OJR=iZsUFYT?>vEq=B5ID9aK!~Cw zVI+d61aRUwM>(;Jl#`e;RY^!C7|KxPB$XvG?uiy6T?)QKH@s4g;bX~`C$+~ZUPzB&l!nK5Y zLLH-c>?Dj9F;Xl~6J9&|)aD6XC1C(*bc@2tMKssAMDxKF7>HI+eFEfaY!Ou4Vrs5j_e2=g#=(i&jaKi7kqk`aeN$|LA zkZe}CoEGS?z-oag3k8h`fFK~1VG{C~O{$0!W@dAU#?`j~{528r;pdS6R=g9yKUyrf zx3*HYR0m~L2OS7iIMG1m+Ilyvk`0;#C=jxm4oxT3EjnyA8?!(JFf^nyL_(I7PvsFy z2m%m^Dwv99^~ve%^K{vFiHPB=OMt1k4ZuGUzFie`N{!Vn)K$r7sdZyRiwBKFK;8m` zl>(+_vq+|MND~ri1*)1CB*+dsoDK;t*$$V>K_26T&m%)ob>RV#Se8goF*%dPWF(8x zsZ2H!&3zxhqeMjEY7xN72LZg`bXd2w)O*lW>%xj!55Bz8hqj;-$EFha_1Q4`&qc_c zb662{q24be;3m%?B`XP>2PR`_gjvZ{4ii+4rxYTtnE8A<(R98V{Suin^!9*m7 zv8gmhCo?!Vp8DUMqU|LTVpo~~R(=hD{|N;goh=O>w33T&T^+>wCN~D+8N7LP9LGsms%X;mG(WMSjJTo&>LSU3r===@I?Wiq4US0~2tL0=dN-G&uSA#}Ibp|;9P zo}gefoW;mwnhC(UvD7L0+fE|k%#|X5mEX$BldJnWn>^@l@!_89LdX;}yxBXB|NEd1 zYa4v{quW-aKIr*vrAv-`dwWq^TZ>RI#C3y!k~ZPl4E7y3g8>SGriKc%H;2<#fN* zB4HxK1fXvu8J&n^_Yethebxl9@?8K9HB`HTT`PRp*zL!zwLu&WC-L(`1CaGRe(&ZE zwAcAd6tY+>qHdv|Arq4m@caA}_pZ6Nnx@T_g+gJDi2jKF^BiYSFLNAsl(4; znnt#kQ0CmwIe0x@R8>{YSrIVfoJCO;NLIk87?8M5BYUC6P&Wg@nodNusEdTMb zVf@8yE3svrP=3yetu3t>9UYyEd;S>;8et(x5;YdbWq=MrP%52**XM=RYK3H%!1BfJ zTKwgnFaFxw+mX-bO~uN|;PVC{Wl$9rU7cMe$&v9@wllK3-7Ccs$PKylrGz7PCZMEACDNIX}GmK_H1f1I%X;l)6F3c=XZajOe7Lzq|8f* z#xT#>CA%p1-q->ulf@?|MllslfQ{5p<3?T3xqIzH?{2z$576=b+K|)IKj~~ax!~{r6 zm4!Gi2g(VF#bTynnn{E}IT0nEFg!Ahfx!W^*ZR>Fa-wfALSB$YU8Rc&K*;CZvie)^ z^jtClx^CISOWK+cB^XLF)7dNrho zeXAc+iiYr19L)h)EM$z%Y}&L*Wb0fm2gxQuM`<1?p97fnWHKqPg=U^B$rmWS-WXzC zZkKp2cxkN`L|GGXp}WR|nOGVzBBHXwg`m#~pUb)fz&|Y61J-`)a6NR~81OmJStBC_ zV4B?P+9omNA)Cpvdx~R+!@(1kg=4-vi3!AJV^H&|dA|I5;~6C+asp%`3_=WC+gyPO zGEyX#LBJ=Wg1p!3wr}YE`Wv-NCV*7j<#pMt0gnTk1!C^xa#J;hL7EJegwrk|;B~;`qOCZ; z^p&NDfJN`-J-k&7F3czz(rOM3J{fMOG-r+Ks%m1n0+~z(M~)mpI-L@Wo9>mXc$R0l zbZHov?oFMI60xco^U&vYc~b-t1{s1lSWFVUE<37SHd-=gkjmuX^*F^Iq%7O7UorvI zheoHvh6cyL?-QL{*VBVFtJb0-PyrT>eclgX zx6iA2%D2`zXWOM`{eexk*fBokO1S`<9x(81`^EB!k>IDIJ z@3|Y#J@Xu|3g?vH|LT4b9_Pz_zk44)r^M<;81T=o=Mbl%H8vB4EES;Tk|^Zj^-nzU zM2fC+;XHZx;fF&oMWg#D0CJKJ)LU&javET@ifwCDd1cYzNF>4!6e~2J*C*Edre~BU zE~nFpj0s#{F2V?=8@llDH*~LVORn* zg&ric2NYN96t7~JhIew92r-fA>gwV}%c7nET})d=g1qU*n=v&N!3!__7pkf&p(rXO z$%e;k9|xu|C*wQD;dl6PzU-I(6F#R0UWW%BhZ~IqS(4$f*qKYfC0I z3*?2;sV_{=xbu!X@!0nsIMhTp;XMwe!j4x0+NFirz~%G!R>ItCCOstSa#Ful*?=oO}?lg2IX7IB&(w^bAx-c@B8x*oz2OkivF5WP-~siBfh@ zDM@7cJV8aKSaO{waCgZMkjHp&zSs)7xK1G*$>1=DK_ILs1>_WR{elG^*@5(I*0een zwE9AAN-{UE>HU5`x;nbV{@-tla#F*-r}vR!rpp?{ojFa5v3r`pZp$bzG_o`siWCr| z3YWTx;|C`3?6K$Oy)wL8Ta)NpV)zA}$dgK=IEp&ewCD zNhk;sRDwNVMdb}{C`?#Bk6hj?`CfW~`;8I;XjHNNG?iAgcru4%Rz;}7L!I^F#CROQ z1vfvqEL*I=Qd-}-WviGtiE~B=G??zI8OoRzR|yIsM+$I!XB0Ausv@l@MW~{lQN(#} z$L*OAx}KpiVa0GU0SzT$J^gRDO%MT}%qFs!jpv}K8mfXGoSjb3t87lm@$o_~KOYgr z9UXDjP@YTCIRV{JT!UJKBCKZ;Ae7H3NGXJz$|cvu-wgtcYs5V?<6Z^6e-XOz{L=jZ zI`=xQuGY^G0ka8}c3p$C6&^=4r6Ayv#6|rB{Wy8@BsOi_#QXQA;=uf~HS-+1uhGVQ zIG5rTI>+?9(_jK1V%@64rdc4u!3YV4ksyl+(XhOsIK%KPE}@~^1HfV_ycC_yV2Z3B zj%E<>yAUETc&l$(Jn3xTS!A~rTvqUal%!QfZ|jkOgtkFUhrqbZC;v-4W`?YH0NMzl4B#8+Og(5UdGTprgn z2IiCvhr_%n!XH1(mjoF+73NW-|qDUJEl`AZe3L)6q=r%rX8Wpi;e>PUZB6ff6*M^^Z82ZwCQnK z^@h#)OaDS-;JJGzlNognef5<&PCG5f&O{K4t7vTup|hn5C*uX|J2WJQ$ey)5%>JV8 z&#`H-m4(3N#5{Wy!|S7ba4-@gsgHzLS`$VJ?t<4o!QRhQvYZc;g58_GjX)IFdEGBX)hN4+0;gtC3DV>ai zCRt_-mgfM&lFL)i8=i29Ay7U#tjPmwzTW!4OHU?Jxqk^yC2kuTtFScJ2hczy@YkJH zAvfx41K=GdhN|$wL=zTI&blEbDzSj@wzrYZ7p=FowQ<4kDi>`(ao8cshMSc|Jxsz9 zW$-`lISJtQmIwZO+jK1T)X;EbT~(zQHPt>Mz$0E)2YfPoUMJil1SGIgJa!F}9_M@= zS;{!ivaIs}&H+nVMe$P{Mc5ftU;O5}Ky%N1UY~D^+v95UdtDZv&jkv=77Z&=JPVaX_h6&j>xYS zK+wtwxG*6Mt>_I|T!a*f3knj-GjmxCFTGway!yQV{`)!EfyMY#udlDKuxr<@Cpk(8 ziWQ#^;qMR`mt1Fs8HO0!@kYX&nVG@R&=4#CC|!2|z#v~H;Yv%n2V92b%kO1;gvIBL zRbw<7WwHu)-F4UBQ~65(rwDOst4X-}V#M%e)j7$*6n-Vo$&Z!iRie6g@7_nr1Kt2| zhLB+8%_R8wmnAQrWLajn=TRWFef#$Brc$YQ0rU})hVoZ~0An%qneY2oS6Acc(W8-V z+qOLd;2>dukT#URS_J5vnAlxEL*e`LR^2B%ckcXW0EdeSFQbzz`+uHZ!Z7F~T*D|H zTkzS5LKq=@LKr4w4dt&20p_|wDDJ%io~IGggg8Ob7g6&60aXr^&r;6@_W%F@07*qo IM6N<$g51#QkpKVy literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/default.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/default.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe97ae308fdf6b431eb3e92eb95851589a9df07 GIT binary patch literal 5022 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 oEsqiaLPi}MG{G#OQ4v=$ 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/flash.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/flash.png new file mode 100644 index 0000000000000000000000000000000000000000..7e9dc7861d1158a272920e0ca5c5e9bf0bcf969a GIT binary patch literal 5065 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/key.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/key.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebfaa43a42d4834cdcbde4716e37c09a55e8126 GIT binary patch literal 4129 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/lightbulb.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/lightbulb.png new file mode 100644 index 0000000000000000000000000000000000000000..3a6755bc3c404c33fa5980c62865ae5f3f4b1134 GIT binary patch literal 5550 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/login.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/login.png new file mode 100644 index 0000000000000000000000000000000000000000..8e881ba3b391eb6460206e8694a24325ef3a769d GIT binary patch literal 2918 zcmV-s3z_tZP))5xvchtv{H}~@jpa)oD!r+k>J1~mnc%CNL+FuLP>J~KS#}*xjscte(Jq-})p{7*C1VZ%c z=WHDSAOJYQ5LF{F7m6_eJ%5q_ZrBUkE*R}Xw&^;N76T2I=2MOB^z|4b`gK?`0EAp? z05Q&)V#w5A5kla55O^&JgAO%F!d^-$z+P=F{;ExbWwDUgbD}*AnZ0)G6&HWc?Et5omNXm zTm90iLJRUdjCHTzv?vmA z0=`=GmEx zcmN|KBas(S1R%`tT-_J#NoXhB@F5`^5K_r9I8hyx8zh}HB;eSwWAOO#V+?c#!Sg(t z95F*jQ}WvLq~YOV0zpXtfkGs(tfNxOeIX)PG&brxGc!YFl8D%}elnoFe*n5G<9d_;C zL(2xxY7-@$I>>mn%^{T%^2CRMT5W5m${;Z}NULBTS_mce=E2C$c>xar$c6w87vKmS zSuu@d#sx|)69Ayn1Yk`LX%{=Yj7a%k9du~X)Dl21RSq9M9K9g<%*XAd0=IA9hJk?r z6$(3QVM~0{jr3hO@_yAD4!(R~j81 zjco+y=jW9d$VB@As%fSrX~roBkx(csxX^>(zkrd>bG;EE74QT!J#Kn|erI>Fy#YN- z8^Mh90ulr{yk!Gan_%*K5}P5%wgGCuZW|z7lK?Xiid5j4;@@huVnu%RtmwH|mBh&g zfMo+{Zl*CzKmzo!k{noOnsJS~1W6b+;O5Pnl9Em|2A32~uS+^rIYAp>i?Ln>!}6*+ z7iS+F-{4kyJQ|sXz=tNke*QFZ}FpEeKl`5IpF9&7~)b$$Uj-w^?=7kGUyG z4;CS}cQ3Z35CGK|gy9A)8^E_&1#};pU>Z_`d%;N$f(U&ON;lMH`}LP9>uc6qWJOGa z;xJtO0dO<;e3q6ThjF3L|CnV1k}`r2TLN5Q=^U_B=Gm_+ET*;2(nX7DO>{+zHn~;m zVA+7pt~sIIAkz{MPZF3L=ashoR!6@@?z+aJ&N?X%z?fkJnB|%w={O+yq&qHh}aN-x3GCvqhjm)yH|kG>In1^_QWx^?Ro0YG~Td3bvA z1xP;+j*X2;#`F0+k^D5bTrSheuavyy00#cqaRv--+A0PiZi9Mb0T0oH4 z(`W7UGKG%74xc}N{+npj9^k!I>{~?_S37s^Tno04wrm8iUcEYkD>RLhn#M`JhWAcm zGZE=*5viakPdwS@f28BYxYB=V3&4!| zq-GQKI|v{MLZkrOYjESn4e732B$*>10Yz=pCk!wTVE_L8Ff}!W>VSP*7bPZ*YVicL zVFZTM#7YRF50BS3B&~0hF*c~Jw>|IYAH4tV9|1r}guL>8DnJZVn@R4KD_1`CJnsXq z)&ADco(e>+p{?GFAVx1W6L2aZBl7wCWxE27eEfIZlMHuX4 zP?rY_g;K6qD&$av2k~uj7F}VcSS)47#$Fj2du43AhKwyOFRxb1y3g*acu0fR{G?7w&>pTMh37 Qz5oCK07*qoM6N<$f<{9 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/logout.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..9f44fd0ef916610a15efbdf654beecced4e429ca GIT binary patch literal 3577 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/network.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/network.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8033452536c47cc213b637991c5847df7a9abf GIT binary patch literal 6602 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 IM6N<$g0J|yl>h($ literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/overview.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/overview.png new file mode 100644 index 0000000000000000000000000000000000000000..0f3edc162668a0943be97cd0ef27e7c020660950 GIT binary patch literal 4553 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 literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/services.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/services.png new file mode 100644 index 0000000000000000000000000000000000000000..54e17dd09f1f2dee8d619edcbd8326390852ac57 GIT binary patch literal 4630 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 M07*qoM6N<$f}0eNO#lD@ literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/shell.png b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/icons/shell.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2f3c17f81528ba01f5e9691bd00e2d3fba3ebf GIT binary patch literal 2110 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 M07*qoM6N<$f}0eNO#lD@ literal 0 HcmV?d00001 diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie6.css b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie6.css new file mode 100644 index 0000000000..1c951854b5 --- /dev/null +++ b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie6.css @@ -0,0 +1,77 @@ +/* obligatory IE6 Voodoo Code */ + +* html body { + padding-left: 50% !important; +} + +* html div#header { + margin-left: -100% !important; +} + +* html div#menubar { + margin-left: -100% !important; + width: 200% !important; +} + +* html ul.dropdowns li ul { + width: 10em; +} + +* html ul.dropdowns li li { + clear: both; + float: left; +} + +* html ul.dropdowns li li { + width: 100%; +} + +* html ul.dropdowns li li a { + height: 1%; +} + +* html div#maincontent { + margin-left: -80% !important; + width: 160% !important; +} + +* html div.cbi-value-description { + width: auto !important; +} + +* html div.cbi-value-field { + margin-left: 0 !important; + width: 100% !important; +} + +* html .cbi-input-text, +* html .cbi-input-user, +* html .cbi-input-select, +* html .cbi-input-password { + width: 50% !important; +} + +* html .cbi-input-user, +* html .cbi-input-password { + text-indent: 0 !important; + padding-left: 1.5em !important; +} + +* html .cbi-section legend { + background-color: #ffffff; + color: #555555; +} + +* html table.cbi-section-table td .cbi-input-text, +* html table.cbi-section-table td .cbi-input-select { + width: 100% !important; +} + +* html div.cbi-page-actions { + text-align: right !important; +} + +* html div.cbi-value-field input, +* html div.cbi-value-field select { + font-size: 90% !important; +} diff --git a/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie7.css b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie7.css new file mode 100644 index 0000000000..67ed9fb816 --- /dev/null +++ b/themes/openwrt.org-oxygen/htdocs/luci-static/openwrt.org-oxygen/ie7.css @@ -0,0 +1,20 @@ +div.cbi-value-field { + margin-left: 0 !important; +} + +.cbi-section legend { + background-color: #ffffff; + color: #555555; +} + +table.cbi-section-table td .cbi-input-text, +table.cbi-section-table td .cbi-input-select { + width: 95% !important; +} + +.cbi-input-user, +.cbi-input-password { + text-indent: 0 !important; + padding-left: 1.5em !important; + width: 18.5em !important; +} diff --git a/themes/openwrt.org-oxygen/ipkg/postinst b/themes/openwrt.org-oxygen/ipkg/postinst new file mode 100755 index 0000000000..e2a497b7d1 --- /dev/null +++ b/themes/openwrt.org-oxygen/ipkg/postinst @@ -0,0 +1,4 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + ( . /etc/uci-defaults/luci-theme-openwrt-oxygen ) && rm -f /etc/uci-defaults/luci-theme-openwrt-oxygen +} diff --git a/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/dashboard.htm b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/dashboard.htm new file mode 100644 index 0000000000..1e05575809 --- /dev/null +++ b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/dashboard.htm @@ -0,0 +1,46 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<% + local node = luci.dispatcher.context.requested + if node.nodes then +%> + +
+<% +end +%> \ No newline at end of file diff --git a/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/footer.htm b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/footer.htm new file mode 100644 index 0000000000..f8ea5ad577 --- /dev/null +++ b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/footer.htm @@ -0,0 +1,21 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +
+
+ +

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

+ + + diff --git a/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/header.htm b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/header.htm new file mode 100644 index 0000000000..a2c48b9f46 --- /dev/null +++ b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/header.htm @@ -0,0 +1,166 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<% +require("luci.sys") +local load1, load5, load15 = luci.sys.loadavg() +local request = require("luci.dispatcher").context.path +local category = request[1] +local tree = luci.dispatcher.node() +local cattree = category and luci.dispatcher.node(category) +local node = luci.dispatcher.context.dispatched +local disp = node +local hostname = luci.sys.hostname() + +local c = tree +for i,r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end +end + +require("luci.i18n").loadc("default") +require("luci.http").prepare_content("application/xhtml+xml") + +-%> + + + + + + + + + + + +<% if node and node.css then %> +<% end -%> + + + +<%=striptags( hostname .. ( (node and node.title) and ' - ' .. node.title or '')) %> - LuCI + + + + + + + + +
+<% if disp and disp.subindex then %><%+themes/openwrt.org-oxygen/dashboard%><% end %> diff --git a/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/indexer.htm b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/indexer.htm new file mode 100644 index 0000000000..8ba29e0f54 --- /dev/null +++ b/themes/openwrt.org-oxygen/luasrc/view/themes/openwrt.org-oxygen/indexer.htm @@ -0,0 +1,17 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<%+header%> +<%+themes/openwrt.org-oxygen/dashboard%> +<%+footer%> diff --git a/themes/openwrt.org-oxygen/root/etc/uci-defaults/luci-theme-openwrt-oxygen b/themes/openwrt.org-oxygen/root/etc/uci-defaults/luci-theme-openwrt-oxygen new file mode 100755 index 0000000000..6fc593f672 --- /dev/null +++ b/themes/openwrt.org-oxygen/root/etc/uci-defaults/luci-theme-openwrt-oxygen @@ -0,0 +1,6 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.OpenWrtOxygen=/luci-static/openwrt.org-oxygen + commit luci +EOF + diff --git a/themes/oxygen/Makefile b/themes/oxygen/Makefile new file mode 100644 index 0000000000..81a96f6a83 --- /dev/null +++ b/themes/oxygen/Makefile @@ -0,0 +1,2 @@ +include ../../build/config.mk +include ../../build/module.mk \ No newline at end of file diff --git a/themes/oxygen/htdocs/luci-static/oxygen/bg.png b/themes/oxygen/htdocs/luci-static/oxygen/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..cfcb575f8fa7754812d116c226711e06a6b5ee02 GIT binary patch literal 40400 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�O4k%UXqa2)QnL%wTI3 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

10D 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%0AEM4f&!17EkA3D5d>_59ymTFO-X^ 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 H2o?W7nrw|~ literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/cascade.css b/themes/oxygen/htdocs/luci-static/oxygen/cascade.css new file mode 100644 index 0000000000..585c9700a7 --- /dev/null +++ b/themes/oxygen/htdocs/luci-static/oxygen/cascade.css @@ -0,0 +1,664 @@ +@charset "utf-8"; + +@media all { + +html, body { + height: 100%; +} + +body { + font-family: Verdana, Arial, sans-serif; + font-size: 101%; + line-height: 100%; + background: #557788 url(bg.png) no-repeat; +} + +div#screen { + min-height: 100%; + background: url(footer.png) no-repeat bottom fixed; +} + +* { + margin: 0; + padding: 0; +} + +abbr, +acronym { + font-style: normal; + font-variant: normal; +} + +abbr[title], +acronym[title] { + border-bottom: 1px dotted; + cursor: help; +} + +a:link abbr[title], +a:visited abbr[title], +a:link acronym[title], +a:visited acronym[title] { + cursor: pointer; +} + +code { + font-family: monospace; + white-space: pre; +} + +#maincontent ul { + margin-left: 2em; +} + +.warning { + color: red; + background-color: white; + font-weight: bold; +} + +.clear { + clear: both; +} + +.skiplink, +.navigation, +.hidden { + position: absolute; + left: -1000px; + top: -1000px; + width: 0px; + height: 0px; + overflow: hidden; + display: inline; +} + +.error { + color: #ff0000; + background-color: white; +} + +#header { + min-height: 98px; + background-image: url(header.png); + background-repeat: no-repeat; + background-position: left center; + background-color: #557788; + color: #ffffff; + text-align: right; +} + +#header h1 { + padding: 1em 1em 0 1em; +} + +#header p { + padding: 0 1em 1em 1em; +} + +#header h1, +#header p { + font-size: 70%; + font-weight: normal; + line-height: 160%; + text-align: right; +} + +.menubar { + background: #000000; + background: rgba(0, 0, 0, 0.8); + color: #ffffff; + width: 80%; + font-size: 0.8em; + + margin: 0.5em auto; + + padding: 0.25em; + padding-left: 0.5em; + padding-right: 0.5em; + + border: 1px solid #000000; + border-radius: 0.8em; + -khtml-border-radius: 0.8em; + -moz-border-radius: 0.8em; + -webkit-border-radius:0.8em; + -opera-border-radius: 0.8em; +} + +.menubar .warning { + color: red; + background-color: #557788; +} + +html .menubar a:link, +html .menubar a:visited { + color: #ffffff; + text-decoration: none; + font-weight: bold; +} + +html .menubar a.menulink { + margin-left: 1em; +} + + +html .menubar a:link:hover, +html .menubar a:visited:hover, +html .menubar a:link:active, +html .menubar a:visited:active, +.menubar a:link:focus, +.menubar a:visited:focus { + background: #000000; + color: #ffff00; +} + +html .menubar a:link.active, +html .menubar a:visited.active, +html .menubar a:link.preactive, +html .menubar a:visited.preactive { + background: #000000; + color: #ffff00; + font-weight: bold; +} + +html .menubar a:link.warning, +html .menubar a:visited.warning { + background: #000000; + color: red; + font-weight: bold; +} + +.lang_de #submenu_admin_uci { + width: 12em; +} + +.lang_ru #submenu_admin_uci { + width: 11.5em; +} + +#maincontent { + clear: both; + width: 80%; + margin: 0 auto; + padding: 0.5em; + background: #f5f5f5; + background: rgba(245, 245, 245, 0.9); + color: #000000; + border-width: 1px solid #444444; + font-size: 80%; + + border-radius: 1em; + -khtml-border-radius: 1em; + -moz-border-radius: 1em; + -webkit-border-radius: 1em; + -opera-border-radius: 1em; +} + +#maincontent h2 { + margin: 0.25em 0 0.5em 0; + font-size: 150%; + font-weight: normal; +} + +#maincontent h3 { + margin: 0.5em 0; + font-size: 120%; + font-weight: normal; + text-decoration: underline; +} + +#maincontent p { + margin-bottom: 1em; +} + +textarea#syslog { + width: 98%; + min-height: 500px; + border: 3px solid #cccccc; + padding: 5px; + font-family: monospace; +} + +.cbi-section { + margin-bottom: 0.5em; + padding: 0.5em 1em; + border: 1px dotted #555555; + background-color: #ffffff; + background-color: rgba(255, 255, 255, 0.8); + color: #000000; +} + +.cbi-section legend { + font-size: 110%; + font-weight: bold; + height: 1em; + padding: 0 0.25em; + background-color: transparent; + color: #555555; +} + +*+html .cbi-section legend { + background-color: #ffffff; + background-color: rgba(255, 255, 255, 0.8); + color: #555555; +} + +* html .cbi-section legend { + background-color: #ffffff; + background-color: rgba(255, 255, 255, 0.8); + color: #555555; +} + +.cbi-section h2 { + margin: 0em 0 0.5em -0.5em !important; +} + +.cbi-section h3 { + height: 1.5em; + font-size: 90%; + background-color: #ffffff; + background-color: rgba(255, 255, 255, 0.8); + color: #555555; +} + +.cbi-section-descr { + margin-bottom: 0.5em; + font-size: 95%; +} + +.cbi-title-ref { + color: inherit; + text-decoration: none; + padding-right: 18px; + background: url('../resources/cbi/link.gif') no-repeat scroll right center; + background-color: inherit; +} + +ul.cbi-apply { + font-size: 90%; +} + +input[type=submit], +input[type=reset], +input[type=image] { + cursor: pointer; +} + + +select, +input, +textarea { + background: #eeeeee; + color: #000000; + border-width: 1px; + border-color: #000000; +} + +input[type=image] { + border: none; +} + +input:focus, +input:hover, +select:focus, +select:hover, +textarea:focus, +textarea:hover { + background-color: #ffffff; + color: #000000; +} + +select, +input[type=text], +input[type=password] { + width: 20em; +} + +td select, +td input[type=text], +td input[type=password] { + width: 99%; +} + +input.cbi-input-user { + background: url('../resources/cbi/user.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-password { + background: url('../resources/cbi/key.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-find { + background: url('../resources/cbi/find.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-reload { + background: url('../resources/cbi/reload.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; +} + +input.cbi-input-add, +input.cbi-button-add { + background: url('../resources/cbi/add.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-fieldadd, +input.cbi-button-fieldadd { + background: url(../resources/cbi/fieldadd.gif) no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-reset, +input.cbi-button-reset { + background: url('../resources/cbi/reset.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-save, +input.cbi-button-save { + background: url('../resources/cbi/save.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-apply, +input.cbi-button-apply { + background: url('../resources/cbi/apply.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +input.cbi-input-remove, +div.cbi-section-remove input { + background: url('../resources/cbi/remove.gif') no-repeat scroll 1px center; + background-color: inherit; + color: #000000; + padding-left: 17px; + padding-right: 1px; +} + +div.cbi-section-remove input { + border-bottom: none; +} + +textarea { + margin-left: -1px; + margin-bottom: 0.5em; +} + +form > div > input[type=submit], +form > div > input[type=reset] { + float: right; + margin-left: 0.5em; +} + +table.smalltext { + background: #f5f5f5; + color: #000000; + border-top: 1px solid #666666; + border-right: 1px solid #666666; + border-bottom: 1px solid #666666; + font-size: 90%; + width: 80%; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +table.smalltext tr:hover td { + background-color: #bbddee; + color: #000000; +} + +table.smalltext tr th { + padding: 0 0.25em; + border-left: 1px solid #666666; + text-align: left; +} + +table.smalltext tr td { + padding: 0 0.25em; + border-top: 1px solid #666666; + border-left: 1px solid #666666; +} + +table.cbi-section-table .cbi-rowstyle-1, +table.cbi-section-table .cbi-rowstyle-1 * { + background-color: #eeeeff; + color: #000000; +} + +.cbi-section .cbi-rowstyle-1 h3 { + background-color: #eeeeff; + color: #555555; +} + +.cbi-rowstyle-2 { +} + +div.cbi-value { + clear: left; + vertical-align: middle; + padding-left: 0.25em; + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-value:hover { + background: #f8f8f8; + color: #000000; +} + +.cbi-value-title { + float: left; + width: 40%; +} + +div.cbi-value-field { + width: 58%; + margin-left: 40%; + padding: 0.25em 0; +} + +div.cbi-value-description { + font-size: 90%; + display: inline; +} + +div.cbi-section-create { + clear: left; + white-space: nowrap; +} + +div.cbi-map-descr { + margin-bottom: 1em; +} + +div.cbi-optionals { + padding: 0.25em; + border-bottom: 1px dotted #bbbbbb; +} + +div.cbi-section-remove { + float: right; +} + +.cbi-section-node { + clear: both; + border-top: 1px dotted #bbbbbb; + border-left: 1px dotted #bbbbbb; + border-right: 1px dotted #bbbbbb; + border-bottom: none; + padding-bottom: 0; +} + +.cbi-section-node table div { + padding-bottom: 0; + border-bottom: none; +} + +.cbi-section-node div.cbi-section-table-row { + margin: 0.25em; +} + +table.cbi-section-table { + width: 100%; + font-size: 95%; +} + +table.cbi-section-table th, +table.cbi-section-table td { + text-align: center; +} + +tr.cbi-section-table-descr th { + font-weight: normal; + font-size: 90%; +} + +td.cbi-section-table-optionals { + text-align: left !important; + padding-top: 1em; +} + +.cbi-value-helpicon img { + vertical-align: bottom; +} + +div.cbi-error { + font-size: 95%; + font-weight: bold; + color: #ff0000; + background-color: #ffffff; +} + +td.cbi-value-error { + border-color: red; +} + +.cbi-value-error input, +.cbi-value-error select { + color: red; + background-color: #ffcccc; +} + +.cbi-section-error { + color: red; + background-color: white; + font-size: 95%; + border: 1px dotted red; + margin: 3px; + padding: 3px; +} + +.right { + text-align: right; +} + +.luci { + position: fixed; + bottom: 0; + left: 0; + text-align: right; + color: #ffffff; +} + +.luci a:link, +.luci a:visited { + background-color: transparent; + color: #ffffff; + text-decoration: none; + font-size: 70%; +} + +.inline { + display: inline; +} + +.error500 { + white-space: normal; + border: 1px dotted #ff0000; + background-color: #ffffff; + color: #000000; + padding: 0.5em; +} + +#memorybar { + width: 200px; + height: 8px; + border: 1px solid #bbb; + color: black; + background-color: red; +} + +#memfree, #membuffers, #memcached { + float: right; + border: 1px solid #bbb; + height: 6px; +} + +#memfree { + background-color: green; + color: black; +} + +#membuffers { + background-color: yellow; + color: black; +} + +#memcached { + background-color: #ffa500; + color: black; +} + + +/* obligatory IE6 Voodoo Code */ + +* html body { + padding-left: 50% !important; +} + +* html div#header { + margin-left: -100% !important; +} + +* html div.menubar { + margin-left: -100% !important; + width: 200% !important; +} + +* html div#maincontent { + margin-left: -80% !important; + width: 160% !important; +} + +* html div.cbi-value-description { + margin-left: 40%; +} + +} diff --git a/themes/oxygen/htdocs/luci-static/oxygen/dashboard.css b/themes/oxygen/htdocs/luci-static/oxygen/dashboard.css new file mode 100644 index 0000000000..ba9691e5c5 --- /dev/null +++ b/themes/oxygen/htdocs/luci-static/oxygen/dashboard.css @@ -0,0 +1,99 @@ +@charset "utf-8"; + +@media all { + +div.dashicon { + float: left; +} + +div.dashicon a { + background-image: url(icons/default.png); + background-repeat: no-repeat; + background-position: top; + display: block; + width: 70px; + padding-top: 70px; + color: #000000; + text-decoration: none; + text-align: center; + margin: 2em; + font-weight: bold; +} + +div.di_network a { + background-image: url(icons/network.png); +} + +div.di_luci a { + background-image: url(icons/desktop.png); +} + +div.di_index a { + background-image: url(icons/overview.png); +} + +div.di_logout a { + background-image: url(icons/logout.png); +} + +div.di_freifunk a { + background-image: url(icons/freifunk.png); +} + +div.di_status a { + background-image: url(icons/status.png); +} + +div.di_system a { + background-image: url(icons/system.png); +} + +div.di_syslog a { + background-image: url(icons/shell.png); +} + +div.di_ntpc a { + background-image: url(icons/datetime.png); +} + +div.di_leds a { + background-image: url(icons/lightbulb.png); +} + +div.di_reboot a { + background-image: url(icons/restart.png); +} + +div.di_passwd a { + background-image: url(icons/login.png); +} + +div.di_statistics a { + background-image: url(icons/stats.png); +} + +div.di_packages a { + background-image: url(icons/package.png); +} + +div.di_sshkeys a { + background-image: url(icons/key.png); +} + +div.di_upgrade a { + background-image: url(icons/flash.png); +} + +div.di_services a { + background-image: url(icons/worker.png); +} + +div.di_backup a { + background-image: url(icons/switch.png); +} + +div.di_fstab a { + background-image: url(icons/harddisk.png); +} + +} \ No newline at end of file diff --git a/themes/oxygen/htdocs/luci-static/oxygen/footer.png b/themes/oxygen/htdocs/luci-static/oxygen/footer.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0dc782c1cb29557386530b0f0e76ce255c74d2 GIT binary patch literal 61400 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 W3tk86V&WM90000 + Copyright (C) 2007 Johann Ollivier Lapeyre + Copyright (C) 2007 Kenneth Wimer + Copyright (C) 2007 Nuno Fernades Pinheiro + Copyright (C) 2007 Riccardo Iaconelli + Copyright (C) 2007 David Miller + +and others + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library. If not, see . + +Clarification: + + The GNU Lesser General Public License or LGPL is written for + software libraries in the first place. We expressly want the LGPL to + be valid for this artwork library too. + + KDE Oxygen theme icons is a special kind of software library, it is an + artwork library, it's elements can be used in a Graphical User Interface, or + GUI. + + Source code, for this library means: + - where they exist, SVG; + - otherwise, if applicable, the multi-layered formats xcf or psd, or + otherwise png. + + The LGPL in some sections obliges you to make the files carry + notices. With images this is in some cases impossible or hardly useful. + + With this library a notice is placed at a prominent place in the directory + containing the elements. You may follow this practice. + + The exception in section 5 of the GNU Lesser General Public License covers + the use of elements of this art library in a GUI. + + kde-artists [at] kde.org diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/datetime.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/datetime.png new file mode 100644 index 0000000000000000000000000000000000000000..641653c07025465c8b090a2eff56f1557a26e88c GIT binary patch literal 5250 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 IM6N<$g51#QkpKVy literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/default.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/default.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe97ae308fdf6b431eb3e92eb95851589a9df07 GIT binary patch literal 5022 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 oEsqiaLPi}MG{G#OQ4v=$ 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/flash.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/flash.png new file mode 100644 index 0000000000000000000000000000000000000000..7e9dc7861d1158a272920e0ca5c5e9bf0bcf969a GIT binary patch literal 5065 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/key.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/key.png new file mode 100644 index 0000000000000000000000000000000000000000..1ebfaa43a42d4834cdcbde4716e37c09a55e8126 GIT binary patch literal 4129 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/lightbulb.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/lightbulb.png new file mode 100644 index 0000000000000000000000000000000000000000..3a6755bc3c404c33fa5980c62865ae5f3f4b1134 GIT binary patch literal 5550 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/login.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/login.png new file mode 100644 index 0000000000000000000000000000000000000000..8e881ba3b391eb6460206e8694a24325ef3a769d GIT binary patch literal 2918 zcmV-s3z_tZP))5xvchtv{H}~@jpa)oD!r+k>J1~mnc%CNL+FuLP>J~KS#}*xjscte(Jq-})p{7*C1VZ%c z=WHDSAOJYQ5LF{F7m6_eJ%5q_ZrBUkE*R}Xw&^;N76T2I=2MOB^z|4b`gK?`0EAp? z05Q&)V#w5A5kla55O^&JgAO%F!d^-$z+P=F{;ExbWwDUgbD}*AnZ0)G6&HWc?Et5omNXm zTm90iLJRUdjCHTzv?vmA z0=`=GmEx zcmN|KBas(S1R%`tT-_J#NoXhB@F5`^5K_r9I8hyx8zh}HB;eSwWAOO#V+?c#!Sg(t z95F*jQ}WvLq~YOV0zpXtfkGs(tfNxOeIX)PG&brxGc!YFl8D%}elnoFe*n5G<9d_;C zL(2xxY7-@$I>>mn%^{T%^2CRMT5W5m${;Z}NULBTS_mce=E2C$c>xar$c6w87vKmS zSuu@d#sx|)69Ayn1Yk`LX%{=Yj7a%k9du~X)Dl21RSq9M9K9g<%*XAd0=IA9hJk?r z6$(3QVM~0{jr3hO@_yAD4!(R~j81 zjco+y=jW9d$VB@As%fSrX~roBkx(csxX^>(zkrd>bG;EE74QT!J#Kn|erI>Fy#YN- z8^Mh90ulr{yk!Gan_%*K5}P5%wgGCuZW|z7lK?Xiid5j4;@@huVnu%RtmwH|mBh&g zfMo+{Zl*CzKmzo!k{noOnsJS~1W6b+;O5Pnl9Em|2A32~uS+^rIYAp>i?Ln>!}6*+ z7iS+F-{4kyJQ|sXz=tNke*QFZ}FpEeKl`5IpF9&7~)b$$Uj-w^?=7kGUyG z4;CS}cQ3Z35CGK|gy9A)8^E_&1#};pU>Z_`d%;N$f(U&ON;lMH`}LP9>uc6qWJOGa z;xJtO0dO<;e3q6ThjF3L|CnV1k}`r2TLN5Q=^U_B=Gm_+ET*;2(nX7DO>{+zHn~;m zVA+7pt~sIIAkz{MPZF3L=ashoR!6@@?z+aJ&N?X%z?fkJnB|%w={O+yq&qHh}aN-x3GCvqhjm)yH|kG>In1^_QWx^?Ro0YG~Td3bvA z1xP;+j*X2;#`F0+k^D5bTrSheuavyy00#cqaRv--+A0PiZi9Mb0T0oH4 z(`W7UGKG%74xc}N{+npj9^k!I>{~?_S37s^Tno04wrm8iUcEYkD>RLhn#M`JhWAcm zGZE=*5viakPdwS@f28BYxYB=V3&4!| zq-GQKI|v{MLZkrOYjESn4e732B$*>10Yz=pCk!wTVE_L8Ff}!W>VSP*7bPZ*YVicL zVFZTM#7YRF50BS3B&~0hF*c~Jw>|IYAH4tV9|1r}guL>8DnJZVn@R4KD_1`CJnsXq z)&ADco(e>+p{?GFAVx1W6L2aZBl7wCWxE27eEfIZlMHuX4 zP?rY_g;K6qD&$av2k~uj7F}VcSS)47#$Fj2du43AhKwyOFRxb1y3g*acu0fR{G?7w&>pTMh37 Qz5oCK07*qoM6N<$f<{9 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/logout.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..9f44fd0ef916610a15efbdf654beecced4e429ca GIT binary patch literal 3577 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/network.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/network.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8033452536c47cc213b637991c5847df7a9abf GIT binary patch literal 6602 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 IM6N<$g0J|yl>h($ literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/overview.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/overview.png new file mode 100644 index 0000000000000000000000000000000000000000..0f3edc162668a0943be97cd0ef27e7c020660950 GIT binary patch literal 4553 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 literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/services.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/services.png new file mode 100644 index 0000000000000000000000000000000000000000..54e17dd09f1f2dee8d619edcbd8326390852ac57 GIT binary patch literal 4630 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 M07*qoM6N<$f}0eNO#lD@ literal 0 HcmV?d00001 diff --git a/themes/oxygen/htdocs/luci-static/oxygen/icons/shell.png b/themes/oxygen/htdocs/luci-static/oxygen/icons/shell.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2f3c17f81528ba01f5e9691bd00e2d3fba3ebf GIT binary patch literal 2110 zcmV-E2*LM>P)CRA zF|Jw@V^`Hh)6Z3t#vkCOYZc^61&v7+)QA=6#x$~_#^|sDYbyyK^TEt}J?Hu^=W*|y zcX=AQ5S?t2q)T^IZiiA121LE~3cFym3iiUddED&JU;%*POGJd9Ht zVWlYE!xhAohgssCn3kHaMQkMW%2iNVkV8x&{^Q{iq9X-B%x*z!xq0*E&mA2d`_t)k zl|LR}nJ`~juQQLem)Tb(RmDXNhO=y;4as2BcD{xRMpDWdiG%@N+5J zExZk_I!-)#yvo4G>ySYaJHqVjtl3nV7Nv|}G5zpu1T8Hs!Wz`z9y3XAZf*{a9618b zJDZ`od52lD^hY16QmIQVd8juIG@55FP{!az7+73fgoT9#=$gr7ALDm&AzM6DZ7pwDX2z6DqSb{8-+?^-kl z#tQGh&59T$a8GVBf*uI9l$gzC!wG;v)t175e|22X9~rbPE}#^V8YQgebwYbwV4gx- z0F{I7oguv6Bj)Yu2`-n*NknFeI)%6Z2`sD&*n<{?_IraHh-mMSsS-- zL^Ge0U!R2CZMz|YA48(b>(Gv8+UZmplF1aLGa1Nw+V*{^C75#G;>7?4%>`(&t*xza z{P5*iux#E5z{LxStU|yzHhf8ZZ1j;hz4f?c7c)6QDkTZ-hAUN zIC{k2x?EBEUTtRU0LR0>k5G%;`1oLj&Suv9_N1eY%l!}aUe;owIHVc))e z(9!WWw72hu`&0L!yQdo-KYAp!9V&wmn5Dqmp<+VRo(0$qmX?>Gr?&^b|M3Ty{9{7& z+w<-oIQ7dZOZsyS=`YCdy)i75(#HUE>U+L9S;?fSje?~_Eocc0+%XyazI0i@z7OD) zaA2#BSHt1Y4?}0?dvwMI1c^if`UZNj-7Waek1NV024FF}@;qmM^6{t8)pY_??+k@7o>KdCGbl(qg z_)(JEVbGREXxp!oc`u`ezsTbP+{Z0t`eVMV7NDHdyP?njlF1}7s4%UcB!ktG+>!;s zXkcfSL5QGbOMO;LqNcJCfX<^mZxfnCW>0+*O9plU=o(|N=k3Dp{7P>D+)+_pD2)Xk zdU8X6C6$8(SkL{rza0Bqpl2M;SB0a)_(I@4bPhaY8=1$eE6Jo8(Z6_rg8Bs6Q( zym+hM+Ydj=%mu2ds*GCWQb-ptTT)4ZpLW>=K&Lw9?Q0=BK(iD|mi}U~Sh#(_-%p>~ zf|m6iBKz5YvE6{*6hjDiCiv{%XE6TzI5ajjvUcsS!7J^y2s$z{0!>X#aP8VPjmmZ! zPveNvI60r3Uw)te`|sSj16#LlU8Q&L-i3yS2BLIL&npF;oSY;Y&INGNU+e4Z8!SPu z+ykIQbw4oQ)zx(@p9?sMSqxT#_#pH^4T9gCsLTxMLP4-*3vGoaR)7@_!K>7(@1 ze=L#00Qnp7=<&MdS7X&!eg(13vxF_|9u@J+G1p^y(bN1i;wiTSj@ggEChT!&ay zVFJi8kAgaW3m_&pA=Z=jsa&DI8%%pvus~%O!T-zAsHgQ9n|~zID zC5tNm0un-~s;IhxNNg$)?S@j~l!gQn;y59}aqO9~XU6lmkKXUNpL(j}c~o{nDf7iA z=iD>r_5056_dAb!(MKPB^wCEjef05dg=fVh00xxze~bh`9Y6&@9AFJoAAb1ZKelb# zwiRN;^I#)M5)*oZ+eRG6?S2<}?vMHIv)b#9uTnhv=%a@L%!`06TT>JY1$&@sR2?w3 zJ7efPI9FhmQT?6;?M_s8VwJyZ*RE}xbejN=g8RO&#+cRsyAD8*U>(qwObd2f8iyl@ zP3C`#X0vHT;0wv#nC8 zWYV=-4WEDhIo^5a9ZXG4L4wcD&f>1S?!x8EmvQ&qcZ&>1c$VYumo8nxo;`b5j&iyL z*t4C4AX(R4Nsd9-JINwNyh`50TI3p?s06cyMqK zqobovK8fbwuUxr;n>TMF3`0H}VhIw$aulB96bURNS(s)yrY~N+Na01s`WnDa7;M30 z1`1R~4U{#5e1K;0-&&*JN?{4fK!Uhpw88$(CPKk}=8V%z zyJYH_vvKX(HTe&bC86b0XfDj7Epx1#UFOqFIJ0bz!l_*fYc$v{_t;~PnfB}Tx=Vlt zB@(ELw!>r02IT{4xfO&-h{2U%#|IQgZWwY#%L(&26OIpH`z%kpn{e;F_fj5?#UVhBkAu}< zG*}7m*m)~%B18+hXwVU^k*p%|RMr)o1EPR*fcAbvfq4w}K0)G{q( z?=*p+&?1Lz34!HgG~-$BLu)0vk>Qn{6LLRlL zGW_Kt7Iw~J-|S&5Vjh|0JeIQ8kv}_$*&Q<|%xuTv!He*k0laHfBvUOU+<_-BB$t{+ zcsU?i(#)>q+de>KNK-%f-~*PGCeaBpwr8Ef)9IN#g?!p;uf2wS`}Tow2++){VY569 z=8ZFJh7BY`F)*AUoL^Hzgg{Wwp*mg0`1$RqZ7JjC^koeGIaTvZ%cx%}BOFVBeGO#K zO#)*P;>j4;AHv_2z-#%)`0yPIYE*R)K3ME5I4EL1Ae$>D)9>7PiK%T z7O=9ti29#0Sn{vHTUoPV@5%^*Lm33Ml*nd?%)S= zYvk8Q8>kek(f|sgw8kcXpmp6m3j$4+`x2!I`LT9q0mliN##{jB2;dHkwrD#jc93LZV;1GcvhfqRoH0AC zk&zLMuZ&}0OBS{54Ilz^;F06YBa77?4W{**?d)tPs5;tzP{o<sjSUDSfJAZUMkk}0(oAqSH#t0kn^zaLT#*=)Z=UC3M^OD{Ibhb|X;670 zK?8SY*4AMA__dk$$Rtjjfw;oB zX~k_If6-30o!cXs3N=%!8jr$^1!o^Xq16}#Wo0r=)#nC?s;QHoVx1Q0FIZlKV365p z*-{^hIT#YmG|5*?2gg`}ZEBL*sJ6^RWkrsN<@h;HY69DF36QsyioX2omk~xG0za^4 zs@FS03DfTGPxjr*O|a^AQf(fRWWEB4q)a+d%2YdFh-d&yl_k9K(HnU3z?0a!b+7Ur z`?O;TrmM9sSL`ZdFTHkq&MmUQt1(Mkb<0DQcL-29k;5_!>k`05Y@zCfI^JD;7l+D+ zaP+{@PR@#I?FcSNSgVec)*!n%M(zFW!w>6erXfPza*Eeq1!SYz4o7i>`PMwPPHx5f zrS~!W(JY>Q@L2?zK*FdjZAu-rzkziH>L_dnaQSou({q<{@)a%tHaiSR|88a%QEU{E zOLCZBp2v;9+`tQuynt*bE5Yr?ItkOOy>}x-GwW!So;#FNzuk|+My-Mj=5li=c|~|7 z55Zi3@$D1ZOfcAcaRx^?4XgvYk|0e{n%?}-p+m61Jf|P7Fm1}YX93$z1&{xxJos53 z*GbsV5aC?!+1gwl(j{^q|BI_mp}|{U#WV#8|E(Y(NiQXMR3!m?OT?q}w~7D?POq%HM6*Nty5QsXK}Xbt z+f<&walQb(xq6Sj%4ziLY$qO&N^wRZjk`Le&)i2{Xe$u?qOfra&LBiXfsHQ`gV)GqR znmpV}vWSrZ;znAo&focNfM)W00Kfa%2snQH`1jL|%G2l_yn24n{=h1Xcmz!l*&jnO zFIN07QsM}H(n`~&jM0#fKmPa^ue|cg5p;$wZm+%g;)^FY)db#p>#Y;%?(H}0eI~PB z9tGr`0pBb^Qc;Er2 zLtB;YK-)fj`n2BRZwPFk7oPU_io`no>KouqHvztP(~HQC$4vVhB7V8WWp0CD8|xUJBY<9nZ)`+Y@-Q5HNAB>4^46K`&&3?edgv5j>C{z|jWD^$3x>~GI5K5t?^!B{M}D7=dHKi+I-)A_mzgjVf6R+V~QY+IWf15 z8#lfUV90cfh^7!szt12kC@Cpf!sHnjFJ8pLg$t8@WH2Y@#vDnSNCt^|G~NQz*zeQR z(=%hS7zlgxF&NA(F19)1gWwG-a7Uw2+(0A}!GZ+~l774~p(Z!C$yG^A zgOdB@U<-V5(vJyn2-n0km`HfpvSrB3%tTR95u8pZk`cPD$xRu;gsPTvj0NQ){A#G|aNOd>25O>#UH7pSeR#qs0EF^RzU&K#J_tt}wY zY)r@u$D%P9iXlHRYt}5h`s%CDoNoN<`xYGiM;*XsmgmFDpFM&{AAJ|&xox7&^U{Cr%$eqC;OY-|jS!NI{haRK3Ae!ra< zAS0j5!Z##0w`0c+oW9(JzkYHYPL~sZDldb}>A>MLU3mMGb9ic5K3;zLWxV_DyJ%}` zLmW7mvMCDr<;#}~(NHKP*C{M4L`Fu2oa6WV*>9zYVSM}Tw|A-lz6Q%}D8RA+&ZRP& zTefUL<@px8`N1hXu=D}U%}zs955iDgNcU=(H-8?E)sG<>Ys02Zo3MTRcEqEiqJoG2 ziPWi6r*P-6CXsM^3a|o5M8+qcSPekMu6-=m^;SVtffCGxpBIzMP&LN=ot!;$?NdALU?LvHp+_ACD-me z(t^I>Fs^itVsKPPZR?Pn^V#R0{}2mua&iz11W8Fz_IEiiB_%~%A}==&LqkJSZ(JX` zF5A6cF9Kr$1Vcf1+#aN+rSdTnlQO4e%Jx{v`)RV266_XP3N6@>_g z!f?4E~g7=zBCE6H8nNNfrBjv(%a7h27SbbB2gK2iUp&=7`#3p z9Epka4F#kI7z;&+yo#s-=ys^XFV=9J6(#*JH->Mrp<5r&M4jVu7kp;4$Vr=+#wyflP@UGSv&`A3xiw~RQ zcgX8Jk(K7eaLj;C#Ms25WSSw}5UVID z@L}oPEWH2zK@5@~62!L`FIo)Ep&=_v%o?)`XLD+lS=BTr8XK>|>+zz#z8*g&6#gix z9R-L5h#Wd}2&-4G#vgt;4}aWu4Skr76?0NhlA}q%vi{*Lyz@mHoSK3^|7HP#!2tH} z-%sR}AC}d7_wGdkh;-w)UECiN;tsYf0EWzL#4Ln%?b?N{Teo88Is?0iY*TjxpPh~1 zi}M4}Gz|-LUHIFEMOajrj_1pthw4x<2_UntsCG(WGj))N0vfJ1fO=}8g!l9OIM+Ok z3+-cM-U=R?@5AeBegYU#l$V#w%&O{SQGfzfQEdc41zbe13-HOZy}scJ&F*t}=2vT^ zU-0;Y#X_{XxfvgQxEBWwej zMV0h1p$p8XHTw(YFCdL7yWQ`-hjZs@Fc~2nR2x}974qXNVC|ZkIe z8HKaJ1~x{eZjfd$=by(BBhwvgXh7^*BMdg_>C+LQ{oLFzA=|&M`UW@9)ZBzyK$;@A zLMvI^L>NZ{_OgJOj#URp2PW+I!641+aVR5bhFjkAQDXW^$O6n*cs0{t;JV?1=vj**6h{g{>^0+>{2TPgh;@Jsy0b z4C>caSbFqJbR9d2Fzs7>_$Vq@twMxcqqVzRj!g_iIXSuVY@mUxrEpdu_wppzWoBe@ zA5e}-PtU-2-&JG9@)c-mYJ%J2Vc+J?l8_i38AT4cM-^F9X=$kh)oIhRIDpc*ew;XQ zVuDim&SL;WT35eV|11W+IgJ+T5h(AxNm1B==FQs?q*)J?K8y}(d3#g5iFSn;kr*PP z^o$-Yt<7>%@_>Y_Nss8_zk#ta4sx`gnymf3(ilzgrbuMZ$jm@D#e}dP;zb(w`NRS` zNs-i1A}jKn_xWSRfP^f-aJgMLak&nUlM>Es-+>tl;28vlwrz*&XyndrVq6g7jGCIWh(~X4@3_|$4yw&Gm}mkHO+)pWvnc-c zdKA6*A_l4JBmY~oZXM1qEXLJ}3T|JIdlM^HtmG)pJ}+?~GjkeslSXm+^l3cy*eVPV zvG(>hq*DxWOG+DJ3y^-K#0dM9ki9ghOi&5>h`@*YKF0d>>+r~P8>MhLeW?zIKiDHJ z>G9xD9nff&ySlsN`2K-@DPBfM9GZj4bKSr`PNY*zj}PGBfeL6uD5UH1kaGe^U*Y7*6E~S~C#+O==FE36ArCbK*0Fb_09CP@1;lqO z4@iX9>$bjYZcI`L2i0~z!2G~KQbLiB%`~V${Dz}*GXIN=+0?c3Y>>{<^@y~^lNh1| z1OGh;8Z7Y&*t}^orVu2ZG7|Vsm<4!wdRM+NVz32FaTpURAVLzp3tpoOGuK1~L`gH$!3dY!R!po(UgqDO-l1t!1Vh0+kR{g_G^CM}hs%mOz zRYm+OiK-@2RcJ`l$B#y(p?RpZ3RMZT0j1m;f_cP1fgsxf41SJZ^PY3|zO(nt*38j9 zV|(00b#$}FpZ7jz&Y1IkYpuQ3**5sp{+}B`4r_b>s9XqIVgiu_2xlOlC}I@c=LVl} z0V7wydXLUjfO~*di(wQN!VQ7~H+6eVmY|#hgh0GNAm@M@JO< zKRxG}Q4XnNuFl&=`<#m#zWuglGCbZFiN?awa2SabmtdhYhX9KF1Iyr|9#`>gpI!f` z%UAqFcc6FK>FcNbgm4%Xpd<+j$GL>VoTNeR!ez`(Sdw8pJt{DLu11Tc=2q4@O5A8| zX^Y%h*?ch`9{=UJcYpi38I4aK?Sh#tf(u!;^7Ak#ca?0~vh%q`^`H6XjqzT%u35Mg zcn^jmn*~Zzqf5>8_tlvByb?o2i6RU;F)JH9JzAN$Y1xUZYt=b}5-hH5@-41ia!-9} z!^>{3Z$-zU-OnUBPMqq5r3rBRJs<@P-qIy&A6?eC@|z1P=A*Kx3QKBMVB6hK!9`v8 zj~mwxa~k6eMFmAD^7;^p2hmV{=Tm>GtUFm5xb=r5*T~IIaGL;iEg&%A^A?pqabxTz zD*aWU+>O4GYclCRiAF%sT-}VA8OQMCC|tg>Ct=?DbCPRR6Tnjn!h`VjjD5K5L~jRb zi)xb}8o?*suJm6)%e)pGy>bjgp}?{d4quY%n3e)G4nhcAr>}Pwp1#qE)s1Vw7(+f5 z919{5OQ5)-7%sO9bHx&70-e2`7>|zo?<8;uu9^VM1Yp77>3R}390C*lcopXdfA z0GHuHPrL`!pQ%Re9krMX#yEr5@Je2m1p~yP3M8T+)B~c@-Ly>1AoZokZ=Je@dl%k| z#fuli<#J(oco-*6oxsHC1PV(F=Yjy~31CqW7IlaKD=v?yO@JAYA3igT2fy$jmM&ci z!!Tsp6c-nxw6qi*JspU$=$sIMq&YJND!A$?U;%_>3Ba@n(87N7>?qc+S}(~{N+o%b zLc+?*%CM+u5jqDt@t-!8)?g_CnB^bu7Ug*X8+q!cc=P=?5sU>f2TVOZNiYkP!9jp@lu)Eh3tcm2 zB6cZ;hgUzWg}s6xPuv8roqY{M;UOrSYbn5)lK?(|B|x+YNPFJAY@+pxt;+L?yc%T% zATEOar}twpG>AE4Dg`)E5kR=lNdOaIdIU)F`~!}*FScpqvk{Jkap2qm^iTHBV)KH4 z5b|*fke;MC3a(C_AR&gW3dpdh-4vU@w0SD>^4!Iqi@1LLIzpqNG%Kjus~tOqsOdG~ zZSulj?f>XgK+xtk0f-&}766jn2`1pW=0@9>q~}$WVNFnX~``3+F8qR0>c+5o0kF6civHkLU8f zA~Gdm08Ym$al8g&toDsfnrZFVzJnC z-WQP~FjD~(w4ZUT_m~vGnY@M>@1&^+U;wo|ngD7wP745vxD~^mV|&oPt{rZdTNA27ctDoLr@VQxaujuqzE+S-BiP)+Trd%H=cX@Is9<_57ok`t?2XS&BNF3{~Gok-iN*g zeIP!26O@@t%-l?%w!0QAso-gjY}yo{2!uw!DV4dcMA&s`7j|ykDMd&m5?UD(Wpf+dhF9Kx z1=ki_11ThSuV;|kxIGH$%sM>L_5_wJSt9SnG)*jDz8qC=SD~Nu!!yr=3%4%dt**Dw zJacauR;*gO zN~WJO;edwv27Gw&L+n1f8z%!NmA4(&gA%VFEX)vz#8Akw4<@dKyJ6a&1(@KGSp*3I z5>^5up%DoHav?lFcpg_ruVVkU{jx+_mSt;ig$Tl1-$=fGarqY*EgTi%$lYQI>VmqS z6Iq{A&jQR8ka;^4AHwA1q$IUw{u)W1F=ne8qVs&T^-<}B=ewTAfNvnP7Fe*E>{US1 z|0am75pr5l<>d~)(oOJ$4E>J24s3p9Gv4~fTPSu*5wtZy>=`TyFT%5zo&_-otgIKv z6lG0;rEsA80KUHX>u@l+@w(-qEmDLRx?Zr0klpUe`*N-r6q?BoBtf++C5+Vg{?Pk) zWZxqQnn9WW%9IFRuNRe7m53sW2#+96;;^VCB+tMQkaO+4!fRJw!|yKr4l31PHyH_= zH*H3HOFL@9HMZ)b%n<2m=QF(k1||B+P1Tsfx#4qY`$L-$L4>KgNg;?#mxI?2+Q`5) z3mCxTM;^zkS6)>=Uo~U4NO)x9BY1l0(>4+85kO`x03kNT6lo1ggw{7&(I4&?i<5vP zzq@NU4&FGZ5ua8JLxYT*#|}S+S1-S++HLItt)!#`53he1-(C9MlnBIL1!xWdT#l+x zBA}BeIYbDY!-{L>xu0UdE7kEAYSi&-R?!I&87JV{3x0zg29d4 z4?0YZcI+J3iK4AVSl77D76qzGh&>6hFp6^eLT7SeEEt$Y1Q4Q9KoQl5PZJq>C{xHA zyzk~evFMgwvy($oS%kY^u2D5f=%UwXVZ@gDLtNnSxG z@9cd=UiBkqZ*+=?&PxCZ5X{1IN5iw-&!Q*NlaKe+^Mz=%MD&P0LmaE9(6-|QaYbHy zX3x<*xOD4ZAbD2->gdsb%Ld{DSb1V4zP;ev_*}{7;HBQ2dwra7FpI%TNbk#IZl%su z(JI{Kze|aug}x&HvtvKQjyHE;b^V>71bGOc7Qv6f0*L^A)cd1Mzd+JWk7?CI=lCA%__H9dsv4O^1kitjG}oZFxyTZMYa(cZ)Za*v-*Ep1(ei3}FXoc`Klfn! z!R;EK{31YrklB#cp@4)-V#i-)*lVB! z`3Yc15vK7hrVxZ_q;+po2LYHK37h+2jRmVZXO?FLoT-Ae?Ks#O#r@;YR5G}8!B{f|;ik#i1l zEzEV#JCn5S3+m!#gt%$lgx~KMy?`KYBmdHwm$3cF_KfFQ?n=WYw<-1n2?ZyFuwq{! zVkS^l;B&fhea@zVmAj_Ha+q6o{N{t-V1iGesHjNoILY5ZzI65_v>#~~p0`&Jrl)Fo zl2bTt!Q-L;0TWy`0k{F4v{*w`ZQSplhtJQy10KVeE#cfSrxHXvmVa%w;V&ET$L>F3 zC_048W0&!rzkLVa``h<&k++>IaC@*a$z?K1;4d)Z;D`yXS_&`*%K%2f5eL=O8=pFCDV@LkSCa}S1mY4OB5}>-Y7~i_@ ze*Eu+ei#M=C1wwRQNdLcU=*-!0|p0&2H&i&YIx?x#3Xzn;HkUUg0U#5K^=a{se=Q~ z*Fm4_=0r%FI|KT&1SJJH-gOhhlOe>-aqu{Qg8+kqtK;odw8BdW?kcJ&+|^LGU`v6g z5F?XAxH)nSnrU_1nGEL+m+1d3?jtw1%Y%yI+hhe84~-!l3jGN|?BpCD1P&sWDfw9z zDF7=hLnskSoC$=6$3`O~)sc9p#AKF{7kNk0&SG%>@%?RJBo>KJhQ_ZZ!ts|$7`p-V z1g;^9!Kngr8AwGVJQOGcM>T+Q0A88BpDbelVlul41{p9G=tUe|;FwWHZUikSsogvm y1L0N@9CP1PFJpk4RFbtuIV>Ck!>9JCY4(4WE%s&!;H+@~0000k+MzI@>U9l_JKm-dQVxdS!=_nnPa_8T3IK0K;JuCR$`|n!gMegPM?(AuM zX3iBv^#4xqD5a!yQ7L%sL$CG!QSmYmZHNw}GNhW4Dv(N$3XpOP#)km$wi}d{&kD`| zA;rtHvI`e3wA!&_$CeW(PI%tB<(lE{;hu8a{dV-NTep0jot<}V+_FDhSo+_-VpfBp4Wn#Uav3JnXTh{ys~zI{7AJ3E`Qb8_g-n>Q36A5Zu0-;ZClYSmx{=syjD za{G#%I(0Jn^UpuyJiR0QOQe6PEMxG%uGBdX|7(qnl^Lh z%*(h&O-Q-70l)~?gj>BVtb9^(GHwz>&!eK~_=yv*@Sb`q221@1t*;HK4+FSey>^vd zo2|~)mWsbhdPONI$&`|sLKztul$e-EP&#|@;>B4*h75@Va3>H3{c(-D5Uqdr*@e1E zgN++EJz~WfgyfWze<~jq5kW4uZqcw|!?zb8$rt($S-(oNX3f6dx^-)ANJwzL@^P`O zsI+uidYZI$NJxn0x8HutnlookCOr8`y?XWb<8S9det@)9VO*B4`!)ddkn{%MyLT@q zMJfLR%7;Vw$4{SIq++G_Q8C@w|y7Wr?%`~NWXGn8tG?l~N6#_LN=CfzdJ{1xcmalwdBt3!h zuCV?UCnv<+3+iiWmDs#_b4FB$LHNw>Ujg#f+_`hzot>R1Dmsed5%aHJy`r?VRLaWA zlFH}h<&lSnM}ktkFQgr$kf} zxM>I`S|f;iji48fj79BRUrnDVOG}G#}6JllzHy_1$y}C5d{VXQCwV{L_IY%m4=TT zeYsk-Y7IXZ29ickH-vUX!QTL!O?VNI-F%bmWbP3>$vEL4yWOBnXN%mT>&n9X4#3-GKuK zC^#gD!1iPaB%<6Q`?DuVdHL!k`S|#x6at{kyZVQs?6&9|%BhPqR!L->g@whzQDeua zJ$UedLEsX^B}W1=VBp|8NR0X%Yb6B&UqhAKrZZ;DxNzaZdGhx5qO)huavqSL7@rW& zB!>Z!RUryF%f`lLA%j*l;T3qe(oI{6@{)J;0&LY5>HC4#Ln6$r;Kr4d!QN zg|Z(A4h}+Z;6q!sZl+(CF1}K=YSl)nL#$zKZEdz^&rX+AU24Itm3&d&I{Yd7Brl*k7@J`4g9QmQORqehPnoiu5Z8G}%q21)_13+}(+=&_@8 z=Im*@d-pCqdh`g&hH@VuIYDG(I6Vt`MuC9=h~ z;-w3IK0XgLuCA_h?AS3{zhQk2n!U4%ALy{5KeP?~LZQ|fGS%3`>^?UkzP`T5&|qfZ z;Oq$#Crx<)HrDl1vT?!v)V=gUXYZXnd7Q3Yze-P@JYnT!Z{qXt0j*eVM|bbtrKf&R z=<$=sXxx0|@13tY(f$K_X~V|#blUMWhlk8t=g*&~UAuPCl3y2Pwrttbmakt>!9FG~ zE3joC=8(x9O-$U75G7fP1_&|unRCMQ88hRTELqa$Q$Q%7zm+Og>ICBdW!1@ z2M5!UW5;Rvs?{{db}sd_>_`8YIRln|3QzPVFKpNSi<}(i&a+Lj zx3~X}bI1qu4n?a_-3b#WtT}n=B;CI4Ms{m|qah=P)BeBq!qN}vvhzh+v}6(K*4Ja} zqFcR7ckX(iOx^}-bwT5HjCSn!6Xfj*xx2g5sZ*zD+qP}Ac*){Cb93`UxPB+q8y!!_>_b2=BeN4x|OhPsGieH<0Ke zXs+#i>fXC2+5fhhJiYHyNLUcr*{`G~O&ZhBKmUwAz-zSscwm-L$BXYpeqep4OhV?Xcs!gu0uI>sIzBLPXhWt-)K==~U z0W!+au>DblKn{{4h)N;_K6{3ch$07vUD@d8r^_2F5Z+R4s(^HLL+cwIfXt4TSCTD$ zm|Juv6EhRqxOp8Y@e_dHMO(LRAtU3Cv}ey=I(7OaZQrq-Hf`QSYwYa^_apnY_O$hn zE%f80A9Gu@Xu<8V6{Jzo=}>VQo0d|{5Hj4rpzQ&;Z8j_iiuwvkDnMrM3l}ft+Adfy zUjn9>T2bXOj_cvz;1GxR^JGW%9eBvRf-aS6d|88RrcI`RKtEO(p)rqsp1**zJwVtE zH(yQ5mMx|E^KI#;Su<(cv}u}=BS*dgpE!)`4~DcXXyuDi;gSHMhGLCFTC{Ar3*Fmm z^z7j5Nn9mhwE!-e8XKEwD^%!c7ow+CzsCcyngsATk8t=%0Qmoy{?Z?R{6TsR8dBT# z?P%bTp|ozp2Eu%hHg4QND^{+6((^H|m_<{kO@+Hpr72UU(0~EoM^>p)Wi75hNcA_> zisYhV15h-6tE(Fg!pvaXrAwDHxFRqRk5P^uf-`W%m~3OSi3c5uFx3Eq9D_2I#x)z^ z12(sXtgZXQeYeu-)2Af>D2cRm=~6;cC4`79X`so3Spi|@N7JWI&mKR1d;%!B7h-)E zuDg({6r?w#MN#F80#K45R8y`t03dAIzTF`WmXvJq(c>p{|Nebx;qenE?comw<$uEb z;Wali006POlDd4|nR@o>PMGJ(GKR2_0BnHO0fJO|-n@C)D3zgT#2mp+SE=#WB*;*R zCB#A*qh3*F`dI)d+D$6dzr{Rn?ZQP%l5%r%DK#xkdcv(+ZW4rX<0tsS?Q=NhxrEx< z+S1ouyHF1(->ySD>fO6H-MDc>0?Vb?y2!_2}7+ zIvBMhSeC7iiSI=Y7fgB8n&gIH*d-$2R5ns;fEits(9`O zX{CA+WntCZf8t`4<#X@y3P7+%Mz$L>c3iqfqoH&K!l_fIWtsbKzyRuK+<{Q9<=}&- zz!-BAT>b|BcC;c~bqn13eHJbr041LjYC=rVm*1K-YZhU|MhXNjk!WF$%5vAcuO;#P z@9^QnGRvceyYWN{Vq7rfD2CGi1ppMc#{{_nIJ-0Gt)!+5Lf?K?gv2O8c#0v%0k}IS z!f_KOGH)l)VNXtS?uVuxIb+{zW>G5rKMO$78A9#awHqUYyYf5{9iy~v+qP|~WvdqS zP4^x=Na6V+K=7yCNO=DK{xov*m^TQ8br*JxIg$GGkGxRFfv-1?5TlFM@{*FzrMym) zCQbAa$DZ7ihlPd7*fupak;$%I`?geHuO1n7H0IepbAC|VXCOTea>#OGpKWGN@?*^_ z-(M(Thaew&kqrVB0F|8Li^emM5i+uwrfib8tM^7Ql7x z_3PhPQrxzNZKz?RhJ+4{&YU^JM2EY!Y#kk)OT(?c3QTvcMj3vkDECDv$_W>gM4hiXc<|uSD03<3=6HV3of=}kBU$ygq|RN;sZCo0>Gpbhda|Rtc<~~;zouKa zZh!076>~h6i*( zghX-Y0M)U-pN_3fMhs{z_VnDTk*S%9w7f-Ub24bt8oj(8>FU;HV0e?uuFpj0GEb5q z{kDt}w=XXcOH ztoHc>mwYE~JO6@`w@%PAl)k8=f|A+#03bU;ATJ2Y^cVCx2*8Bk|B>*JI9*C`Ye`PF z;&Q#}a@1YnV?p@jSs)nQTEu!Tl;?9f1W$mwTaabHKA7QkqSgkjWUa4Jvj)G$^Lbul z)33k&8p6|Lh!LcYk`9oOV=Tm}ZR16Zqpf&zeU+eq!>~5IAng%A2uCxrfxn;Sl9B#z$Qfk#}d{H05mXz<`cOmIMPd$R|~I$y7T zJ*rl%Dn?TSSb3TCL5vbGz_5{f1;y``)Ku+lf5=p=vck@OvvaW^Yad286j^1&2aK?X)^0!p=^!1Cx zYSA;mRn&V-AY)gK5MI6xNRE!k37%XLWDWobMwFYpgEE4w>E$i_J^)qZJV4k4Pna*F zzcZB~R;gGMp@OCc1C2(Q$+>gK#-;A>zyBu8@WJ4EQE!N8ClhMXvW3j_AT`vkT|2_b zhJuk+j4q}`l=}=u@89Vh2f=KHJO+gBh&Yx-hFzavh;adBZ9oQLzh`_xjRX@OgQM6%U|^jZfmxU&{XaWCBcTs{cN-T)z( zL1;)hiHjr%8Q!HNFcIJj_qT#M{vuLrx{L1bTGYPX3QBpn?*krKfZ@pzb%ze^$;#T2 zdiCi+CZ@*JyoEm1sauD>_@V+gH*yb;eY|Xdu;V|+6Jm&dfh9iSq*!aC#$vAHY?0}) zMj-2>L?S0VSIIBs0YFHoLpcf40fH4kC_`^T1x12HdHo5}v_NFcwvq;@^3J_L(RP-V zhr$n7@yN(XPGWLi*WbDy_3Yh)j7>Y{D_^I!v^)+>v3IcY>;b&E^x#Daq*Y-Hd;;I7 z1Np|Vfmm~VhRC{S4>vz6DDDQ7JO$3MCqFl6;;U0m{20m%?nCKbWo5a10n+3RPH}Ug z$olnrF|hDV;cWmE^zzMi@80c=c^xk(Ip%ra#;y;mn@F0g-@F;shVq#B5S9^y!_3SC zCDTK)3{*tN@O|6i58N0xhFF3&uQ~D$k?sx)SCv*b{ zH4VY;YC(Bz zW_euSdA!X@kGXzqnKET2D56udxTCB>!_}q?f?h4L;?Pu)a(x*ab4P>*^25v9 zAWN|oC?}=|Wd>PLnrA);F?i3z-SC7ZBG+Mpm{k~rq9?O;@nwm-NO(M!&IPXz>D8;3 z6UfXR99hZm^77*HCu3b(Tbpotj210g#L7!S$fV%R@jq}KQ%Q8xDU1@FFgJnpsZmiZ z+CNDoxvYS4H&}6ia7Kb46J%bD7G?@2l<~}nQa$l=DBcG$<%`$7?L^+0IbuPeM{`FkdaMEBM30#_)03m}{Y2>bFIrrapxfv8rL5!fmpgb?Hn_x!{e;~Z=sS{JBT$}{zHzAj>NKJ#R|fAbO>I--jajU+IB^W&gYsp zDn8L&yPTN4W1NV(wgkDrDc=*K&Oyn2+&VLBEDaDEfFw1f|f9&6=cX}R~4h)(gP=+Qk3$dr`>#3Q%muv8X zR7`rjVDTV4=fLH;xnX{P4DTIL@O_*T-q;lT=-w~i3U{YpgvNIr`iIRZe`u+9&JcI; z+C=r9FAMld;WEgG7{cmP5a;PQW5+z5jDX` ztdPY*5-SlDq!NSCLQoTpm53TERFO)S+JICNV;)5X(I}P{52Iy-O(lQ{5I`Q;urGEO zc4udI9{ujV_nve7`kvF=>ontpZ9q!)RQ>y$zCGK0e*f?L&ONvLE;Gj9&D=QYgaIcE zIAOq>w@JLg8l#3q%~1RQW5Dvj4Bdb8ni(SB0MIO}MaPU2T(46@UL7Ok|1mUQByral zETW15j4hj90@5W{i2gz*$D3qvyZ>tJf5~ z!t`{sE)6r}nQwPAgfllI`2fTGE(!qgNBYOB~W%8b_AHM&dBS#Pc&`u^b;*DTH zH#pCL%U%Ea_A6JcjII;D+`w4Fm$_kZkq1W=&_{u27r`4SEvXk!v4)Cb#Bm75SDBD) zdgRHc>VNX?4?g@5kQkwsGNE?^dIuM6{rk4nXPx)9so(3L@ZKwmr{tJ_62TMzQvr0D z`YKGc2da4xt(HNf8lhgUqFD`5uNkx&2Am5B#-pK$W@B))Am`@QZJ)nYZU5r8>ho!N zI1_p|pm*^1zGW!?nd_#0V{(0PePQj`DSY^+!Se3_OlYBXmBtO|crR4_5dsfUIl6$O zhYq7!t|OOc7#iU4JOYP=iX@_jM5V+L#l{pTYL&t9+}wh`=+hTn{tth5=n%qANwnMR zWk3p_g7>w-$0rIOFP=KFN>2Sc(D#c8EOd!fNg@t)h`_%^(S8vNM`kg9crW5GM4<=_ z3^L>c2I+G!Fc>YNBY~I<2pc}C3qH#83{BlMlN*Dw;wOK0>+gK$wq3hW&zkTW8{pv6 zsLQ9mw0Y~)sN9}gIj}Z=$|kUpj{$Nuz==xNT*_Brn%_lK{u@*)A&%^M7WK+JMn{0r zalj*RAsCW()|^NHqgguxteQR|GNHZ@pj48mG+GFTn++ohxBk|)=RfoK@i-B|3C*XGubF@N<1V13ciT zSawZt2J{Sn%e8C9f9=A-yS>2M(tp}Yh%u^jxyC{ZqT)_a6#UPjUVa9LpL-6~V@KK% zPn0hJoOSO5jWr-OL2;;1l03?S0C9~>DCJSD0}HhX@L2WmJU;OL8}>W^AY85#WUp!e z!FLW7uDEdUo1SD_`Zf%L51$4wV{1K0VP-=b?SyW81GQ=yFFf-UTGa)tB#%Z2-p{35 zp~a1`?b~USBsGss+X#|^^dgvmBiH9aMFCWfp;U|d`-R!Ib}fGHzyW(^py?(q^p*kL z1_+XT@y^q~T*!&5{8gjKttA@K)-aeHrhX_HLp=s#en54uap3Vsp_*l^Tn7w}12Wfn zCuab2T0AWcn2$&IPKOMo12^l!Lo#YEo6JG~J=#rqIP z4eIOAjXf}p`+(?iyW*=B%F~B&Z13|JT?q`W0%Tu0t!0~W;2{m`3}`YiZEU4*Lk|R> z7(vH`wkD7Q!NfV6`abIH<*(i%=nVMfpBnrH8VXsQMcg7#RKR!%zN|tR10w(?14N;Z zW4rgEFrYCy1$ceNLN&9Ic4O8()f658$z1{^(1rJYBuurBttUbBtc^-kQhK(ck_n_F8JT_O&;%#&zION{5s;uAPfmU z=8)Qh ztOo;ZoPKlb=oo+%%xf=v1Ruu)9}%#EQg-uW0Fq9O@H_@?I+1rhgL`mHIwJ+(C0V1g zJ40lpZ7(^%IkO8Cx8f{`c|1HIF3GF~=+ywW_1wYpq8Ko|0b>YLE9f|aRw0dJD6Q=t z-WYHVa92G>aTiGvb8;YyTKDlZ`gSL1m=k~Lm}D#grw+W62}bK6;OBMLfyG%MkLL_9 zG9b>14PaQ9Kr$%6gir)X`~+{3`BG^lQ8C6ryGb)<(hQ(+=QVVTeQCtGpj`Xsia{xn)%yZw4^e^SqDKglCIaaN}0v7)D2l01ah;u&&{I9Gs<5vOpyM z$}%7eZb%kdr0|^{NcI6ak0%Bc3ra}O^aBvbSpwZ(czDdL7k&h-ZSaI_M>+;fXiYFW z$%1B8!xI7woyj?P!|a5?x`4aDQ{(<8tP&*dBoe{!6pY(X>kBl~2>2ggk=y9z&wE}3 zNmDY2?HjPR47k)_WP&j<0FxLKRsl~+zz90t0d^oSMbp*uVrWt}vfc0`E$s7HB+54C z1z2q*BU>Xntkiw7@IMcSSsi_vDp#alq zgc4xIfH;N2A}}lhN7|-vmbH8(JHYRLk>64nG^ZEGeWAcXy6)dmecK(|fM05>*GLnLEBXMfUIdiBrNeqvw>uOkmeu7DUE0L#^2 znhzmfXeOVbsf$`bi+W>P7+;Y`v$XSa0AC;}C&-^P`u}k&e#HyS)eHhd6Gst8mLtu0 zx58*U;jqjg;KL-7REaAZc0**CyRL_Wr{|26Hh1dO?cPN{oBk#boj(H@@WIS9bo~kF z`3leop+h8@8IzhVB)ig)&6lDzvja`dW)@!;$e$$oxBn?t27UO($QToqr(>va-k!Q+ zfP2ma4hz{<)E0+?4;G7L%-!m*HM786!*sw&CNUz7e!6c+OF(;@p@MN3E}&~a2C8!u z={c~t2^GcA3Q#c+hCocc@QWy}ITPXZ-4Ml~@%E22KDuZ_1i2jimp+NXQ`X~IH4o8u zG65XTz$!qIgxh3tlF$a)Gw^}{Oy;0tf`}9}!7xn{Jb?!(0p|wHWkK4k0R{n#w;r)5 z&^V8{{sK(v08BVfs)8GW);5_VWuxAx(-;F7UUxnkGmoKm_)#+x4Ly4K@0LEbmy!hl zUnT=m_#L<5B9X_v%^CRPD;bOe!Ws}164(Fanb!K+h1Yuvaa9o_KT6t!c!SImG1|s2UMP z^`y?2`wULfZ7HBy1&$rF@cqLRm^%Gz)aQPLBRh9M1;ox8KL)!~$r}@FZY(#@fu*p67EA z`2gO)N#x=bm{fpSNJtoyFd76~MO-Zra2dK;1ypSJ@y<-{daW&ZxlAe%iSjVKY7_bh zes=$psMqT8p84FaKl@twfrB$tut1GeA{`^mIL(qOq>!WxHD^Ey|NYx>dp^RIQrg<) zl0o+OW8{n*ksG}baq~sY?|%#jzV}rO&}6S$~gG!lco}~@_j$VBip}Oe$rj+G+e~X zqS>N%*uJD+PXv0Ol>LS13RB~q2Gw|9_>y$utv*SH^2mg95Fjp|nF}&eA44m{K zf}Vv+;HP0?>f;v>F5CmHt2XL_q17}f%`!CRHFQfu00=z5C*^ztk9tqK#Z%cePbrdi zJxLoMkc060MiJ0j;rEYFUx1*`oZa^$9D1?d;EHKx%HcWJ;j0d);ozz+!sQHf#hKC~ zg&lYjUd{kP@~^%GtN-Y7_D?IfeDd_d)cc^r8G@fC__k)qfN4b4`vE-*=1PPM7j;2n zZZikMrfwJu#34tkE)iEGqLu)M2O)hjBoFE5$ecWxRX{FBukbn;BD7mvn@4kY+8mtL z^V|P1e)ubQ*Y;e$6({dKilg^Fg53_T(gDwmt7*h7_)>R~utez@Ax9c|%Lbfs(?{4R z&OGnjpD(WcB_9mXv4xN8KZH?-2pkr?4V@a1j@@g_nZt|^6MKLn#XgvJW9_$l`y3n$ z3UPG?wT0REnZ5jlYj37Be=b~b5K$-99q>Z-d*#e(-&zdb1;50NOL@{TX(egR1!v;S zk6+C%JAcdCGyRcu+(ZY-hyxBT3z{{+8sf(GH6|RagH{$gJ2uTanR^uFa;xz#|A}X> z`E=>wR)m&=2pv?@!MhrF3tI{vIw>c;6nJ+Aqy`LXdjHXtp7 z9I4+yk2;Nz2AnxLXOu@0E60$(^c`%~IUDJUbA7%ruH8YdVf`_DL2C$M*ZP9N=VOP|9yiG1O!GZ-2wn!Rs8qAoG&ln*|JbRhhy$f)C zH*}QNZT56Va<%Q?o0&+fOs}0Bc<;B$8d98@Y?MjIvNNFHnb4Ot!HHXS8DN$GcXjR} z-<{r#Or({QS)`tCm0jvyKjEN!2b#CgBxis-=4VPmqWd>qof>Q5yMO*nwJ6o&Y<*`l zs#ox=0n7am${m>JKm(^-X6!l1OewG>q8~1)w5Fp>wDoa7_hP{E_xd`e(5XcCoj%>Q zzgUaT+p32Y@6mwejaZx+4%lhwH9$L=6f{*9xYua+Zou+JAOpzL=b3R=b5PkjPKDPC z`c=M7uKO^SX^UZBYv|YiZt-QCgM9wucJkxJOBUy M07*qoM6N<$f}0eNO#lD@ literal 0 HcmV?d00001 diff --git a/themes/oxygen/ipkg/postinst b/themes/oxygen/ipkg/postinst new file mode 100755 index 0000000000..6eb778f669 --- /dev/null +++ b/themes/oxygen/ipkg/postinst @@ -0,0 +1,4 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + ( . /etc/uci-defaults/luci-theme-oxygen ) && rm -f /etc/uci-defaults/luci-theme-oxygen +} diff --git a/themes/oxygen/luasrc/view/themes/oxygen/dashboard.htm b/themes/oxygen/luasrc/view/themes/oxygen/dashboard.htm new file mode 100644 index 0000000000..1e05575809 --- /dev/null +++ b/themes/oxygen/luasrc/view/themes/oxygen/dashboard.htm @@ -0,0 +1,46 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<% + local node = luci.dispatcher.context.requested + if node.nodes then +%> +

+
+<% +end +%> \ No newline at end of file diff --git a/themes/oxygen/luasrc/view/themes/oxygen/footer.htm b/themes/oxygen/luasrc/view/themes/oxygen/footer.htm new file mode 100644 index 0000000000..b570788d5d --- /dev/null +++ b/themes/oxygen/luasrc/view/themes/oxygen/footer.htm @@ -0,0 +1,22 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +
+
+ +

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

+ +
+ + \ No newline at end of file diff --git a/themes/oxygen/luasrc/view/themes/oxygen/header.htm b/themes/oxygen/luasrc/view/themes/oxygen/header.htm new file mode 100644 index 0000000000..ce8019d235 --- /dev/null +++ b/themes/oxygen/luasrc/view/themes/oxygen/header.htm @@ -0,0 +1,130 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<% +local hostname = require("luci.sys").hostname() +local crequest = luci.dispatcher.context.request +local request = require("luci.dispatcher").context.path +local category = request[1] +local tree = luci.dispatcher.node() +local cattree = category and luci.dispatcher.node(category) +local node = luci.dispatcher.context.dispatched + +local c = tree +for i,r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end +end + +require("luci.i18n").loadc("default") +require("luci.http").prepare_content("application/xhtml+xml") + +-%> + + + + + + + + + +<% if node and node.css then %> +<% end -%> +<%=striptags( hostname .. ( (node and node.title) and ' - ' .. node.title or '')) %> - LuCI + + +
+ + + +<%- +local function ucimenu(prefix, node) + if not node.nodes or node.hidden then + return false + end + local index = {} + local count = 0 + for k, n in pairs(node.nodes) do + if n.title and n.target then + table.insert(index, {name=k, order=n.order or 100}) + count = count + 1 + end + end + + table.sort(index, function(a, b) return a.order < b.order end) + + if count > 0 then + for j, v in pairs(index) do + if #v.name > 0 then + local nnode = node.nodes[v.name] + local href = controller .. prefix .. v.name .. "/" + href = (nnode.query) and href .. luci.http.build_querystring(nnode.query) or href +%> + > <%=nnode.title%> +<%- + end + end +%> + +<% + end +end +%> + + + +<% +if tree.nodes[category] and tree.nodes[category].ucidata then + local ucic = 0 + for i, j in pairs(require("luci.model.uci").cursor():changes()) do + for k, l in pairs(j) do + for m, n in pairs(l) do + ucic = ucic + 1; + end + end + end +-%> +<% if ucic > 0 then %> +<% end %> +<% end %> + + + +
+<% if node.subindex then %><%+themes/oxygen/dashboard%><% end %> diff --git a/themes/oxygen/luasrc/view/themes/oxygen/indexer.htm b/themes/oxygen/luasrc/view/themes/oxygen/indexer.htm new file mode 100644 index 0000000000..6e290dd997 --- /dev/null +++ b/themes/oxygen/luasrc/view/themes/oxygen/indexer.htm @@ -0,0 +1,17 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> +<%+header%> +<%+themes/oxygen/dashboard%> +<%+footer%> \ No newline at end of file diff --git a/themes/oxygen/root/etc/uci-defaults/luci-theme-oxygen b/themes/oxygen/root/etc/uci-defaults/luci-theme-oxygen new file mode 100755 index 0000000000..f4b504b49c --- /dev/null +++ b/themes/oxygen/root/etc/uci-defaults/luci-theme-oxygen @@ -0,0 +1,6 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.Oxygen=/luci-static/oxygen + commit luci +EOF + -- 2.30.2