Merge pull request #1690 from karlp/pagekite
authorHannu Nyman <hannu.nyman@iki.fi>
Tue, 1 May 2018 07:01:50 +0000 (10:01 +0300)
committerGitHub <noreply@github.com>
Tue, 1 May 2018 07:01:50 +0000 (10:01 +0300)
luci-app-pagekitec: new package

199 files changed:
applications/luci-app-adblock/luasrc/controller/adblock.lua
applications/luci-app-adblock/po/it/adblock.po
applications/luci-app-adblock/po/ja/adblock.po
applications/luci-app-adblock/po/pt-br/adblock.po
applications/luci-app-adblock/po/ru/adblock.po
applications/luci-app-adblock/po/templates/adblock.pot
applications/luci-app-adblock/po/zh-cn/adblock.po
applications/luci-app-adblock/po/zh-tw/adblock.po
applications/luci-app-advanced-reboot/Makefile
applications/luci-app-advanced-reboot/README.md
applications/luci-app-advanced-reboot/luasrc/controller/advanced_reboot.lua
applications/luci-app-advanced-reboot/po/ru/advanced-reboot.po
applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js
applications/luci-app-commands/luasrc/view/commands.htm
applications/luci-app-cshark/luasrc/controller/cshark.lua
applications/luci-app-ddns/Makefile
applications/luci-app-ddns/luasrc/controller/ddns.lua
applications/luci-app-ddns/luasrc/model/cbi/ddns/detail.lua
applications/luci-app-dnscrypt-proxy/Makefile
applications/luci-app-dnscrypt-proxy/luasrc/controller/dnscrypt-proxy.lua
applications/luci-app-dnscrypt-proxy/luasrc/model/cbi/dnscrypt-proxy/overview_tab.lua
applications/luci-app-dnscrypt-proxy/po/ja/dnscrypt-proxy.po
applications/luci-app-firewall/luasrc/controller/firewall.lua
applications/luci-app-freifunk-diagnostics/luasrc/controller/freifunk/diag.lua
applications/luci-app-freifunk-diagnostics/luasrc/view/freifunk/diagnostics.htm
applications/luci-app-lxc/Makefile
applications/luci-app-lxc/luasrc/controller/lxc.lua
applications/luci-app-lxc/root/etc/config/lxc
applications/luci-app-mwan3/Makefile
applications/luci-app-mwan3/luasrc/controller/mwan3.lua
applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua
applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua
applications/luci-app-mwan3/luasrc/model/cbi/mwan/notify.lua
applications/luci-app-mwan3/luasrc/model/cbi/mwan/policy.lua
applications/luci-app-mwan3/luasrc/model/cbi/mwan/rule.lua
applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm
applications/luci-app-mwan3/luasrc/view/mwan/status_detail.htm
applications/luci-app-mwan3/luasrc/view/mwan/status_diagnostics.htm
applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm
applications/luci-app-mwan3/luasrc/view/mwan/status_troubleshooting.htm
applications/luci-app-mwan3/po/ja/mwan3.po
applications/luci-app-mwan3/po/ru/mwan3.po
applications/luci-app-mwan3/po/templates/mwan3.pot
applications/luci-app-mwan3/po/zh-cn/mwan3.po
applications/luci-app-mwan3/po/zh-tw/mwan3.po
applications/luci-app-olsr/luasrc/controller/olsr.lua
applications/luci-app-openvpn/luasrc/model/cbi/openvpn.lua
applications/luci-app-splash/luasrc/controller/splash/splash.lua
applications/luci-app-splash/root/usr/sbin/luci-splash
applications/luci-app-statistics/luasrc/statistics/rrdtool.lua
applications/luci-app-tinyproxy/luasrc/view/tinyproxy_status.htm
applications/luci-app-travelmate/Makefile
applications/luci-app-travelmate/luasrc/controller/travelmate.lua
applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua
applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua
applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua
applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua
applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm
applications/luci-app-travelmate/po/ja/travelmate.po
applications/luci-app-travelmate/po/pt-br/travelmate.po
applications/luci-app-travelmate/po/ru/travelmate.po
applications/luci-app-travelmate/po/templates/travelmate.pot
applications/luci-app-unbound/luasrc/controller/unbound.lua
applications/luci-app-unbound/luasrc/model/cbi/unbound/configure.lua
applications/luci-app-upnp/luasrc/controller/upnp.lua
applications/luci-app-upnp/po/zh-cn/upnp.po
applications/luci-app-vnstat/luasrc/view/vnstat.htm
applications/luci-app-vpnbypass/Makefile
applications/luci-app-vpnbypass/luasrc/model/cbi/vpnbypass.lua
applications/luci-app-vpnbypass/po/ru/vpnbypass.po
applications/luci-app-wireguard/Makefile
applications/luci-app-wol/luasrc/controller/wol.lua
applications/luci-app-wol/luasrc/model/cbi/wol.lua
build/check-controllers.sh [new file with mode: 0755]
contrib/package/community-profiles/files/etc/config/profile_berlin
contrib/package/community-profiles/files/etc/config/profile_cottbus
contrib/package/community-profiles/files/etc/config/profile_potsdam
contrib/package/community-profiles/files/etc/config/profile_tulumlibre
contrib/package/freifunk-common/Makefile
contrib/package/lucihttp/Makefile [new file with mode: 0644]
documentation/api/index.html
documentation/api/modules/luci.dispatcher.html
documentation/api/modules/luci.http.html
documentation/api/modules/luci.i18n.html
documentation/api/modules/luci.ip.cidr.html
documentation/api/modules/luci.ip.html
documentation/api/modules/luci.json.html
documentation/api/modules/luci.jsonc.html
documentation/api/modules/luci.jsonc.parser.html
documentation/api/modules/luci.model.ipkg.html
documentation/api/modules/luci.model.uci.html
documentation/api/modules/luci.rpcc.html
documentation/api/modules/luci.rpcc.ruci.html
documentation/api/modules/luci.sys.html
documentation/api/modules/luci.sys.init.html
documentation/api/modules/luci.sys.iptparser.html
documentation/api/modules/luci.sys.net.html
documentation/api/modules/luci.sys.process.html
documentation/api/modules/luci.sys.user.html
documentation/api/modules/luci.sys.wifi.html
documentation/api/modules/luci.util.html
documentation/api/modules/nixio.CHANGELOG.html
documentation/api/modules/nixio.CryptoHash.html
documentation/api/modules/nixio.File.html
documentation/api/modules/nixio.README.html
documentation/api/modules/nixio.Socket.html
documentation/api/modules/nixio.TLSContext.html
documentation/api/modules/nixio.TLSSocket.html
documentation/api/modules/nixio.UnifiedIO.html
documentation/api/modules/nixio.bin.html
documentation/api/modules/nixio.bit.html
documentation/api/modules/nixio.crypto.html
documentation/api/modules/nixio.fs.html
documentation/api/modules/nixio.html
libs/luci-lib-httpclient/Makefile
libs/luci-lib-httpclient/luasrc/httpclient.lua
libs/luci-lib-httpprotoutils/Makefile [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.lua [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/conditionals.luadoc [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/date.lua [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/date.luadoc [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/mime.lua [new file with mode: 0644]
libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc [new file with mode: 0644]
modules/luci-base/Makefile
modules/luci-base/htdocs/luci-static/resources/cbi.js
modules/luci-base/htdocs/luci-static/resources/xhr.js
modules/luci-base/luasrc/cbi/datatypes.lua
modules/luci-base/luasrc/dispatcher.lua
modules/luci-base/luasrc/dispatcher.luadoc
modules/luci-base/luasrc/http.lua
modules/luci-base/luasrc/http.luadoc
modules/luci-base/luasrc/http/protocol.lua [deleted file]
modules/luci-base/luasrc/http/protocol.luadoc [deleted file]
modules/luci-base/luasrc/http/protocol/conditionals.lua [deleted file]
modules/luci-base/luasrc/http/protocol/conditionals.luadoc [deleted file]
modules/luci-base/luasrc/http/protocol/date.lua [deleted file]
modules/luci-base/luasrc/http/protocol/date.luadoc [deleted file]
modules/luci-base/luasrc/http/protocol/mime.lua [deleted file]
modules/luci-base/luasrc/http/protocol/mime.luadoc [deleted file]
modules/luci-base/luasrc/model/ipkg.lua
modules/luci-base/luasrc/model/network.lua
modules/luci-base/luasrc/model/uci.lua
modules/luci-base/luasrc/model/uci.luadoc
modules/luci-base/luasrc/sys.lua
modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
modules/luci-base/luasrc/tools/status.lua
modules/luci-base/luasrc/util.lua
modules/luci-base/luasrc/util.luadoc
modules/luci-base/luasrc/view/cbi/filebrowser.htm
modules/luci-base/luasrc/view/cbi/simpleform.htm
modules/luci-base/luasrc/view/cbi/tblsection.htm
modules/luci-base/luasrc/view/error404.htm
modules/luci-base/luasrc/view/sysauth.htm
modules/luci-base/po/ca/base.po
modules/luci-base/po/cs/base.po
modules/luci-base/po/de/base.po
modules/luci-base/po/el/base.po
modules/luci-base/po/en/base.po
modules/luci-base/po/es/base.po
modules/luci-base/po/fr/base.po
modules/luci-base/po/he/base.po
modules/luci-base/po/hu/base.po
modules/luci-base/po/it/base.po
modules/luci-base/po/ja/base.po
modules/luci-base/po/ko/base.po
modules/luci-base/po/ms/base.po
modules/luci-base/po/no/base.po
modules/luci-base/po/pl/base.po
modules/luci-base/po/pt-br/base.po
modules/luci-base/po/pt/base.po
modules/luci-base/po/ro/base.po
modules/luci-base/po/ru/base.po
modules/luci-base/po/sk/base.po
modules/luci-base/po/sv/base.po
modules/luci-base/po/templates/base.pot
modules/luci-base/po/tr/base.po
modules/luci-base/po/uk/base.po
modules/luci-base/po/vi/base.po
modules/luci-base/po/zh-cn/base.po
modules/luci-base/po/zh-tw/base.po
modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json [new file with mode: 0644]
modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
modules/luci-mod-admin-full/luasrc/controller/admin/status.lua
modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/vlan.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
modules/luci-mod-admin-full/luasrc/view/admin_system/packages.htm
modules/luci-mod-admin-full/luasrc/view/admin_uci/changes.htm
modules/luci-mod-admin-full/luasrc/view/admin_uci/revert.htm
modules/luci-mod-freifunk/htdocs/luci-static/resources/OSMLatLon.htm
modules/luci-mod-freifunk/luasrc/controller/freifunk/freifunk.lua
modules/luci-mod-rpc/luasrc/controller/rpc.lua
protocols/luci-proto-ipv6/luasrc/model/cbi/admin_network/proto_6in4.lua
themes/luci-theme-bootstrap/luasrc/view/themes/bootstrap/header.htm
themes/luci-theme-freifunk-generic/luasrc/view/themes/freifunk-generic/header.htm
themes/luci-theme-material/htdocs/luci-static/material/css/style.css
themes/luci-theme-material/luasrc/view/themes/material/header.htm
themes/luci-theme-openwrt/luasrc/view/themes/openwrt.org/header.htm

index 700f187..1011066 100644 (file)
@@ -15,9 +15,9 @@ function index()
        entry({"admin", "services", "adblock", "tab_from_cbi"}, cbi("adblock/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
        entry({"admin", "services", "adblock", "logfile"}, call("logread"), _("View Logfile"), 20).leaf = true
        entry({"admin", "services", "adblock", "advanced"}, firstchild(), _("Advanced"), 100)
-       entry({"admin", "services", "adblock", "advanced", "blacklist"}, cbi("adblock/blacklist_tab"), _("Edit Blacklist"), 110).leaf = true
-       entry({"admin", "services", "adblock", "advanced", "whitelist"}, cbi("adblock/whitelist_tab"), _("Edit Whitelist"), 120).leaf = true
-       entry({"admin", "services", "adblock", "advanced", "configuration"}, cbi("adblock/configuration_tab"), _("Edit Configuration"), 130).leaf = true
+       entry({"admin", "services", "adblock", "advanced", "blacklist"}, form("adblock/blacklist_tab"), _("Edit Blacklist"), 110).leaf = true
+       entry({"admin", "services", "adblock", "advanced", "whitelist"}, form("adblock/whitelist_tab"), _("Edit Whitelist"), 120).leaf = true
+       entry({"admin", "services", "adblock", "advanced", "configuration"}, form("adblock/configuration_tab"), _("Edit Configuration"), 130).leaf = true
        entry({"admin", "services", "adblock", "advanced", "query"}, template("adblock/query"), _("Query domains"), 140).leaf = true
        entry({"admin", "services", "adblock", "advanced", "result"}, call("queryData"), nil, 150).leaf = true
 end
@@ -36,8 +36,8 @@ end
 function queryData(domain)
        if domain then
                luci.http.prepare_content("text/plain")
-               local cmd = "/etc/init.d/adblock query %q 2>&1"
-               local util = io.popen(cmd % domain)
+               local cmd = "/etc/init.d/adblock query %s 2>&1"
+               local util = io.popen(cmd % util.shellquote(domain))
                if util then
                        while true do
                                local line = util:read("*l")
index 88adcc8..0a1b65a 100644 (file)
@@ -275,8 +275,8 @@ msgid ""
 msgstr ""
 
 msgid ""
-"Size of the download queue to handle downloads &amp; list processing in parallel "
-"(default '4').<br />"
+"Size of the download queue to handle downloads &amp; list processing in "
+"parallel (default '4').<br />"
 msgstr ""
 
 msgid "Startup Trigger"
index 60c5a9a..dfd72cb 100644 (file)
@@ -301,8 +301,8 @@ msgstr ""
 "処理エラーまたはドメイン カウントが0以下の場合、メールを送信します。<br />"
 
 msgid ""
-"Size of the download queue to handle downloads &amp; list processing in parallel "
-"(default '4').<br />"
+"Size of the download queue to handle downloads &amp; list processing in "
+"parallel (default '4').<br />"
 msgstr ""
 "ダウンロードの制御とリストの処理を同時並行的に行うダウンロード キューのサイズ"
 "です(既定値: '4')。<br />"
index 7eb6e3e..c0d9d81 100644 (file)
@@ -267,8 +267,8 @@ msgid ""
 msgstr ""
 
 msgid ""
-"Size of the download queue to handle downloads &amp; list processing in parallel "
-"(default '4').<br />"
+"Size of the download queue to handle downloads &amp; list processing in "
+"parallel (default '4').<br />"
 msgstr ""
 
 msgid "Startup Trigger"
index 6e80e80..17f39fd 100644 (file)
@@ -303,8 +303,8 @@ msgstr ""
 "&le; 0.<br />"
 
 msgid ""
-"Size of the download queue to handle downloads &amp; list processing in parallel "
-"(default '4').<br />"
+"Size of the download queue to handle downloads &amp; list processing in "
+"parallel (default '4').<br />"
 msgstr ""
 "Значение очереди загрузки для выполнения параллельных загрузок (по умолчанию "
 "'4').<br />"
index 5a93f8f..6fbaa65 100644 (file)
@@ -248,8 +248,8 @@ msgid ""
 msgstr ""
 
 msgid ""
-"Size of the download queue to handle downloads &amp; list processing in parallel "
-"(default '4').<br />"
+"Size of the download queue to handle downloads &amp; list processing in "
+"parallel (default '4').<br />"
 msgstr ""
 
 msgid "Startup Trigger"
index 1d7dc2b..e26c44c 100644 (file)
@@ -369,152 +369,3 @@ msgstr "已暂停"
 msgid "running"
 msgstr ""
 
-#~ msgid ""
-#~ "For SSL protected blocklist sources you need a suitable SSL library, e.g. "
-#~ "'libustream-ssl' or the wget 'built-in'."
-#~ msgstr ""
-#~ "对于 SSL 保护的 blocklist 源,您需要一个合适的 SSL 库,例如'libustream-"
-#~ "ssl'或 wget'built-in'。"
-
-#~ msgid ""
-#~ "Caution: Please don't select big lists or many lists at once on low "
-#~ "memory devices to prevent OOM exceptions!"
-#~ msgstr ""
-#~ "注意:请勿在内存较小的设备上选择过长的列表或同时选择多个列表,以防止 OOM "
-#~ "异常!"
-
-#~ msgid ""
-#~ "Create compressed blocklist backups, they will be used in case of "
-#~ "download errors or during startup in manual mode."
-#~ msgstr "创建压缩的 blocklist 备份,它们将在下载错误或手动模式下启动时使用。"
-
-#~ msgid ""
-#~ "Enable memory intense overall sort / duplicate removal on low memory "
-#~ "devices (&lt; 64 MB RAM)"
-#~ msgstr "在低内存设备上启用耗用内存的整体排序/重复规则删除(&lt;64 MB RAM)"
-
-#~ msgid ""
-#~ "For further information <a href=\"%s\" target=\"_blank\">see online "
-#~ "documentation</a>"
-#~ msgstr "有关更多信息,请<a href=\"%s\" target=\"_blank\">参阅在线文档</a>"
-
-#~ msgid ""
-#~ "In OPKG use the '--force-maintainer' option to overwrite the pre-existing "
-#~ "config file or download a fresh default config from <a href=\"%s\" target="
-#~ "\"_blank\">here</a>"
-#~ msgstr ""
-#~ "在 OPKG 中,使用“--force-maintainer”选项覆盖预先存在的配置文件,或从<a "
-#~ "href=\"%s\" target=\"_blank\">此处</a>下载新的默认配置"
-
-#~ msgid ""
-#~ "List of available network interfaces. By default the startup will be "
-#~ "triggered by the 'wan' interface.<br />"
-#~ msgstr "可用网络接口列表。默认情况下,将由“wan”界面触发启动。<br />"
-
-#~ msgid "Manual / Backup mode"
-#~ msgstr "手动/备份模式"
-
-#~ msgid "Overall Blocked Domains"
-#~ msgstr "整体封锁域名"
-
-#~ msgid "Please update your adblock config file to use this package."
-#~ msgstr "请更新您的 adblock 配置文件以使用此软件包。"
-
-#~ msgid ""
-#~ "Target directory for adblock backups. Please use only non-volatile disks, "
-#~ "no ram/tmpfs drives."
-#~ msgstr ""
-#~ "adblock 备份的目标目录。请仅使用非易失性磁盘,不使用 ram/tmpfs 驱动器。"
-
-#~ msgid "DNS backend"
-#~ msgstr "DNS 后端"
-
-#~ msgid "Enable verbose debug logging"
-#~ msgstr "启用详细调试输出"
-
-#~ msgid "Resume adblock"
-#~ msgstr "恢复 Adblock"
-
-#~ msgid "Status"
-#~ msgstr "状态"
-
-#~ msgid "Suspend adblock"
-#~ msgstr "暂停 Adblock"
-
-#~ msgid "active"
-#~ msgstr "已启用"
-
-#~ msgid "no domains blocked"
-#~ msgstr "没有被拦截的域名"
-
-#~ msgid "suspended"
-#~ msgstr "已暂停"
-
-#~ msgid "."
-#~ msgstr "."
-
-#~ msgid "For further information"
-#~ msgstr "更多信息"
-
-#~ msgid "see online documentation"
-#~ msgstr "查看在线文档"
-
-#~ msgid "Backup options"
-#~ msgstr "备份选项"
-
-#~ msgid ""
-#~ "). Note that list URLs and Shallalist category selections are not "
-#~ "configurable via Luci."
-#~ msgstr ")。需要注意的是列表URL和列表类别选项无法通过Luci设置。"
-
-#~ msgid "Available blocklist sources ("
-#~ msgstr "可用拦截列表来源("
-
-#~ msgid ""
-#~ "File with whitelisted hosts/domains that are allowed despite being on a "
-#~ "blocklist."
-#~ msgstr "允许的主机/域名列表"
-
-#~ msgid "Global options"
-#~ msgstr "全局选项"
-
-#~ msgid "Whitelist file"
-#~ msgstr "白名单文件"
-
-#~ msgid "see list details"
-#~ msgstr "查看列表详情"
-
-#~ msgid "Count"
-#~ msgstr "数量"
-
-#~ msgid "IPv4 blackhole ip address"
-#~ msgstr "IPv4禁止列表"
-
-#~ msgid "IPv6 blackhole ip address"
-#~ msgstr "IPv6禁止列表"
-
-#~ msgid "List date/state"
-#~ msgstr "列表日期/状态"
-
-#~ msgid "Name of the logical lan interface"
-#~ msgstr "LAN接口名称"
-
-#~ msgid "Port of the adblock uhttpd instance"
-#~ msgstr "Adblock uhttpd端口"
-
-#~ msgid "Redirect all DNS queries to the local resolver"
-#~ msgstr "将所有DNS查询都重定向到本地解析器"
-
-#~ msgid "Timeout for blocklist fetch (seconds)"
-#~ msgstr "列表查询超时时间(秒)"
-
-#~ msgid "Total count of blocked domains"
-#~ msgstr "阻止域名总数"
-
-#~ msgid ""
-#~ "When adblock is active, all DNS queries are redirected to the local "
-#~ "resolver in this server by default. You can disable that to allow queries "
-#~ "to external DNS servers."
-#~ msgstr ""
-#~ "当Adblock处于活动状态时,默认情况下会将所有的DNS查询重定向到此服务器的本地"
-#~ "解析器。您可以禁用以允许查询外部DNS服务器。"
index da00842..417fc6b 100644 (file)
@@ -369,153 +369,3 @@ msgstr "已暫停"
 msgid "running"
 msgstr ""
 
-#~ msgid ""
-#~ "For SSL protected blocklist sources you need a suitable SSL library, e.g. "
-#~ "'libustream-ssl' or the wget 'built-in'."
-#~ msgstr ""
-#~ "對於 SSL 保護的 blocklist 源,您需要一個合適的 SSL 庫,例如'libustream-"
-#~ "ssl'或 wget'built-in'。"
-
-#~ msgid ""
-#~ "Caution: Please don't select big lists or many lists at once on low "
-#~ "memory devices to prevent OOM exceptions!"
-#~ msgstr ""
-#~ "注意:請勿在記憶體較小的裝置上選擇過長的列表或同時選擇多個列表,以防止 "
-#~ "OOM 異常!"
-
-#~ msgid ""
-#~ "Create compressed blocklist backups, they will be used in case of "
-#~ "download errors or during startup in manual mode."
-#~ msgstr "建立壓縮的 blocklist 備份,它們將在下載錯誤或手動模式下啟動時使用。"
-
-#~ msgid ""
-#~ "Enable memory intense overall sort / duplicate removal on low memory "
-#~ "devices (&lt; 64 MB RAM)"
-#~ msgstr ""
-#~ "在低記憶體裝置上啟用耗用記憶體的整體排序/重複規則刪除(&lt;64 MB RAM)"
-
-#~ msgid ""
-#~ "For further information <a href=\"%s\" target=\"_blank\">see online "
-#~ "documentation</a>"
-#~ msgstr "有關更多資訊,請<a href=\"%s\" target=\"_blank\">參閱線上文件</a>"
-
-#~ msgid ""
-#~ "In OPKG use the '--force-maintainer' option to overwrite the pre-existing "
-#~ "config file or download a fresh default config from <a href=\"%s\" target="
-#~ "\"_blank\">here</a>"
-#~ msgstr ""
-#~ "在 OPKG 中,使用“--force-maintainer”選項覆蓋預先存在的配置檔案,或從<a "
-#~ "href=\"%s\" target=\"_blank\">此處</a>下載新的預設配置"
-
-#~ msgid ""
-#~ "List of available network interfaces. By default the startup will be "
-#~ "triggered by the 'wan' interface.<br />"
-#~ msgstr "可用網路介面列表。預設情況下,將由“wan”介面觸發啟動。<br />"
-
-#~ msgid "Manual / Backup mode"
-#~ msgstr "手動/備份模式"
-
-#~ msgid "Overall Blocked Domains"
-#~ msgstr "整體封鎖域名"
-
-#~ msgid "Please update your adblock config file to use this package."
-#~ msgstr "請更新您的 adblock 配置檔案以使用此軟體包。"
-
-#~ msgid ""
-#~ "Target directory for adblock backups. Please use only non-volatile disks, "
-#~ "no ram/tmpfs drives."
-#~ msgstr ""
-#~ "adblock 備份的目標目錄。請僅使用非易失性磁碟,不使用 ram/tmpfs 驅動器。"
-
-#~ msgid "DNS backend"
-#~ msgstr "DNS 後端"
-
-#~ msgid "Enable verbose debug logging"
-#~ msgstr "啟用詳細除錯輸出"
-
-#~ msgid "Resume adblock"
-#~ msgstr "恢復 Adblock"
-
-#~ msgid "Status"
-#~ msgstr "狀態"
-
-#~ msgid "Suspend adblock"
-#~ msgstr "暫停 Adblock"
-
-#~ msgid "active"
-#~ msgstr "已啟用"
-
-#~ msgid "no domains blocked"
-#~ msgstr "沒有被攔截的域名"
-
-#~ msgid "suspended"
-#~ msgstr "已暫停"
-
-#~ msgid "."
-#~ msgstr "."
-
-#~ msgid "For further information"
-#~ msgstr "更多資訊"
-
-#~ msgid "see online documentation"
-#~ msgstr "檢視線上文件"
-
-#~ msgid "Backup options"
-#~ msgstr "備份選項"
-
-#~ msgid ""
-#~ "). Note that list URLs and Shallalist category selections are not "
-#~ "configurable via Luci."
-#~ msgstr ")。需要注意的是列表URL和列表類別選項無法通過Luci設定。"
-
-#~ msgid "Available blocklist sources ("
-#~ msgstr "可用攔截列表來源("
-
-#~ msgid ""
-#~ "File with whitelisted hosts/domains that are allowed despite being on a "
-#~ "blocklist."
-#~ msgstr "允許的主機/域名列表"
-
-#~ msgid "Global options"
-#~ msgstr "全域性選項"
-
-#~ msgid "Whitelist file"
-#~ msgstr "白名單檔案"
-
-#~ msgid "see list details"
-#~ msgstr "檢視列表詳情"
-
-#~ msgid "Count"
-#~ msgstr "數量"
-
-#~ msgid "IPv4 blackhole ip address"
-#~ msgstr "IPv4禁止列表"
-
-#~ msgid "IPv6 blackhole ip address"
-#~ msgstr "IPv6禁止列表"
-
-#~ msgid "List date/state"
-#~ msgstr "列表日期/狀態"
-
-#~ msgid "Name of the logical lan interface"
-#~ msgstr "LAN介面名稱"
-
-#~ msgid "Port of the adblock uhttpd instance"
-#~ msgstr "Adblock uhttpd埠"
-
-#~ msgid "Redirect all DNS queries to the local resolver"
-#~ msgstr "將所有DNS查詢都重定向到本地解析器"
-
-#~ msgid "Timeout for blocklist fetch (seconds)"
-#~ msgstr "列表查詢超時時間(秒)"
-
-#~ msgid "Total count of blocked domains"
-#~ msgstr "阻止域名總數"
-
-#~ msgid ""
-#~ "When adblock is active, all DNS queries are redirected to the local "
-#~ "resolver in this server by default. You can disable that to allow queries "
-#~ "to external DNS servers."
-#~ msgstr ""
-#~ "當Adblock處於活動狀態時,預設情況下會將所有的DNS查詢重定向到此伺服器的本地"
-#~ "解析器。您可以禁用以允許查詢外部DNS伺服器。"
index bb545a2..d270498 100644 (file)
@@ -13,7 +13,7 @@ LUCI_DESCRIPTION:=Provides Web UI (found under System/Advanced Reboot) to reboot
 
 LUCI_DEPENDS:=+luci
 LUCI_PKGARCH:=all
-PKG_RELEASE:=26
+PKG_RELEASE:=27
 
 include ../../luci.mk
 
index a938479..d4659c8 100644 (file)
@@ -19,7 +19,7 @@ Currently supported dual-partition devices include:
 If you're interested in having your device supported, please post in [LEDE Project Forum Support Thread](https://forum.lede-project.org/t/web-ui-to-reboot-to-another-partition-dual-partition-routers/3423).
 
 ## Screenshot (luci-app-advanced-reboot)
-![screenshot](https://raw.githubusercontent.com/stangri/screenshots/master/luci-app-advanced-reboot/screenshot01.png "screenshot")
+![screenshot](https://raw.githubusercontent.com/stangri/openwrt_packages/master/screenshots/luci-app-advanced-reboot/screenshot01.png "screenshot")
 
 ## How to install
 Install ```luci-app-advanced-reboot``` from Web UI or connect to your router via ssh and run the following commands:
index 0f512df..b5dd4fe 100644 (file)
@@ -8,19 +8,20 @@ devices = {
   {"Linksys EA3500", "linksys-audi", "mtd3", "mtd5", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
   {"Linksys E4200v2/EA4500", "linksys-viper", "mtd3", "mtd5", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
   {"Linksys EA8500", "ea8500", "mtd13", "mtd15", 32, "boot_part", 1, 2},
-  {"Linksys WRT1200AC", "armada-385-linksys-caiman", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
-  {"Linksys WRT1900AC", "armada-xp-linksys-mamba", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
-  {"Linksys WRT1900ACv2", "armada-385-linksys-cobra", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
-  {"Linksys WRT1900ACS", "armada-385-linksys-shelby", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
-  {"Linksys WRT3200ACM", "armada-385-linksys-rango", "mtd5", "mtd7", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
+--  {"Linksys EA9500", "linksys,panamera", "mtd3", "mtd6", 28, "boot_part", 1, 2},
+  {"Linksys WRT1200AC", "linksys-caiman", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
+  {"Linksys WRT1900AC", "linksys-mamba", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
+  {"Linksys WRT1900ACv2", "linksys-cobra", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
+  {"Linksys WRT1900ACS", "linksys-shelby", "mtd4", "mtd6", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
+  {"Linksys WRT3200ACM", "linksys-rango", "mtd5", "mtd7", 32, "boot_part", 1, 2, "bootcmd", "run nandboot", "run altnandboot"},
   {"ZyXEL NBG6817","nbg6817","mmcblk0p4","mmcblk0p7",32,nil,255,1}
 }
 
 errorMessage = ""
 device_board_name = luci.util.trim(luci.sys.exec("cat /tmp/sysinfo/board_name"))
 for i=1, #devices do
-  table_board_name = devices[i][2]:gsub('-','')
-  if device_board_name and device_board_name:gsub('-',''):match(table_board_name) then
+  table_board_name = devices[i][2]:gsub('%p','')
+  if device_board_name and device_board_name:gsub('%p',''):match(table_board_name) then
     device_name = devices[i][1]
     partition_one_mtd = devices[i][3] or nil
     partition_two_mtd = devices[i][4] or nil
@@ -80,15 +81,17 @@ function index()
 end
 
 function action_reboot()
+  local uci = require "luci.model.uci".cursor()
   luci.template.render("admin_system/applyreboot", {
         title = luci.i18n.translate("Rebooting..."),
         msg   = luci.i18n.translate("The system is rebooting now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
-        addr  = luci.ip.new(uci.cursor():get("network", "lan", "ipaddr")) or "192.168.1.1"
+        addr  = luci.ip.new(uci:get("network", "lan", "ipaddr")) or "192.168.1.1"
       })
   luci.sys.reboot()
 end
 
 function action_altreboot()
+  local uci = require "luci.model.uci".cursor()
   local zyxelFlagPartition, zyxelBootFlag, zyxelNewBootFlag, errorCode, curEnvSetting, newEnvSetting
   errorMessage = ""
   errorCode = 0
@@ -162,7 +165,7 @@ function action_altreboot()
       luci.template.render("admin_system/applyreboot", {
             title = luci.i18n.translate("Rebooting..."),
             msg   = luci.i18n.translate("The system is rebooting to an alternative partition now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
-            addr  = luci.ip.new(uci.cursor():get("network", "lan", "ipaddr")) or "192.168.1.1"
+            addr  = luci.ip.new(uci:get("network", "lan", "ipaddr")) or "192.168.1.1"
           })
       luci.sys.reboot()
     else
@@ -179,6 +182,7 @@ function action_altreboot()
 end
 
 function action_poweroff()
+  local uci = require "luci.model.uci".cursor()
   if luci.http.formvalue("cancel") then
     luci.http.redirect(luci.dispatcher.build_url('admin/system/advanced_reboot'))
     return
@@ -194,7 +198,7 @@ function action_poweroff()
     luci.template.render("admin_system/applyreboot", {
           title = luci.i18n.translate("Shutting down..."),
           msg   = luci.i18n.translate("The system is shutting down now.<br /> DO NOT POWER OFF THE DEVICE!<br /> It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
-          addr  = luci.ip.new(uci.cursor():get("network", "lan", "ipaddr")) or "192.168.1.1"
+          addr  = luci.ip.new(uci:get("network", "lan", "ipaddr")) or "192.168.1.1"
         })
     luci.sys.call("/sbin/poweroff")
   end
index be9d2d7..75d4636 100644 (file)
@@ -12,8 +12,6 @@ msgstr ""
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 "Language: ru\n"
-"Project-Info: Это технический перевод, не дословный. Главное-удобный русский "
-"интерфейс, все проверялось в графическом режиме, совместим с другими apps\n"
 
 msgid "Action"
 msgstr "Действие"
@@ -162,4 +160,4 @@ msgid "Warning: This system does not support powering off!"
 msgstr "Внимание: Эта система не поддерживает отключение питания!"
 
 msgid "to"
-msgstr "к"
+msgstr ""
index 604074a..60f586d 100644 (file)
@@ -373,7 +373,7 @@ function server_request(request_dict, path, callback) {
                error_box("No firmware created due to image size. Try again with less packages selected.")
 
                } else if (request.status === 422) {
-                       var package_missing = response.getResponseHeader("X-Unknown-Package");
+                       var package_missing = request.getResponseHeader("X-Unknown-Package");
                        error_box("Unknown package in request: <b>" + package_missing + "</b>")
                } else if (request.status === 500) {
                        request_json = JSON.parse(request_text)
index f094e18..3b36155 100644 (file)
        uci:foreach("luci", "command", function(s) commands[#commands+1] = s end)
 %>
 
-<form method="get" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
+<form method="get" action="<%=pcdata(FULL_REQUEST_URI)%>">
        <div class="cbi-map">
                <h2 name="content"><%:Custom Commands%></h2>
 
index 4d9bbba..43410a0 100644 (file)
@@ -53,7 +53,13 @@ function cshark_iface_dump_start(ifname, value, flag, filter)
 
        luci.http.prepare_content("text/plain")
 
-       local res = os.execute("(/sbin/cshark -i " .. ifname .. " -" .. flag .. " " .. value .. " -p /tmp/cshark-luci.pid " .. filter .. " > /tmp/cshark-luci.out 2>&1) &")
+       local res = os.execute("(/sbin/cshark -i %s -%s %s -p /tmp/cshark-luci.pid %s > /tmp/cshark-luci.out 2>&1) &" %{
+               luci.util.shellquote(ifname),
+               luci.util.shellquote(flag),
+               luci.util.shellquote(value),
+               luci.util.shellquote(filter)
+       })
+
        luci.http.write(tostring(res))
 end
 
index 50365e5..06dbefb 100644 (file)
@@ -16,7 +16,7 @@ PKG_VERSION:=2.4.9
 
 # Release == build
 # increase on changes of translation files
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_LICENSE:=Apache-2.0
 PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
index 3d31e4e..5f4a511 100755 (executable)
@@ -301,7 +301,7 @@ function startstop(section, enabled)
        uci:unload("ddns")
 
        -- start ddns-updater for section
-       local command = luci_helper .. [[ -S ]] .. section .. [[ -- start]]
+       local command = "%s -S %s -- start" %{ luci_helper, UTIL.shellquote(section) }
        os.execute(command)
        NX.nanosleep(3) -- 3 seconds "show time"
 
index a8f4cbf..977dbe3 100644 (file)
@@ -1229,7 +1229,7 @@ if DDNS.has_proxy or ( ( m:get(section, "proxy") or "" ) ~= "" ) then
                elseif DDNS.has_proxy then
                        local ipv6  = usev6:formvalue(section) or "0"
                        local force = fipv:formvalue(section) or "0"
-                       local command = CRTL.luci_helper .. [[ -]]
+                       local command = CTRL.luci_helper .. [[ -]]
                        if (ipv6 == 1)  then command = command .. [[6]] end
                        if (force == 1) then command = command .. [[f]] end
                        command = command .. [[p ]] .. value .. [[ -- verify_proxy]]
index 4b632b8..d34fec8 100644 (file)
@@ -5,7 +5,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LuCI support for DNSCrypt-Proxy
-LUCI_DEPENDS:=+uclient-fetch +dnscrypt-proxy
+LUCI_DEPENDS:=+uclient-fetch +dnscrypt-proxy +luci-lib-httpprotoutils
 LUCI_PKGARCH:=all
 
 include ../../luci.mk
index 9f6472e..ca078f0 100644 (file)
@@ -15,9 +15,9 @@ function index()
        entry({"admin", "services", "dnscrypt-proxy", "tab_from_cbi"}, cbi("dnscrypt-proxy/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
        entry({"admin", "services", "dnscrypt-proxy", "logfile"}, call("logread"), _("View Logfile"), 20).leaf = true
        entry({"admin", "services", "dnscrypt-proxy", "advanced"}, firstchild(), _("Advanced"), 100)
-       entry({"admin", "services", "dnscrypt-proxy", "advanced", "configuration"}, cbi("dnscrypt-proxy/configuration_tab"), _("Edit DNSCrypt-Proxy Configuration"), 110).leaf = true
-       entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_dnsmasq"}, cbi("dnscrypt-proxy/cfg_dnsmasq_tab"), _("Edit Dnsmasq Configuration"), 120).leaf = true
-       entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_resolvcrypt"}, cbi("dnscrypt-proxy/cfg_resolvcrypt_tab"), _("Edit Resolvcrypt Configuration"), 130).leaf = true
+       entry({"admin", "services", "dnscrypt-proxy", "advanced", "configuration"}, form("dnscrypt-proxy/configuration_tab"), _("Edit DNSCrypt-Proxy Configuration"), 110).leaf = true
+       entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_dnsmasq"}, form("dnscrypt-proxy/cfg_dnsmasq_tab"), _("Edit Dnsmasq Configuration"), 120).leaf = true
+       entry({"admin", "services", "dnscrypt-proxy", "advanced", "cfg_resolvcrypt"}, form("dnscrypt-proxy/cfg_resolvcrypt_tab"), _("Edit Resolvcrypt Configuration"), 130).leaf = true
        entry({"admin", "services", "dnscrypt-proxy", "advanced", "view_reslist"}, call("view_reslist"), _("View Resolver List"), 140).leaf = true
 end
 
index 999c81d..8f0e322 100644 (file)
@@ -4,7 +4,6 @@
 local fs        = require("nixio.fs")
 local uci       = require("luci.model.uci").cursor()
 local util      = require("luci.util")
-local date      = require("luci.http.protocol.date")
 local res_input = "/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv"
 local res_dir   = fs.dirname(res_input)
 local dump      = util.ubus("network.interface", "dump", {})
@@ -12,6 +11,11 @@ local plug_cnt  = tonumber(luci.sys.exec("env -i /usr/sbin/dnscrypt-proxy --vers
 local res_list  = {}
 local url       = "https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv"
 
+local _, date = pcall(require, "luci.http.date")
+if not date then
+       _, date = pcall(require, "luci.http.protocol.date")
+end
+
 if not fs.access(res_input) then
        if not fs.access("/lib/libustream-ssl.so") then
                m = SimpleForm("error", nil, translate("No default resolver list and no SSL support available.<br />")
index 3a081a3..e35efa8 100644 (file)
@@ -7,7 +7,7 @@ msgstr ""
 "Language-Team: \n"
 "MIME-Version: 1.0\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.0.4\n"
+"X-Generator: Poedit 2.0.7\n"
 "Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Language: ja\n"
@@ -79,6 +79,8 @@ msgstr "Dnsmasq オプション"
 msgid ""
 "Download the current resolver list from 'github.com/dyne/dnscrypt-proxy'."
 msgstr ""
+"現在のリゾルバ リストを 'github.com/dyne/dnscrypt-proxy' からダウンロードしま"
+"す。"
 
 msgid "Edit DNSCrypt-Proxy Configuration"
 msgstr "DNSCrypt-Proxy 設定の編集"
@@ -164,6 +166,8 @@ msgid ""
 "Please install a 'libustream-ssl' library to download the current resolver "
 "list from 'github.com/dyne/dnscrypt-proxy'."
 msgstr ""
+"現在のリゾルバ リストを 'github.com/dyne/dnscrypt-proxy' からダウンロードする"
+"ために、 'libustream-ssl' ライブラリをインストールしてください。"
 
 msgid ""
 "Please install a resolver list to '/usr/share/dnscrypt-proxy/dnscrypt-"
@@ -275,14 +279,3 @@ msgstr "ログファイルの確認"
 
 msgid "View Resolver List"
 msgstr "リゾルバ リストの確認"
-
-#~ msgid "Download the current resolver list from 'download.dnscrypt.org'."
-#~ msgstr ""
-#~ "現在のリゾルバ リストを 'download.dnscrypt.org' からダウンロードします。"
-
-#~ msgid ""
-#~ "Please install a 'libustream-ssl' library to download the current "
-#~ "resolver list from 'download.dnscrypt.org'."
-#~ msgstr ""
-#~ "現在のリゾルバ リストを 'download.dnscrypt.org' からダウンロードするため"
-#~ "に、 'libustream-ssl' ライブラリをインストールしてください。"
index 5a6ab0a..4fe7770 100644 (file)
@@ -18,6 +18,6 @@ function index()
                _("Traffic Rules"), 30).leaf = true
 
        entry({"admin", "network", "firewall", "custom"},
-               cbi("firewall/custom"),
+               form("firewall/custom"),
                _("Custom Rules"), 40).leaf = true
 end
index 7bb4761..92b3afc 100644 (file)
@@ -33,7 +33,7 @@ function diag_command(cmd, addr)
        if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
                luci.http.prepare_content("text/plain")
 
-               local util = io.popen(cmd % addr)
+               local util = io.popen(cmd % luci.util.shellquote(addr))
                if util then
                        while true do
                                local ln = util:read("*l")
@@ -52,21 +52,21 @@ function diag_command(cmd, addr)
 end
 
 function diag_ping(addr)
-       diag_command("ping -c 5 -W 1 %q 2>&1", addr)
+       diag_command("ping -c 5 -W 1 %s 2>&1", addr)
 end
 
 function diag_traceroute(addr)
-       diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr)
+       diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
 end
 
 function diag_nslookup(addr)
-       diag_command("nslookup %q 2>&1", addr)
+       diag_command("nslookup %s 2>&1", addr)
 end
 
 function diag_ping6(addr)
-       diag_command("ping6 -c 5 %q 2>&1", addr)
+       diag_command("ping6 -c 5 %s 2>&1", addr)
 end
 
 function diag_traceroute6(addr)
-       diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr)
+       diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
 end
index fe205d0..eac1ecd 100644 (file)
@@ -53,7 +53,7 @@ local has_traceroute6 = fs.access("/usr/bin/traceroute6")
        }
 //]]></script>
 
-<form method="post" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
+<form method="post" action="<%=pcdata(FULL_REQUEST_URI)%>">
        <div class="cbi-map">
                <h2 name="content"><%:Diagnostics%></h2>
 
index 9f313df..85cae5c 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LXC management Web UI
-LUCI_DEPENDS:=+luci-mod-admin-full +lxc +lxc-create +liblxc +rpcd-mod-lxc +getopt +xz
+LUCI_DEPENDS:=+luci-mod-admin-full +lxc +lxc-attach +lxc-console +lxc-create +liblxc +rpcd-mod-lxc +getopt
 LUCI_PKGARCH:=all
 
 PKG_MAINTAINER:=Petar Koretic <petar.koretic@sartura.hr>
index ea7adba..cc490f0 100644 (file)
@@ -14,14 +14,11 @@ Author: Petar Koretic <petar.koretic@sartura.hr>
 
 ]]--
 
-module("luci.controller.lxc", package.seeall)
-
-require "ubus"
-local conn = ubus.connect()
-if not conn then
-    error("Failed to connect to ubus")
-end
+local uci = require "luci.model.uci"
+local util = require "luci.util"
+local nixio = require "nixio"
 
+module("luci.controller.lxc", package.seeall)
 
 function fork_exec(command)
        local pid = nixio.fork()
@@ -71,55 +68,52 @@ function index()
 end
 
 function lxc_get_downloadable()
-       luci.http.prepare_content("application/json")
-
-       local f = io.popen('uname -m', 'r')
-       local target = f:read('*a')
-       f:close()
-       target = target:gsub("^%s*(.-)%s*$", "%1")
-
+       local target = lxc_get_arch_target()
        local templates = {}
 
-       local f = io.popen('lxc-create -n just_want_to_list_available_lxc_templates -t download -- --list', 'r')
+       local f = io.popen('sh /usr/share/lxc/templates/lxc-download --list --no-validate --server %s'
+               % util.shellquote(uci.cursor():get("lxc", "lxc", "url")), 'r')
 
+       local line
        for line in f:lines() do
-               local dist,version = line:match("^(%S+)%s+(%S+)%s+" .. target .. "%s+default%s+%S+$")
-               if dist~=nil and version~=nil then templates[#templates + 1] = dist .. ":" .. version end
+               local dist, version, dist_target = line:match("^(%S+)%s+(%S+)%s+(%S+)%s+default%s+%S+$")
+               if dist and version and dist_target == target then
+                       templates[#templates+1] = "%s:%s" %{ dist, version }
+               end
        end
 
        f:close()
+
+       luci.http.prepare_content("application/json")
        luci.http.write_json(templates)
 end
 
 function lxc_create(lxc_name, lxc_template)
        luci.http.prepare_content("text/plain")
 
-       local uci = require("uci").cursor()
-
-       local url = uci:get("lxc", "lxc", "url")
-
        if not pcall(dofile, "/etc/openwrt_release") then
                return luci.http.write("1")
        end
 
-       local f = io.popen('uname -m', 'r')
-       local target = f:read('*a')
-       f:close()
-       target = target:gsub("^%s*(.-)%s*$", "%1")
-
-       local lxc_dist = lxc_template:gsub("(.*):(.*)", '%1')
-       local lxc_release = lxc_template:gsub("(.*):(.*)", '%2')
-
-       local data = conn:call("lxc", "create", { name = lxc_name, template = "download", args = { "--server", url,  "--no-validate", "--dist", lxc_dist, "--release", lxc_release, "--arch", target } } )
-
-       luci.http.write(data)
+       local lxc_dist, lxc_release = lxc_template:match("^(.+):(.+)$")
+
+       luci.http.write(util.ubus("lxc", "create", {
+               name = lxc_name,
+               template = "download",
+               args = {
+                       "--server", uci.cursor():get("lxc", "lxc", "url"),
+                       "--no-validate",
+                       "--dist", lxc_dist,
+                       "--release", lxc_release,
+                       "--arch", lxc_get_arch_target()
+               }
+       }))
 end
 
 function lxc_action(lxc_action, lxc_name)
-       luci.http.prepare_content("application/json")
-
-       local data, ec = conn:call("lxc", lxc_action, lxc_name and { name = lxc_name} or {} )
+       local data, ec = util.ubus("lxc", lxc_action, lxc_name and { name = lxc_name } or {})
 
+       luci.http.prepare_content("application/json")
        luci.http.write_json(ec and {} or data)
 end
 
@@ -165,3 +159,22 @@ function lxc_configuration_set(lxc_name)
        luci.http.write("0")
 end
 
+function lxc_get_arch_target()
+       local target = nixio.uname().machine
+       local target_map = {
+               armv5  = "armel",
+               armv6  = "armel",
+               armv7  = "armhf",
+               armv8  = "arm64",
+               x86_64 = "amd64"
+       }
+
+       local k, v
+       for k, v in pairs(target_map) do
+               if target:find(k) then
+                       return v
+               end
+       end
+
+       return target
+end
index 5572c73..3b35951 100644 (file)
@@ -1,6 +1,3 @@
-#
-# lxc uci configuration
-#
 
 config lxc 'lxc'
-       option url 'virtualwrt.org/containers/'
+       option url 'images.linuxcontainers.org'
index d65cd3a..c719cb1 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LuCI support for the MWAN3 multiwan hotplug script
-LUCI_DEPENDS:=+mwan3 +luci-mod-admin-full +luci-app-firewall +luci-lib-nixio
+LUCI_DEPENDS:=+mwan3 +libuci-lua +luci-mod-admin-full +luci-app-firewall +luci-lib-nixio
 LUCI_PKGARCH:=all
 PKG_LICENSE:=GPLv2
 
index 64ee9f5..d5fc4a3 100644 (file)
@@ -56,7 +56,7 @@ function index()
                arcombine(cbi("mwan/rule"), cbi("mwan/ruleconfig")),
                _("Rules"), 40).leaf = true
        entry({"admin", "network", "mwan", "notify"},
-               cbi("mwan/notify"),
+               form("mwan/notify"),
                _("Notification"), 50).leaf = true
 end
 
@@ -85,7 +85,8 @@ function diagnosticsData(interface, task)
        function getInterfaceNumber(interface)
                local number = 0
                local interfaceNumber
-               uci.cursor():foreach("mwan3", "interface",
+               local uci = require "luci.model.uci".cursor()
+               uci:foreach("mwan3", "interface",
                        function (section)
                                number = number+1
                                if section[".name"] == interface then
@@ -98,7 +99,7 @@ function diagnosticsData(interface, task)
 
        function diag_command(cmd, addr)
                if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
-                       local util = io.popen(cmd % addr)
+                       local util = io.popen(cmd % ut.shellquote(addr))
                        if util then
                                while true do
                                        local ln = util:read("*l")
@@ -130,7 +131,7 @@ function diagnosticsData(interface, task)
        local results = ""
        local number = getInterfaceNumber(interface)
 
-       local uci = uci.cursor(nil, "/var/state")
+       local uci = require "luci.model.uci".cursor(nil, "/var/state")
        local device = uci:get("network", interface, "ifname")
 
        luci.http.prepare_content("text/plain")
@@ -138,7 +139,7 @@ function diagnosticsData(interface, task)
                if task == "ping_gateway" then
                        local gateway = get_gateway(interface)
                        if gateway ~= nil then
-                               diag_command("ping -c 5 -W 1 %q 2>&1", gateway)
+                               diag_command("ping -c 5 -W 1 %s 2>&1", gateway)
                        else
                                luci.http.prepare_content("text/plain")
                                luci.http.write(string.format("No gateway for interface %s found.", interface))
@@ -147,7 +148,7 @@ function diagnosticsData(interface, task)
                        local trackips = uci:get("mwan3", interface, "track_ip")
                        if #trackips > 0 then
                                for i in pairs(trackips) do
-                                       diag_command("ping -c 5 -W 1 %q 2>&1", trackips[i])
+                                       diag_command("ping -c 5 -W 1 %s 2>&1", trackips[i])
                                end
                        else
                                luci.http.write(string.format("No tracking Hosts for interface %s defined.", interface))
@@ -185,10 +186,10 @@ function diagnosticsData(interface, task)
                                luci.http.write(string.format("Routing table %s for interface %s not found", number, interface))
                        end
                elseif task == "hotplug_ifup" then
-                       os.execute(string.format("/usr/sbin/mwan3 ifup %s", interface))
+                       os.execute(string.format("/usr/sbin/mwan3 ifup %s", ut.shellquote(interface)))
                        luci.http.write(string.format("Hotplug ifup sent to interface %s", interface))
                elseif task == "hotplug_ifdown" then
-                       os.execute(string.format("/usr/sbin/mwan3 ifdown %s", interface))
+                       os.execute(string.format("/usr/sbin/mwan3 ifdown %s", ut.shellquote(interface)))
                        luci.http.write(string.format("Hotplug ifdown sent to interface %s", interface))
                else
                        luci.http.write("Unknown task")
index 4b1a070..162b388 100644 (file)
@@ -3,42 +3,43 @@
 -- Licensed to the public under the GNU General Public License v2.
 
 dsp = require "luci.dispatcher"
+uci = require "uci"
 
 
-function interfaceWarnings(overview, count)
+function interfaceWarnings(overview, count, iface_max)
        local warnings = ""
-       if count <= 250 then
-               warnings = string.format("<strong>%s</strong></br>",
-                       translatef("There are currently %d of 250 supported interfaces configured", count)
+       if count <= iface_max then
+               warnings = string.format("<strong>%s</strong><br />",
+                       translatef("There are currently %d of %d supported interfaces configured", count, iface_max)
                        )
        else
-               warnings = string.format("<strong>%s</strong></br>",
-                       translatef("WARNING: %d interfaces are configured exceeding the maximum of 250!", count)
+               warnings = string.format("<strong>%s</strong><br />",
+                       translatef("WARNING: %d interfaces are configured exceeding the maximum of %d!", count, iface_max)
                        )
        end
 
        for i, k in pairs(overview) do
                if overview[i]["network"] == false then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
                                        translatef("WARNING: Interface %s are not found in /etc/config/network", i)
                                        )
                end
 
                if overview[i]["default_route"] == false then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
                                translatef("WARNING: Interface %s has no default route in the main routing table", i)
                                )
                end
 
                if overview[i]["reliability"] == false then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
                                translatef("WARNING: Interface %s has a higher reliability " ..
                                "requirement than tracking hosts (%d)", i, overview[i]["tracking"])
                                )
                end
 
                if overview[i]["duplicate_metric"] == true then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
                                translatef("WARNING: Interface %s has a duplicate metric %s configured", i, overview[i]["metric"])
                                )
                end
@@ -103,16 +104,43 @@ function configCheck()
                        end
                end
        )
-       return overview, count
+
+       -- calculate iface_max usage from firewall mmx_mask
+       function bit(p)
+               return 2 ^ (p - 1)
+       end
+       function hasbit(x, p)
+               return x % (p + p) >= p
+       end
+       function setbit(x, p)
+               return hasbit(x, p) and x or x + p
+       end
+
+       local uci = require("uci").cursor(nil, "/var/state")
+       local mmx_mask = uci:get("mwan3", "globals", "mmx_mask") or "0x3F00"
+       local number = tonumber(mmx_mask, 16)
+       local bits = 0
+       local iface_max = 0
+       for i=1,16 do
+               if hasbit(number, bit(i)) then
+                       bits = bits + 1
+                       iface_max = setbit( iface_max, bit(bits))
+               end
+       end
+
+       -- subtract blackhole, unreachable and default table from iface_max
+       iface_max = iface_max - 3
+
+       return overview, count, iface_max
 end
 
 m5 = Map("mwan3", translate("MWAN - Interfaces"),
        interfaceWarnings(configCheck()))
 
 mwan_interface = m5:section(TypedSection, "interface", nil,
-       translate("MWAN supports up to 250 physical and/or logical interfaces<br />" ..
+       translate("MWAN supports up to 252 physical and/or logical interfaces<br />" ..
        "MWAN requires that all interfaces have a unique metric configured in /etc/config/network<br />" ..
-       "Names must match the interface name found in /etc/config/network (see advanced tab)<br />" ..
+       "Names must match the interface name found in /etc/config/network<br />" ..
        "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
        "Interfaces may not share the same name as configured members, policies or rules"))
 mwan_interface.addremove = true
@@ -142,7 +170,7 @@ track_method.rawhtml = true
 function track_method.cfgvalue(self, s)
        local tracked = self.map:get(s, "track_ip")
        if tracked then
-               return self.map:get(s, "track_method") or "&#8212;"
+               return self.map:get(s, "track_method") or "ping"
        else
                return "&#8212;"
        end
@@ -153,7 +181,7 @@ reliability.rawhtml = true
 function reliability.cfgvalue(self, s)
        local tracked = self.map:get(s, "track_ip")
        if tracked then
-               return self.map:get(s, "reliability") or "&#8212;"
+               return self.map:get(s, "reliability") or "1"
        else
                return "&#8212;"
        end
@@ -168,7 +196,7 @@ function interval.cfgvalue(self, s)
                if intervalValue then
                        return intervalValue .. "s"
                else
-                       return "&#8212;"
+                       return "5s"
                end
        else
                return "&#8212;"
@@ -180,7 +208,7 @@ down.rawhtml = true
 function down.cfgvalue(self, s)
        local tracked = self.map:get(s, "track_ip")
        if tracked then
-               return self.map:get(s, "down") or "&#8212;"
+               return self.map:get(s, "down") or "3"
        else
                return "&#8212;"
        end
@@ -191,7 +219,7 @@ up.rawhtml = true
 function up.cfgvalue(self, s)
        local tracked = self.map:get(s, "track_ip")
        if tracked then
-               return self.map:get(s, "up") or "&#8212;"
+               return self.map:get(s, "up") or "3"
        else
                return "&#8212;"
        end
index 3a896d3..a439502 100644 (file)
@@ -171,7 +171,7 @@ metric = mwan_interface:option(DummyValue, "metric", translate("Metric"),
        translate("This displays the metric assigned to this interface in /etc/config/network"))
 metric.rawhtml = true
 function metric.cfgvalue(self, s)
-       local uci = uci.cursor(nil, "/var/state")
+       local uci = require "luci.model.uci".cursor(nil, "/var/state")
        local metric = uci:get("network", arg[1], "metric")
        if metric then
                return metric
index 6f87a3d..4c6e210 100644 (file)
@@ -23,7 +23,11 @@ f = m5:section(SimpleSection, nil,
        "<br />" ..
        "There are three main environment variables that are passed to this script.<br />" ..
        "<br />" ..
-       "$ACTION Either \"ifup\" or \"ifdown\"<br />" ..
+       "$ACTION <br />" ..
+       "* \"ifup\" Is called by netifd and mwan3track <br />" ..
+       "* \"ifdown\" Is called by netifd and mwan3track <br />" ..
+       "* \"connected\" Is only called by mwan3track if tracking was successful <br />" ..
+       "* \"disconnected\" Is only called by mwan3track if tracking has failed <br />" ..
        "$INTERFACE Name of the interface which went up or down (e.g. \"wan\" or \"wwan\")<br />" ..
        "$DEVICE Physical device name which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br />" ..
        "<br />"))
index 7f12782..4543260 100644 (file)
@@ -3,6 +3,7 @@
 -- Licensed to the public under the GNU General Public License v2.
 
 dsp = require "luci.dispatcher"
+uci = require "uci"
 
 
 function policyCheck()
@@ -24,8 +25,8 @@ function policyError(policy_error)
        local warnings = ""
        for i, k in pairs(policy_error) do
                if policy_error[i] == true then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
-                               translatef("WARNING: Policie %s has exceeding the maximum name of 15 characters", i)
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
+                               translatef("WARNING: Policy %s has exceeding the maximum name of 15 characters", i)
                                )
                end
        end
@@ -38,9 +39,11 @@ m5 = Map("mwan3", translate("MWAN - Policies"),
 
 mwan_policy = m5:section(TypedSection, "policy", nil,
        translate("Policies are profiles grouping one or more members controlling how MWAN distributes traffic<br />" ..
-       "Member interfaces with lower metrics are used first. Interfaces with the same metric load-balance<br />" ..
+       "Member interfaces with lower metrics are used first<br />" ..
+       "Member interfaces with the same metric will be load-balanced<br />" ..
        "Load-balanced member interfaces distribute more traffic out those with higher weights<br />" ..
-       "Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be 15 characters or less<br />" ..
+       "Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br />" ..
+       "Names must be 15 characters or less<br />" ..
        "Policies may not share the same name as configured interfaces, members or rules"))
 mwan_policy.addremove = true
 mwan_policy.dynamic = false
index cb2a995..f0b94bd 100644 (file)
@@ -3,6 +3,7 @@
 -- Licensed to the public under the GNU General Public License v2.
 
 dsp = require "luci.dispatcher"
+uci = require "uci"
 
 
 function ruleCheck()
@@ -28,7 +29,7 @@ function ruleWarn(rule_error)
        local warnings = ""
        for i, k in pairs(rule_error) do
                if rule_error[i] == true then
-                       warnings = warnings .. string.format("<strong>%s</strong></br>",
+                       warnings = warnings .. string.format("<strong>%s</strong><br />",
                                translatef("WARNING: Rule %s have a port configured with no or improper protocol specified!", i)
                                )
                end
index 86b5ac6..49d120c 100644 (file)
@@ -15,29 +15,35 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_
                                for ( var iface in status.interfaces)
                                {
                                        var state = '';
+                                       var css = ''
                                        switch (status.interfaces[iface].status)
                                        {
                                                case 'online':
-                                                       state = '<%:Online (tracking active)%>';
-                                                       break;
-                                               case 'notMonitored':
-                                                       state = '<%:Online (tracking off)%>';
+                                                       state = '<%:Online%>';
+                                                       css = 'success';
                                                        break;
                                                case 'offline':
                                                        state = '<%:Offline%>';
+                                                       css = 'danger';
                                                        break;
                                                default:
                                                        state = '<%:Disabled%>';
+                                                       css = 'warning';
                                                        break;
                                        }
                                        statusview += String.format(
+                                               '<div class="alert-message %s">',
+                                               css
+                                       );
+                                       statusview += String.format(
                                                '<div><strong>Interface: </strong>%s</div>',
                                                iface
                                        );
                                        statusview += String.format(
-                                               '<div><strong>Status: </strong>%s</div></br></br>',
+                                               '<div><strong>Status: </strong>%s</div>',
                                                state
                                        );
+                                       statusview += '</div>'
                                }
                                statusDiv.innerHTML = statusview;
                        }
@@ -49,9 +55,21 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_
        );
 //]]></script>
 
+<style type="text/css">
+       #mwan_status_text > div {
+               display: inline-block;
+               margin: 1rem;
+               padding: 1rem;
+               width: 10rem;
+               float: left;
+               line-height: 125%;
+       }
+</style>
+
 <fieldset id="interface_field" class="cbi-section">
        <legend><%:MWAN Interfaces%></legend>
        <div id="mwan_status_text">
-               <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%>
+               <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" />
+               <%:Collecting data...%>
        </div>
 </fieldset>
index 70eac72..bcc23be 100644 (file)
@@ -18,9 +18,7 @@
        XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "detailed_status")%>', null,
                function(x)
                {
-                       var legend = document.getElementById('diag-rc-legend');
                        var output = document.getElementById('diag-rc-output');
-                       legend.style.display = 'none';
                        output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
                }
        );
@@ -32,9 +30,9 @@
        <div><strong><%:INFO: MWAN not running%></strong></div>
        <%end%>
        <fieldset class="cbi-section">
-               <legend id="diag-rc-legend"><%:Collecting data...%></legend>
                <span id="diag-rc-output">
                        <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
+                       <%:Collecting data...%>
                </span>
        </fieldset>
 </div>
index f1c5d8f..22f4734 100644 (file)
@@ -31,7 +31,6 @@
 
        function update_status(iface, task)
        {
-               var legend = document.getElementById('diag-rc-legend');
                var output = document.getElementById('diag-rc-output');
 
                output.innerHTML =
@@ -45,7 +44,6 @@
                stxhr.post('<%=url('admin/status/mwan')%>/diagnostics_display' + '/' + iface + '/' + task, { token: '<%=token%>' },
                        function(x)
                        {
-                               legend.style.display = 'none';
                                output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
                        }
                );
@@ -86,7 +84,6 @@
                </fieldset>
        </div>
        <fieldset class="cbi-section" style="display:none">
-               <legend id="diag-rc-legend"><%:Collecting data...%></legend>
                <span id="diag-rc-output"></span>
        </fieldset>
 </form>
index cb47696..4518bd6 100644 (file)
@@ -15,6 +15,7 @@
 
 <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
 
-<%+mwan/overview_status_interface%>
-
+<div class="cbi-map">
+       <%+mwan/overview_status_interface%>
+</div>
 <%+footer%>
index 77d0092..f60e0da 100644 (file)
@@ -18,9 +18,7 @@
        XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "troubleshooting_display")%>', null,
                function(x)
                {
-                       var legend = document.getElementById('diag-rc-legend');
                        var output = document.getElementById('diag-rc-output');
-                       legend.style.display = 'none';
                        output.innerHTML = String.format('<pre>%h</pre>', x.responseText);
                }
        );
@@ -32,9 +30,9 @@
        <div><strong><%:INFO: MWAN not running%></strong></div>
        <%end%>
        <fieldset class="cbi-section">
-               <legend id="diag-rc-legend"><%:Collecting data...%></legend>
                <span id="diag-rc-output">
                        <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" />
+                       <%:Collecting data...%>
                </span>
        </fieldset>
 </div>
index 4b3662a..6ee351c 100644 (file)
@@ -103,6 +103,9 @@ msgstr "ホットプラグ ifdown"
 msgid "Hotplug ifup"
 msgstr "ホットプラグ ifup"
 
+msgid "INFO: MWAN not running"
+msgstr ""
+
 msgid "IPset"
 msgstr "IPset"
 
@@ -174,8 +177,8 @@ msgstr ""
 msgid "MWAN Interface Configuration - %s"
 msgstr "MWAN インターフェース設定 - %s"
 
-msgid "MWAN Interface Live Status"
-msgstr "MWAN インターフェース Live ステータス"
+msgid "MWAN Interfaces"
+msgstr ""
 
 msgid "MWAN Member Configuration - %s"
 msgstr "MWAN メンバー設定 - %s"
@@ -195,24 +198,21 @@ msgstr ""
 msgid "MWAN Status - Troubleshooting"
 msgstr ""
 
-msgid "MWAN status - Interface Live Status"
-msgstr ""
-
 msgid ""
-"MWAN supports up to 250 physical and/or logical interfaces<br />MWAN "
+"MWAN supports up to 252 physical and/or logical interfaces<br />MWAN "
 "requires that all interfaces have a unique metric configured in /etc/config/"
 "network<br />Names must match the interface name found in /etc/config/"
-"network (see advanced tab)<br />Names may contain characters A-Z, a-z, 0-9, "
-"_ and no spaces<br />Interfaces may not share the same name as configured "
-"members, policies or rules"
+"network<br />Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br /"
+">Interfaces may not share the same name as configured members, policies or "
+"rules"
 msgstr ""
-"MWAN は、250個までの物理または論理、あるいは両方のインターフェースをサポート"
+"MWAN は、252個までの物理または論理、あるいは両方のインターフェースをサポート"
 "します。<br />MWAN は、全てのインターフェースが /etc/config/network で設定さ"
 "れるユニークなメトリックを持つことを必要とします。<br />下記 \"インターフェー"
 "ス\" の名前は、 /etc/config/network に存在するインターフェース名と同じでなけ"
-"ればなりません(詳細設定タブを確認)。<br />名前は A-Z, a-z, 0-9, _ を含むこ"
-"ã\81¨ã\81\8cã\81§ã\81\8dã\81¾ã\81\99ã\81\8cã\80\81ã\82¹ã\83\9aã\83¼ã\82¹ã\81¯ä½¿ç\94¨ã\81§ã\81\8dã\81¾ã\81\9bã\82\93ã\80\82<br />ã\82¤ã\83³ã\82¿ã\83¼ã\83\95ã\82§ã\83¼ã\82¹ã\81«ã\81¯ã\80\81設å®\9aæ¸\88"
-"ã\81¿ã\81®ã\83¡ã\83³ã\83\90ã\83¼ã\82\84ã\83\9dã\83ªã\82·ã\83¼ã\80\81ã\83«ã\83¼ã\83«ã\81¨å\90\8cã\81\98å\90\8då\89\8dã\82\92使ç\94¨ã\81\99ã\82\8bã\81\93ã\81¨ã\81¯ã\81§ã\81\8dã\81¾ã\81\9bã\82\93ã\80\82"
+"ればなりません。<br />名前は A-Z, a-z, 0-9, _ を含むことができますが、スペー"
+"ã\82¹ã\81¯ä½¿ç\94¨ã\81§ã\81\8dã\81¾ã\81\9bã\82\93ã\80\82<br />ã\82¤ã\83³ã\82¿ã\83¼ã\83\95ã\82§ã\83¼ã\82¹ã\81«ã\81¯ã\80\81設å®\9aæ¸\88ã\81¿ã\81®ã\83¡ã\83³ã\83\90ã\83¼ã\82\84ã\83\9dã\83ª"
+"シー、ルールと同じ名前を使用することはできません。"
 
 msgid ""
 "May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or "
@@ -268,12 +268,6 @@ msgstr "オフライン"
 msgid "Online"
 msgstr "オンライン"
 
-msgid "Online (tracking active)"
-msgstr "オンライン(追跡実行中)"
-
-msgid "Online (tracking off)"
-msgstr "オンライン(追跡オフ)"
-
 msgid "Ping count"
 msgstr "Ping 回数"
 
@@ -304,11 +298,11 @@ msgstr "ポリシー"
 msgid ""
 "Policies are profiles grouping one or more members controlling how MWAN "
 "distributes traffic<br />Member interfaces with lower metrics are used "
-"first. Interfaces with the same metric load-balance<br />Load-balanced "
-"member interfaces distribute more traffic out those with higher weights<br /"
-">Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be "
-"15 characters or less<br />Policies may not share the same name as "
-"configured interfaces, members or rules"
+"first<br />Member interfaces with the same metric will be load-balanced<br /"
+">Load-balanced member interfaces distribute more traffic out those with "
+"higher weights<br />Names may contain characters A-Z, a-z, 0-9, _ and no "
+"spaces<br />Names must be 15 characters or less<br />Policies may not share "
+"the same name as configured interfaces, members or rules"
 msgstr ""
 "ポリシーは、MWANがどのようにトラフィックの分配を行うかを制御する、1つ以上のメ"
 "ンバーをグループ化するプロファイルです。<br />最小のメトリックを持つメンバー "
@@ -370,8 +364,8 @@ msgstr "CIDR 表記のサポート(例: \"192.168.100.0/24\")"
 msgid "Task"
 msgstr ""
 
-msgid "There are currently %d of 250 supported interfaces configured"
-msgstr "現在、250個中 %d 個のサポートされたインターフェースが設定済みです。"
+msgid "There are currently %d of %d supported interfaces configured"
+msgstr "現在、%d 個中 %d 個のサポートされたインターフェースが設定済みです。"
 
 msgid ""
 "This displays the metric assigned to this interface in /etc/config/network"
@@ -395,21 +389,14 @@ msgid ""
 "will<br />be executed with each netifd hotplug interface event<br />on "
 "interfaces for which mwan3 is enabled.<br /><br />There are three main "
 "environment variables that are passed to this script.<br /><br />$ACTION "
-"Either \"ifup\" or \"ifdown\"<br />$INTERFACE Name of the interface which "
-"went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE Physical device name "
-"which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br /><br />"
-msgstr ""
-"このセクションでは、 \"/etc/mwan3.user\" の内容を変更することができます。"
-"<br />このファイルは、 sysupgrade 時に保持されます。<br /><br />注意: <br />"
-"このファイルは、シェルスクリプトとして解釈されます。<br />スクリプトの1行目"
-"は、&#34;#!bin/sh&#34; である必要があります(クォーテーション不要)。<br /># "
-"で始まる行はコメントであり、実行されません。<br />mwan3 のカスタム動作をここ"
-"に入力してください。これらは、 mwan3 が有効なインターフェースの<br />netifd "
-"ホットプラグ インターフェース イベント毎に実行されます。<br /><br />主に3つの"
-"環境変数が利用可能です。<br /><br />$ACTION - \"ifup\" および \"ifdown\"<br /"
-">$INTERFACE - Up または Down が行われたインターフェース名(例: \"wan\" や "
-"\"wwan\")<br />$DEVICE - Up または Down が行われた物理デバイス名(例: "
-"\"eth0\" や \"wwan0\")<br /><br />"
+"<br />* \"ifup\" Is called by netifd and mwan3track <br />* \"ifdown\" Is "
+"called by netifd and mwan3track <br />* \"connected\" Is only called by "
+"mwan3track if tracking was successful <br />* \"disconnected\" Is only "
+"called by mwan3track if tracking has failed <br />$INTERFACE Name of the "
+"interface which went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE "
+"Physical device name which interface went up or down (e.g. \"eth0\" or "
+"\"wwan0\")<br /><br />"
+msgstr ""
 
 msgid "Tracking hostname or IP address"
 msgstr "追跡ホスト名または IP アドレス"
@@ -441,9 +428,9 @@ msgstr ""
 msgid "View the content of /etc/protocols for protocol description"
 msgstr ""
 
-msgid "WARNING: %d interfaces are configured exceeding the maximum of 250!"
+msgid "WARNING: %d interfaces are configured exceeding the maximum of %d!"
 msgstr ""
-"警告: %d 個のインターフェースが、最大個数の 250個 を超えて設定されています!"
+"警告: %d 個のインターフェースが、最大個数の %d 個 を超えて設定されています!"
 
 msgid "WARNING: Interface %s are not found in /etc/config/network"
 msgstr ""
@@ -459,7 +446,7 @@ msgstr ""
 msgid "WARNING: Interface %s has no default route in the main routing table"
 msgstr ""
 
-msgid "WARNING: Policie %s has exceeding the maximum name of 15 characters"
+msgid "WARNING: Policy %s has exceeding the maximum name of 15 characters"
 msgstr ""
 
 msgid ""
@@ -503,6 +490,41 @@ msgstr "never"
 msgid "unreachable (reject)"
 msgstr "unreachable (reject)"
 
+#~ msgid "Online (tracking active)"
+#~ msgstr "オンライン(追跡実行中)"
+
+#~ msgid "MWAN Interface Live Status"
+#~ msgstr "MWAN インターフェース Live ステータス"
+
+#~ msgid "Online (tracking off)"
+#~ msgstr "オンライン(追跡オフ)"
+
+#~ msgid ""
+#~ "This section allows you to modify the content of \"/etc/mwan3.user\".<br /"
+#~ ">The file is also preserved during sysupgrade.<br /><br />Notes:<br /"
+#~ ">This file is interpreted as a shell script.<br />The first line of the "
+#~ "script must be &#34;#!/bin/sh&#34; without quotes.<br />Lines beginning "
+#~ "with # are comments and are not executed.<br />Put your custom mwan3 "
+#~ "action here, they will<br />be executed with each netifd hotplug "
+#~ "interface event<br />on interfaces for which mwan3 is enabled.<br /><br /"
+#~ ">There are three main environment variables that are passed to this "
+#~ "script.<br /><br />$ACTION Either \"ifup\" or \"ifdown\"<br />$INTERFACE "
+#~ "Name of the interface which went up or down (e.g. \"wan\" or \"wwan"
+#~ "\")<br />$DEVICE Physical device name which interface went up or down (e."
+#~ "g. \"eth0\" or \"wwan0\")<br /><br />"
+#~ msgstr ""
+#~ "このセクションでは、 \"/etc/mwan3.user\" の内容を変更することができます。"
+#~ "<br />このファイルは、 sysupgrade 時に保持されます。<br /><br />注意: "
+#~ "<br />このファイルは、シェルスクリプトとして解釈されます。<br />スクリプト"
+#~ "の1行目は、&#34;#!bin/sh&#34; である必要があります(クォーテーション不"
+#~ "要)。<br /># で始まる行はコメントであり、実行されません。<br />mwan3 のカ"
+#~ "スタム動作をここに入力してください。これらは、 mwan3 が有効なインター"
+#~ "フェースの<br />netifd ホットプラグ インターフェース イベント毎に実行され"
+#~ "ます。<br /><br />主に3つの環境変数が利用可能です。<br /><br />$ACTION - "
+#~ "\"ifup\" および \"ifdown\"<br />$INTERFACE - Up または Down が行われたイン"
+#~ "ターフェース名(例: \"wan\" や \"wwan\")<br />$DEVICE - Up または Down が"
+#~ "行われた物理デバイス名(例: \"eth0\" や \"wwan0\")<br /><br />"
+
 #~ msgid "Currently Configured Interfaces"
 #~ msgstr "設定済みインターフェース"
 
index 8d5742c..11721ec 100644 (file)
@@ -107,6 +107,9 @@ msgstr "Hotplug ifdown"
 msgid "Hotplug ifup"
 msgstr "Hotplug ifup"
 
+msgid "INFO: MWAN not running"
+msgstr ""
+
 msgid "IPset"
 msgstr "IPset"
 
@@ -177,8 +180,8 @@ msgstr "MWAN - Правила"
 msgid "MWAN Interface Configuration - %s"
 msgstr "Настройка интерфейсов MWAN  - %s"
 
-msgid "MWAN Interface Live Status"
-msgstr "Состояние интерфейса MWAN в настоящее время"
+msgid "MWAN Interfaces"
+msgstr ""
 
 msgid "MWAN Member Configuration - %s"
 msgstr "MWAN настройка узлов - %s"
@@ -198,24 +201,20 @@ msgstr "Состояние MWAN - Диагностика"
 msgid "MWAN Status - Troubleshooting"
 msgstr "Состояние MWAN - Устранение неполадок"
 
-msgid "MWAN status - Interface Live Status"
-msgstr "Состояние MWAN - Интерфейс в настоящее время"
-
 msgid ""
-"MWAN supports up to 250 physical and/or logical interfaces<br />MWAN "
+"MWAN supports up to 252 physical and/or logical interfaces<br />MWAN "
 "requires that all interfaces have a unique metric configured in /etc/config/"
 "network<br />Names must match the interface name found in /etc/config/"
-"network (see advanced tab)<br />Names may contain characters A-Z, a-z, 0-9, "
-"_ and no spaces<br />Interfaces may not share the same name as configured "
-"members, policies or rules"
+"network<br />Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br /"
+">Interfaces may not share the same name as configured members, policies or "
+"rules"
 msgstr ""
-"MWAN поддерживает до 250 физических и / или логических интерфейсов.<br /"
+"MWAN поддерживает до 252 физических и / или логических интерфейсов.<br /"
 ">MWAN требует, чтобы все интерфейсы имели уникальную метрику, настроенную в "
 "config файле /etc/config/network.<br />Имена должны соответствовать имени "
-"интерфейса, найденному в /etc/config/network (см. соответствующую страницу)."
-"<br />Имена могут содержать символы A-Z, a-z, 0-9, _ и пробелы.<br /"
-">Интерфейсы не могут иметь одинаковые имена с настроенными узлами, "
-"политиками или правилами."
+"интерфейса, найденному в /etc/config/network.<br />Имена могут содержать "
+"символы A-Z, a-z, 0-9, _ и пробелы.<br />Интерфейсы не могут иметь "
+"одинаковые имена с настроенными узлами, политиками или правилами."
 
 msgid ""
 "May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or "
@@ -270,12 +269,6 @@ msgstr "Отключен"
 msgid "Online"
 msgstr "Онлайн"
 
-msgid "Online (tracking active)"
-msgstr "Онлайн (отслеживание активно)"
-
-msgid "Online (tracking off)"
-msgstr "Онлайн  (отслеживание отключено)"
-
 msgid "Ping count"
 msgstr "Кол-во пинг-запросов"
 
@@ -306,11 +299,11 @@ msgstr "Политики"
 msgid ""
 "Policies are profiles grouping one or more members controlling how MWAN "
 "distributes traffic<br />Member interfaces with lower metrics are used "
-"first. Interfaces with the same metric load-balance<br />Load-balanced "
-"member interfaces distribute more traffic out those with higher weights<br /"
-">Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be "
-"15 characters or less<br />Policies may not share the same name as "
-"configured interfaces, members or rules"
+"first<br />Member interfaces with the same metric will be load-balanced<br /"
+">Load-balanced member interfaces distribute more traffic out those with "
+"higher weights<br />Names may contain characters A-Z, a-z, 0-9, _ and no "
+"spaces<br />Names must be 15 characters or less<br />Policies may not share "
+"the same name as configured interfaces, members or rules"
 msgstr ""
 "Политики это профили, объединяющие один или несколько узлов, контролирующих, "
 "как MWAN распределяет трафик.<br />Сначала используются интерфейсы-узлы с "
@@ -385,8 +378,8 @@ msgstr "Поддерживает CIDR нотацию (например '192.168.
 msgid "Task"
 msgstr "Задача"
 
-msgid "There are currently %d of 250 supported interfaces configured"
-msgstr "В настоящее время настроено %d из 250 поддерживаемых интерфейсов."
+msgid "There are currently %d of %d supported interfaces configured"
+msgstr "В настоящее время настроено %d из %d поддерживаемых интерфейсов."
 
 msgid ""
 "This displays the metric assigned to this interface in /etc/config/network"
@@ -411,23 +404,14 @@ msgid ""
 "will<br />be executed with each netifd hotplug interface event<br />on "
 "interfaces for which mwan3 is enabled.<br /><br />There are three main "
 "environment variables that are passed to this script.<br /><br />$ACTION "
-"Either \"ifup\" or \"ifdown\"<br />$INTERFACE Name of the interface which "
-"went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE Physical device name "
-"which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br /><br />"
+"<br />* \"ifup\" Is called by netifd and mwan3track <br />* \"ifdown\" Is "
+"called by netifd and mwan3track <br />* \"connected\" Is only called by "
+"mwan3track if tracking was successful <br />* \"disconnected\" Is only "
+"called by mwan3track if tracking has failed <br />$INTERFACE Name of the "
+"interface which went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE "
+"Physical device name which interface went up or down (e.g. \"eth0\" or "
+"\"wwan0\")<br /><br />"
 msgstr ""
-"Страница позволяет изменять содержимое файла mwan3.user (/etc/mwan3.user)."
-"<br />Файл также сохраняется во время перепрошивки sysupgrade-совместимым "
-"образом.<br /><br />Примечание:<br />Этот файл интерпретируется как shell "
-"скрипт.<br />Первая строка скрипта должна быть &#34;#!/bin/sh&#34; без "
-"кавычек.<br />Строки начинающиеся с #, являются комментариями и не "
-"исполняются.<br />Поместите свои пользовательские действия mwan3 здесь, они "
-"будут<br />выполняться с каждым событием netifd hotplug интерфейса<br />на "
-"интерфейсах, для которых включен mwan3.<br /><br />В этот сценарий "
-"передаются три основные переменные среды.<br /><br />$ACTION либо \"ifup\" "
-"или \"ifdown\"<br />$INTERFACE - имя интерфейса, который включили или "
-"отключили (например, 'wan' или 'wwan') <br />$DEVICE - имя физического "
-"устройства, чей интерфейс включили или отключили  (например, 'eth0' или "
-"'wwan0')<br /><br />."
 
 msgid "Tracking hostname or IP address"
 msgstr "Отслеживание имени хоста или IP-адреса"
@@ -459,10 +443,10 @@ msgstr ""
 msgid "View the content of /etc/protocols for protocol description"
 msgstr "Просмотр содержимого файла /etc/protocols для описания протокола."
 
-msgid "WARNING: %d interfaces are configured exceeding the maximum of 250!"
+msgid "WARNING: %d interfaces are configured exceeding the maximum of %d!"
 msgstr ""
 "ВНИМАНИЕ: Интерфейсы %d настроены, превышая установленное ограничение в "
-"количестве 250шт.!"
+"количестве %dшт.!"
 
 msgid "WARNING: Interface %s are not found in /etc/config/network"
 msgstr "ВНИМАНИЕ: Интерфейс %s не настроен в config файле /etc/config/network."
@@ -483,7 +467,7 @@ msgstr ""
 "ВНИМАНИЕ: Интерфейс %s не имеет маршрута по умолчанию в основной таблице "
 "маршрутизации."
 
-msgid "WARNING: Policie %s has exceeding the maximum name of 15 characters"
+msgid "WARNING: Policy %s has exceeding the maximum name of 15 characters"
 msgstr ""
 "ВНИМАНИЕ: Имя политики %s  превышает установленное ограничение в 15 символов."
 
@@ -527,3 +511,43 @@ msgstr "никогда"
 
 msgid "unreachable (reject)"
 msgstr "недоступен (отклонить)"
+
+#~ msgid "Online (tracking active)"
+#~ msgstr "Онлайн (отслеживание активно)"
+
+#~ msgid "MWAN Interface Live Status"
+#~ msgstr "Состояние интерфейса MWAN в настоящее время"
+
+#~ msgid "MWAN status - Interface Live Status"
+#~ msgstr "Состояние MWAN - Интерфейс в настоящее время"
+
+#~ msgid "Online (tracking off)"
+#~ msgstr "Онлайн  (отслеживание отключено)"
+
+#~ msgid ""
+#~ "This section allows you to modify the content of \"/etc/mwan3.user\".<br /"
+#~ ">The file is also preserved during sysupgrade.<br /><br />Notes:<br /"
+#~ ">This file is interpreted as a shell script.<br />The first line of the "
+#~ "script must be &#34;#!/bin/sh&#34; without quotes.<br />Lines beginning "
+#~ "with # are comments and are not executed.<br />Put your custom mwan3 "
+#~ "action here, they will<br />be executed with each netifd hotplug "
+#~ "interface event<br />on interfaces for which mwan3 is enabled.<br /><br /"
+#~ ">There are three main environment variables that are passed to this "
+#~ "script.<br /><br />$ACTION Either \"ifup\" or \"ifdown\"<br />$INTERFACE "
+#~ "Name of the interface which went up or down (e.g. \"wan\" or \"wwan"
+#~ "\")<br />$DEVICE Physical device name which interface went up or down (e."
+#~ "g. \"eth0\" or \"wwan0\")<br /><br />"
+#~ msgstr ""
+#~ "Страница позволяет изменять содержимое файла mwan3.user (/etc/mwan3.user)."
+#~ "<br />Файл также сохраняется во время перепрошивки sysupgrade-совместимым "
+#~ "образом.<br /><br />Примечание:<br />Этот файл интерпретируется как shell "
+#~ "скрипт.<br />Первая строка скрипта должна быть &#34;#!/bin/sh&#34; без "
+#~ "кавычек.<br />Строки начинающиеся с #, являются комментариями и не "
+#~ "исполняются.<br />Поместите свои пользовательские действия mwan3 здесь, "
+#~ "они будут<br />выполняться с каждым событием netifd hotplug "
+#~ "интерфейса<br />на интерфейсах, для которых включен mwan3.<br /><br />В "
+#~ "этот сценарий передаются три основные переменные среды.<br /><br />"
+#~ "$ACTION либо \"ifup\" или \"ifdown\"<br />$INTERFACE - имя интерфейса, "
+#~ "который включили или отключили (например, 'wan' или 'wwan') <br />$DEVICE "
+#~ "- имя физического устройства, чей интерфейс включили или отключили  "
+#~ "(например, 'eth0' или 'wwan0')<br /><br />."
index b726624..f6b3a1b 100644 (file)
@@ -88,6 +88,9 @@ msgstr ""
 msgid "Hotplug ifup"
 msgstr ""
 
+msgid "INFO: MWAN not running"
+msgstr ""
+
 msgid "IPset"
 msgstr ""
 
@@ -157,7 +160,7 @@ msgstr ""
 msgid "MWAN Interface Configuration - %s"
 msgstr ""
 
-msgid "MWAN Interface Live Status"
+msgid "MWAN Interfaces"
 msgstr ""
 
 msgid "MWAN Member Configuration - %s"
@@ -178,16 +181,13 @@ msgstr ""
 msgid "MWAN Status - Troubleshooting"
 msgstr ""
 
-msgid "MWAN status - Interface Live Status"
-msgstr ""
-
 msgid ""
-"MWAN supports up to 250 physical and/or logical interfaces<br />MWAN "
+"MWAN supports up to 252 physical and/or logical interfaces<br />MWAN "
 "requires that all interfaces have a unique metric configured in /etc/config/"
 "network<br />Names must match the interface name found in /etc/config/"
-"network (see advanced tab)<br />Names may contain characters A-Z, a-z, 0-9, "
-"_ and no spaces<br />Interfaces may not share the same name as configured "
-"members, policies or rules"
+"network<br />Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br /"
+">Interfaces may not share the same name as configured members, policies or "
+"rules"
 msgstr ""
 
 msgid ""
@@ -236,12 +236,6 @@ msgstr ""
 msgid "Online"
 msgstr ""
 
-msgid "Online (tracking active)"
-msgstr ""
-
-msgid "Online (tracking off)"
-msgstr ""
-
 msgid "Ping count"
 msgstr ""
 
@@ -272,11 +266,11 @@ msgstr ""
 msgid ""
 "Policies are profiles grouping one or more members controlling how MWAN "
 "distributes traffic<br />Member interfaces with lower metrics are used "
-"first. Interfaces with the same metric load-balance<br />Load-balanced "
-"member interfaces distribute more traffic out those with higher weights<br /"
-">Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be "
-"15 characters or less<br />Policies may not share the same name as "
-"configured interfaces, members or rules"
+"first<br />Member interfaces with the same metric will be load-balanced<br /"
+">Load-balanced member interfaces distribute more traffic out those with "
+"higher weights<br />Names may contain characters A-Z, a-z, 0-9, _ and no "
+"spaces<br />Names must be 15 characters or less<br />Policies may not share "
+"the same name as configured interfaces, members or rules"
 msgstr ""
 
 msgid "Policy"
@@ -330,7 +324,7 @@ msgstr ""
 msgid "Task"
 msgstr ""
 
-msgid "There are currently %d of 250 supported interfaces configured"
+msgid "There are currently %d of %d supported interfaces configured"
 msgstr ""
 
 msgid ""
@@ -351,9 +345,13 @@ msgid ""
 "will<br />be executed with each netifd hotplug interface event<br />on "
 "interfaces for which mwan3 is enabled.<br /><br />There are three main "
 "environment variables that are passed to this script.<br /><br />$ACTION "
-"Either \"ifup\" or \"ifdown\"<br />$INTERFACE Name of the interface which "
-"went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE Physical device name "
-"which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br /><br />"
+"<br />* \"ifup\" Is called by netifd and mwan3track <br />* \"ifdown\" Is "
+"called by netifd and mwan3track <br />* \"connected\" Is only called by "
+"mwan3track if tracking was successful <br />* \"disconnected\" Is only "
+"called by mwan3track if tracking has failed <br />$INTERFACE Name of the "
+"interface which went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE "
+"Physical device name which interface went up or down (e.g. \"eth0\" or "
+"\"wwan0\")<br /><br />"
 msgstr ""
 
 msgid "Tracking hostname or IP address"
@@ -381,7 +379,7 @@ msgstr ""
 msgid "View the content of /etc/protocols for protocol description"
 msgstr ""
 
-msgid "WARNING: %d interfaces are configured exceeding the maximum of 250!"
+msgid "WARNING: %d interfaces are configured exceeding the maximum of %d!"
 msgstr ""
 
 msgid "WARNING: Interface %s are not found in /etc/config/network"
@@ -398,7 +396,7 @@ msgstr ""
 msgid "WARNING: Interface %s has no default route in the main routing table"
 msgstr ""
 
-msgid "WARNING: Policie %s has exceeding the maximum name of 15 characters"
+msgid "WARNING: Policy %s has exceeding the maximum name of 15 characters"
 msgstr ""
 
 msgid ""
index c838bdb..ef59339 100644 (file)
@@ -99,6 +99,9 @@ msgstr "Hotplug ifdown"
 msgid "Hotplug ifup"
 msgstr "Hotplug ifup"
 
+msgid "INFO: MWAN not running"
+msgstr ""
+
 msgid "IPset"
 msgstr "IPset"
 
@@ -168,8 +171,8 @@ msgstr ""
 msgid "MWAN Interface Configuration - %s"
 msgstr "MWAN 接口配置 - %s"
 
-msgid "MWAN Interface Live Status"
-msgstr "MWAN 接口实时状态"
+msgid "MWAN Interfaces"
+msgstr ""
 
 msgid "MWAN Member Configuration - %s"
 msgstr "MWAN 成员配置 - %s"
@@ -189,22 +192,18 @@ msgstr ""
 msgid "MWAN Status - Troubleshooting"
 msgstr ""
 
-msgid "MWAN status - Interface Live Status"
-msgstr ""
-
 msgid ""
-"MWAN supports up to 250 physical and/or logical interfaces<br />MWAN "
+"MWAN supports up to 252 physical and/or logical interfaces<br />MWAN "
 "requires that all interfaces have a unique metric configured in /etc/config/"
 "network<br />Names must match the interface name found in /etc/config/"
-"network (see advanced tab)<br />Names may contain characters A-Z, a-z, 0-9, "
-"_ and no spaces<br />Interfaces may not share the same name as configured "
-"members, policies or rules"
+"network<br />Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br /"
+">Interfaces may not share the same name as configured members, policies or "
+"rules"
 msgstr ""
-"MWAN 支持最多 250 个物理或逻辑接口。<br />MWAN 要求所有接口必须在 /etc/"
+"MWAN 支持最多 252 个物理或逻辑接口。<br />MWAN 要求所有接口必须在 /etc/"
 "config/network 中设定唯一的网关跃点。<br />名称必须与 /etc/config/network 中"
-"的接口名称匹配。(可查看“高级”选项卡)<br />名称允许包括 A-Z、a-z、0-9、_ 但"
-"是不能有空格。<br />接口不应该与成员、策略、规则中的任意一个设置项使用相同的"
-"名称"
+"的接口名称匹配。<br />名称允许包括 A-Z、a-z、0-9、_ 但是不能有空格。<br />接"
+"口不应该与成员、策略、规则中的任意一个设置项使用相同的名称"
 
 msgid ""
 "May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or "
@@ -259,12 +258,6 @@ msgstr "离线"
 msgid "Online"
 msgstr "在线"
 
-msgid "Online (tracking active)"
-msgstr "在线(跟踪启用中)"
-
-msgid "Online (tracking off)"
-msgstr "在线(跟踪已关闭)"
-
 msgid "Ping count"
 msgstr "Ping 计数"
 
@@ -295,11 +288,11 @@ msgstr "策略"
 msgid ""
 "Policies are profiles grouping one or more members controlling how MWAN "
 "distributes traffic<br />Member interfaces with lower metrics are used "
-"first. Interfaces with the same metric load-balance<br />Load-balanced "
-"member interfaces distribute more traffic out those with higher weights<br /"
-">Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be "
-"15 characters or less<br />Policies may not share the same name as "
-"configured interfaces, members or rules"
+"first<br />Member interfaces with the same metric will be load-balanced<br /"
+">Load-balanced member interfaces distribute more traffic out those with "
+"higher weights<br />Names may contain characters A-Z, a-z, 0-9, _ and no "
+"spaces<br />Names must be 15 characters or less<br />Policies may not share "
+"the same name as configured interfaces, members or rules"
 msgstr ""
 "“策略”把成员进行分组,告诉 MWAN 如何分配“规则”中使用这一策略的流量<br />拥有"
 "较低跃点数的成员将会被优先使用。拥有相同跃点数的成员把流量进行负载均衡。<br /"
@@ -358,8 +351,8 @@ msgstr "支持 CIDR 记法(例如:\"192.168.100.0/24\")不含引号"
 msgid "Task"
 msgstr ""
 
-msgid "There are currently %d of 250 supported interfaces configured"
-msgstr "当前已配置 %d 个接口,最大支持 250 个"
+msgid "There are currently %d of %d supported interfaces configured"
+msgstr "当前已配置 %d 个接口,最大支持 %d 个"
 
 msgid ""
 "This displays the metric assigned to this interface in /etc/config/network"
@@ -379,18 +372,14 @@ msgid ""
 "will<br />be executed with each netifd hotplug interface event<br />on "
 "interfaces for which mwan3 is enabled.<br /><br />There are three main "
 "environment variables that are passed to this script.<br /><br />$ACTION "
-"Either \"ifup\" or \"ifdown\"<br />$INTERFACE Name of the interface which "
-"went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE Physical device name "
-"which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br /><br />"
-msgstr ""
-"这里允许您修改“/etc/mwan3.user”的内容。<br />该文件在 sysupgrade 期间也会保"
-"留。<br /><br />注意:<br />该文件会作为 shell 脚本解释。<br />脚本的第一行必"
-"须是&#34;#!/bin/sh&#34;,不带引号。<br />以#开头的行是注释,不会执行。<br />"
-"将您的自定义 mwan3 动作放在这里,他们将<br />在启用 mwan3 的接口上<br />在 "
-"netifd hotplug 接口事件时执行。<br /><br />有三个主要的环境变量传递给这个脚"
-"本。<br /><br />$ACTION “ifup”或“ifdown”<br />$INTERFACE 启动或停止的接口名"
-"(例如“wan”或“wwan”)<br />$DEVICE 启动或停止接口的物理设备名(例"
-"如“eth0”或“wwan0”)<br /><br />"
+"<br />* \"ifup\" Is called by netifd and mwan3track <br />* \"ifdown\" Is "
+"called by netifd and mwan3track <br />* \"connected\" Is only called by "
+"mwan3track if tracking was successful <br />* \"disconnected\" Is only "
+"called by mwan3track if tracking has failed <br />$INTERFACE Name of the "
+"interface which went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE "
+"Physical device name which interface went up or down (e.g. \"eth0\" or "
+"\"wwan0\")<br /><br />"
+msgstr ""
 
 msgid "Tracking hostname or IP address"
 msgstr "跟踪的主机或 IP 地址"
@@ -419,8 +408,8 @@ msgstr "使用该接口的 IP 地址作为路由器本身发起的流量的源 I
 msgid "View the content of /etc/protocols for protocol description"
 msgstr ""
 
-msgid "WARNING: %d interfaces are configured exceeding the maximum of 250!"
-msgstr "警告:已配置 %d 个接口,超过最大值 250!"
+msgid "WARNING: %d interfaces are configured exceeding the maximum of %d!"
+msgstr "警告:已配置 %d 个接口,超过最大值 %d!"
 
 msgid "WARNING: Interface %s are not found in /etc/config/network"
 msgstr ""
@@ -436,7 +425,7 @@ msgstr ""
 msgid "WARNING: Interface %s has no default route in the main routing table"
 msgstr ""
 
-msgid "WARNING: Policie %s has exceeding the maximum name of 15 characters"
+msgid "WARNING: Policy %s has exceeding the maximum name of 15 characters"
 msgstr ""
 
 msgid ""
@@ -478,6 +467,38 @@ msgstr "从不"
 msgid "unreachable (reject)"
 msgstr "不可达(拒绝)"
 
+#~ msgid "Online (tracking active)"
+#~ msgstr "在线(跟踪启用中)"
+
+#~ msgid "MWAN Interface Live Status"
+#~ msgstr "MWAN 接口实时状态"
+
+#~ msgid "Online (tracking off)"
+#~ msgstr "在线(跟踪已关闭)"
+
+#~ msgid ""
+#~ "This section allows you to modify the content of \"/etc/mwan3.user\".<br /"
+#~ ">The file is also preserved during sysupgrade.<br /><br />Notes:<br /"
+#~ ">This file is interpreted as a shell script.<br />The first line of the "
+#~ "script must be &#34;#!/bin/sh&#34; without quotes.<br />Lines beginning "
+#~ "with # are comments and are not executed.<br />Put your custom mwan3 "
+#~ "action here, they will<br />be executed with each netifd hotplug "
+#~ "interface event<br />on interfaces for which mwan3 is enabled.<br /><br /"
+#~ ">There are three main environment variables that are passed to this "
+#~ "script.<br /><br />$ACTION Either \"ifup\" or \"ifdown\"<br />$INTERFACE "
+#~ "Name of the interface which went up or down (e.g. \"wan\" or \"wwan"
+#~ "\")<br />$DEVICE Physical device name which interface went up or down (e."
+#~ "g. \"eth0\" or \"wwan0\")<br /><br />"
+#~ msgstr ""
+#~ "这里允许您修改“/etc/mwan3.user”的内容。<br />该文件在 sysupgrade 期间也会"
+#~ "保留。<br /><br />注意:<br />该文件会作为 shell 脚本解释。<br />脚本的第"
+#~ "一行必须是&#34;#!/bin/sh&#34;,不带引号。<br />以#开头的行是注释,不会执"
+#~ "行。<br />将您的自定义 mwan3 动作放在这里,他们将<br />在启用 mwan3 的接口"
+#~ "上<br />在 netifd hotplug 接口事件时执行。<br /><br />有三个主要的环境变量"
+#~ "传递给这个脚本。<br /><br />$ACTION “ifup”或“ifdown”<br />$INTERFACE 启动"
+#~ "或停止的接口名(例如“wan”或“wwan”)<br />$DEVICE 启动或停止接口的物理设备"
+#~ "名(例如“eth0”或“wwan0”)<br /><br />"
+
 #~ msgid "Currently Configured Interfaces"
 #~ msgstr "当前配置的接口"
 
index d28bd82..6af9fae 100644 (file)
@@ -99,6 +99,9 @@ msgstr "Hotplug ifdown"
 msgid "Hotplug ifup"
 msgstr "Hotplug ifup"
 
+msgid "INFO: MWAN not running"
+msgstr ""
+
 msgid "IPset"
 msgstr "IPset"
 
@@ -168,8 +171,8 @@ msgstr ""
 msgid "MWAN Interface Configuration - %s"
 msgstr "MWAN 介面配置 - %s"
 
-msgid "MWAN Interface Live Status"
-msgstr "MWAN 介面實時狀態"
+msgid "MWAN Interfaces"
+msgstr ""
 
 msgid "MWAN Member Configuration - %s"
 msgstr "MWAN 成員配置 - %s"
@@ -189,22 +192,18 @@ msgstr ""
 msgid "MWAN Status - Troubleshooting"
 msgstr ""
 
-msgid "MWAN status - Interface Live Status"
-msgstr ""
-
 msgid ""
-"MWAN supports up to 250 physical and/or logical interfaces<br />MWAN "
+"MWAN supports up to 252 physical and/or logical interfaces<br />MWAN "
 "requires that all interfaces have a unique metric configured in /etc/config/"
 "network<br />Names must match the interface name found in /etc/config/"
-"network (see advanced tab)<br />Names may contain characters A-Z, a-z, 0-9, "
-"_ and no spaces<br />Interfaces may not share the same name as configured "
-"members, policies or rules"
+"network<br />Names may contain characters A-Z, a-z, 0-9, _ and no spaces<br /"
+">Interfaces may not share the same name as configured members, policies or "
+"rules"
 msgstr ""
-"MWAN 支援最多 250 個物理或邏輯介面。<br />MWAN 要求所有介面必須在 /etc/"
+"MWAN 支援最多 252 個物理或邏輯介面。<br />MWAN 要求所有介面必須在 /etc/"
 "config/network 中設定唯一的閘道器躍點。<br />名稱必須與 /etc/config/network "
-"中的介面名稱匹配。(可檢視“高階”選項卡)<br />名稱允許包括 A-Z、a-z、0-9、_ "
-"但是不能有空格。<br />介面不應該與成員、策略、規則中的任意一個設定項使用相同"
-"的名稱"
+"中的介面名稱匹配。<br />名稱允許包括 A-Z、a-z、0-9、_ 但是不能有空格。<br />"
+"介面不應該與成員、策略、規則中的任意一個設定項使用相同的名稱"
 
 msgid ""
 "May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or "
@@ -259,12 +258,6 @@ msgstr "離線"
 msgid "Online"
 msgstr "線上"
 
-msgid "Online (tracking active)"
-msgstr "線上(跟蹤啟用中)"
-
-msgid "Online (tracking off)"
-msgstr "線上(跟蹤已關閉)"
-
 msgid "Ping count"
 msgstr "Ping 計數"
 
@@ -295,11 +288,11 @@ msgstr "策略"
 msgid ""
 "Policies are profiles grouping one or more members controlling how MWAN "
 "distributes traffic<br />Member interfaces with lower metrics are used "
-"first. Interfaces with the same metric load-balance<br />Load-balanced "
-"member interfaces distribute more traffic out those with higher weights<br /"
-">Names may contain characters A-Z, a-z, 0-9, _ and no spaces. Names must be "
-"15 characters or less<br />Policies may not share the same name as "
-"configured interfaces, members or rules"
+"first<br />Member interfaces with the same metric will be load-balanced<br /"
+">Load-balanced member interfaces distribute more traffic out those with "
+"higher weights<br />Names may contain characters A-Z, a-z, 0-9, _ and no "
+"spaces<br />Names must be 15 characters or less<br />Policies may not share "
+"the same name as configured interfaces, members or rules"
 msgstr ""
 "“策略”把成員進行分組,告訴 MWAN 如何分配“規則”中使用這一策略的流量<br />擁有"
 "較低躍點數的成員將會被優先使用。擁有相同躍點數的成員把流量進行負載均衡。<br /"
@@ -358,8 +351,8 @@ msgstr "支援 CIDR 記法(例如:\"192.168.100.0/24\")不含引號"
 msgid "Task"
 msgstr ""
 
-msgid "There are currently %d of 250 supported interfaces configured"
-msgstr "當前已配置 %d 個介面,最大支援 250 個"
+msgid "There are currently %d of %d supported interfaces configured"
+msgstr "當前已配置 %d 個介面,最大支援 %d 個"
 
 msgid ""
 "This displays the metric assigned to this interface in /etc/config/network"
@@ -379,18 +372,14 @@ msgid ""
 "will<br />be executed with each netifd hotplug interface event<br />on "
 "interfaces for which mwan3 is enabled.<br /><br />There are three main "
 "environment variables that are passed to this script.<br /><br />$ACTION "
-"Either \"ifup\" or \"ifdown\"<br />$INTERFACE Name of the interface which "
-"went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE Physical device name "
-"which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br /><br />"
-msgstr ""
-"這裡允許您修改“/etc/mwan3.user”的內容。<br />該檔案在 sysupgrade 期間也會保"
-"留。<br /><br />注意:<br />該檔案會作為 shell 指令碼解釋。<br />指令碼的第一"
-"行必須是&#34;#!/bin/sh&#34;,不帶引號。<br />以#開頭的行是註釋,不會執行。"
-"<br />將您的自定義 mwan3 動作放在這裡,他們將<br />在啟用 mwan3 的介面上<br /"
-">在 netifd hotplug 介面事件時執行。<br /><br />有三個主要的環境變數傳遞給這個"
-"腳本。<br /><br />$ACTION “ifup”或“ifdown”<br />$INTERFACE 啟動或停止的介面名"
-"(例如“wan”或“wwan”)<br />$DEVICE 啟動或停止介面的物理裝置名(例"
-"如“eth0”或“wwan0”)<br /><br />"
+"<br />* \"ifup\" Is called by netifd and mwan3track <br />* \"ifdown\" Is "
+"called by netifd and mwan3track <br />* \"connected\" Is only called by "
+"mwan3track if tracking was successful <br />* \"disconnected\" Is only "
+"called by mwan3track if tracking has failed <br />$INTERFACE Name of the "
+"interface which went up or down (e.g. \"wan\" or \"wwan\")<br />$DEVICE "
+"Physical device name which interface went up or down (e.g. \"eth0\" or "
+"\"wwan0\")<br /><br />"
+msgstr ""
 
 msgid "Tracking hostname or IP address"
 msgstr "跟蹤的主機或 IP 位址"
@@ -419,8 +408,8 @@ msgstr "使用該介面的 IP 位址作為路由器本身發起的流量的源 I
 msgid "View the content of /etc/protocols for protocol description"
 msgstr ""
 
-msgid "WARNING: %d interfaces are configured exceeding the maximum of 250!"
-msgstr "警告:已配置 %d 個介面,超過最大值 250!"
+msgid "WARNING: %d interfaces are configured exceeding the maximum of %d!"
+msgstr "警告:已配置 %d 個介面,超過最大值 %d!"
 
 msgid "WARNING: Interface %s are not found in /etc/config/network"
 msgstr ""
@@ -436,7 +425,7 @@ msgstr ""
 msgid "WARNING: Interface %s has no default route in the main routing table"
 msgstr ""
 
-msgid "WARNING: Policie %s has exceeding the maximum name of 15 characters"
+msgid "WARNING: Policy %s has exceeding the maximum name of 15 characters"
 msgstr ""
 
 msgid ""
@@ -478,6 +467,38 @@ msgstr "從不"
 msgid "unreachable (reject)"
 msgstr "不可達(拒絕)"
 
+#~ msgid "Online (tracking active)"
+#~ msgstr "線上(跟蹤啟用中)"
+
+#~ msgid "MWAN Interface Live Status"
+#~ msgstr "MWAN 介面實時狀態"
+
+#~ msgid "Online (tracking off)"
+#~ msgstr "線上(跟蹤已關閉)"
+
+#~ msgid ""
+#~ "This section allows you to modify the content of \"/etc/mwan3.user\".<br /"
+#~ ">The file is also preserved during sysupgrade.<br /><br />Notes:<br /"
+#~ ">This file is interpreted as a shell script.<br />The first line of the "
+#~ "script must be &#34;#!/bin/sh&#34; without quotes.<br />Lines beginning "
+#~ "with # are comments and are not executed.<br />Put your custom mwan3 "
+#~ "action here, they will<br />be executed with each netifd hotplug "
+#~ "interface event<br />on interfaces for which mwan3 is enabled.<br /><br /"
+#~ ">There are three main environment variables that are passed to this "
+#~ "script.<br /><br />$ACTION Either \"ifup\" or \"ifdown\"<br />$INTERFACE "
+#~ "Name of the interface which went up or down (e.g. \"wan\" or \"wwan"
+#~ "\")<br />$DEVICE Physical device name which interface went up or down (e."
+#~ "g. \"eth0\" or \"wwan0\")<br /><br />"
+#~ msgstr ""
+#~ "這裡允許您修改“/etc/mwan3.user”的內容。<br />該檔案在 sysupgrade 期間也會"
+#~ "保留。<br /><br />注意:<br />該檔案會作為 shell 指令碼解釋。<br />指令碼"
+#~ "的第一行必須是&#34;#!/bin/sh&#34;,不帶引號。<br />以#開頭的行是註釋,不會"
+#~ "執行。<br />將您的自定義 mwan3 動作放在這裡,他們將<br />在啟用 mwan3 的介"
+#~ "面上<br />在 netifd hotplug 介面事件時執行。<br /><br />有三個主要的環境變"
+#~ "數傳遞給這個腳本。<br /><br />$ACTION “ifup”或“ifdown”<br />$INTERFACE 啟"
+#~ "動或停止的介面名(例如“wan”或“wwan”)<br />$DEVICE 啟動或停止介面的物理裝"
+#~ "置名(例如“eth0”或“wwan0”)<br /><br />"
+
 #~ msgid "Currently Configured Interfaces"
 #~ msgstr "當前配置的介面"
 
index 229f3d6..c5fb2b2 100644 (file)
@@ -84,11 +84,11 @@ function action_json()
        local jsonreq4
        local jsonreq6
 
-       local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
-       local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
+       local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
+       local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
 
-       jsonreq4 = utl.exec("(echo /status | nc 127.0.0.1 " .. v4_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null" )
-       jsonreq6 = utl.exec("(echo /status | nc ::1 " .. v6_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
+       jsonreq4 = utl.exec("(echo /status | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v4_port)
+       jsonreq6 = utl.exec("(echo /status | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" % v6_port)
        http.prepare_content("application/json")
        if not jsonreq4 or jsonreq4 == "" then
                jsonreq4 = "{}"
@@ -150,7 +150,7 @@ function action_neigh(json)
        for _, dev in ipairs(devices) do
                for _, net in ipairs(dev:get_wifinets()) do
                        local radio = net:get_device()
-                       assoclist[#assoclist+1] = {} 
+                       assoclist[#assoclist+1] = {}
                        assoclist[#assoclist]['ifname'] = net:ifname()
                        assoclist[#assoclist]['network'] = net:network()[1]
                        assoclist[#assoclist]['device'] = radio and radio:name() or nil
@@ -165,7 +165,7 @@ function action_neigh(json)
                local mac = ""
                local ip
                local neihgt = {}
-               
+
                if resolve == "1" then
                        hostname = nixio.getnameinfo(v.remoteIP, nil, 100)
                        if hostname then
@@ -350,11 +350,11 @@ function fetch_jsoninfo(otable)
        local IpVersion = uci:get_first("olsrd", "olsrd","IpVersion")
        local jsonreq4 = ""
        local jsonreq6 = ""
-       local v4_port = uci:get("olsrd", "olsrd_jsoninfo", "port") or 9090
-       local v6_port = uci:get("olsrd6", "olsrd_jsoninfo", "port") or 9090
+       local v4_port = tonumber(uci:get("olsrd", "olsrd_jsoninfo", "port") or "") or 9090
+       local v6_port = tonumber(uci:get("olsrd6", "olsrd_jsoninfo", "port") or "") or 9090
 
-       jsonreq4 = utl.exec("(echo /" .. otable .. " | nc 127.0.0.1 " .. v4_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
-       jsonreq6 = utl.exec("(echo /" .. otable .. " | nc ::1 " .. v6_port .. " | sed -n '/^[}{ ]/p') 2>/dev/null")
+       jsonreq4 = utl.exec("(echo /%s | nc 127.0.0.1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v4_port })
+       jsonreq6 = utl.exec("(echo /%s | nc ::1 %d | sed -n '/^[}{ ]/p') 2>/dev/null" %{ otable, v6_port })
        local jsondata4 = {}
        local jsondata6 = {}
        local data4 = {}
index 719145b..d2b5d32 100644 (file)
@@ -26,9 +26,9 @@ uci:foreach( "openvpn_recipes", "openvpn_recipe",
 )
 
 function s.getPID(section) -- Universal function which returns valid pid # or nil
-       local pid = sys.exec("%s | grep -w %s | grep openvpn | grep -v grep | awk '{print $1}'" % { psstring,section} )
-       if pid and #pid > 0 and tonumber(pid) ~= nil then
-               return tonumber(pid)
+       local pid = sys.exec("%s | grep -w '[o]penvpn(%s)'" % { psstring, section })
+       if pid and #pid > 0 then
+               return tonumber(pid:match("^%s*(%d+)"))
        else
                return nil
        end
index b4fdbd5..af7a3a3 100644 (file)
@@ -9,7 +9,7 @@ function index()
        entry({"admin", "services", "splash", "splashtext" }, form("splash/splashtext"), _("Splashtext"), 10)
 
        local e
-       
+
        e = node("splash")
        e.target = call("action_dispatch")
 
@@ -82,7 +82,7 @@ function action_activate()
                        end
                end)
 
-               if blacklisted then     
+               if blacklisted then
                        luci.http.redirect(luci.dispatcher.build_url("splash" ,"blocked"))
                else
                        local id = tostring(mac):gsub(':', ''):lower()
@@ -106,7 +106,7 @@ function action_status_admin()
        local uci = luci.model.uci.cursor_state()
        local macs = luci.http.formvaluetable("save")
 
-       local changes = { 
+       local changes = {
                whitelist = { },
                blacklist = { },
                lease     = { },
@@ -129,22 +129,22 @@ function action_status_admin()
 
        if #changes.whitelist > 0 then
                os.execute("luci-splash whitelist %s >/dev/null"
-                       % table.concat(changes.whitelist))
+                       % util.shellquote(table.concat(changes.whitelist)))
        end
 
        if #changes.blacklist > 0 then
                os.execute("luci-splash blacklist %s >/dev/null"
-                       % table.concat(changes.blacklist))
+                       % util.shellquote(table.concat(changes.blacklist)))
        end
 
        if #changes.lease > 0 then
                os.execute("luci-splash lease %s >/dev/null"
-                       % table.concat(changes.lease))
+                       % util.shellquote(table.concat(changes.lease)))
        end
 
        if #changes.remove > 0 then
                os.execute("luci-splash remove %s >/dev/null"
-                       % table.concat(changes.remove))
+                       % util.shellquote(table.concat(changes.remove)))
        end
 
        luci.template.render("admin_status/splash", { is_admin = true })
index 2870dbe..9ec9f3a 100755 (executable)
@@ -36,6 +36,10 @@ function call(cmd)
        os.execute(cmd)
 end
 
+function esc(str)
+       return utl.shellquote(str)
+end
+
 
 function lock()
        call("lock /var/run/luci_splash.lock")
@@ -84,14 +88,14 @@ end
 
 function get_physdev(interface)
        local dev
-       dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME '" ..  interface .. "'; echo $IFNAME"))
+       dev = utl.trim(sys.exec(". /lib/functions/network.sh; network_get_device IFNAME %s; echo $IFNAME" % esc(interface)))
        return dev
 end
 
 
 
 function get_filter_handle(parent, direction, device, mac)
-       local input = utl.split(sys.exec('/usr/sbin/tc filter show dev ' .. device .. ' parent ' .. parent) or {})
+       local input = utl.split(sys.exec('/usr/sbin/tc filter show dev %s parent %s' %{ esc(device), esc(parent) }) or {})
        local tbl = {}
        local handle
        for k, v in pairs(input) do
@@ -264,7 +268,7 @@ function main(argv)
                                elseif whitelist_macs[mac] then
                                        print("Removing %s from whitelist" % mac)
                                        remove_whitelist(mac)
-                                       whitelist_macs[mac] = nil                                       
+                                       whitelist_macs[mac] = nil
                                elseif blacklist_macs[mac] then
                                        print("Removing %s from blacklist" % mac)
                                        remove_blacklist(mac)
@@ -295,7 +299,7 @@ function main(argv)
                print("\n  luci-splash remove <MAC-or-IP>\n    Remove given address from the lease-, black- or whitelist")
                print("")
 
-               os.exit(1)      
+               os.exit(1)
        end
 end
 
@@ -338,8 +342,8 @@ function ipt_delete_all(args, comp, off)
                        off[r.table] = off[r.table] or { }
                        off[r.table][r.chain] = off[r.table][r.chain] or 0
 
-                       exec("iptables -t %q -D %q %d 2>/dev/null"
-                               %{ r.table, r.chain, r.index - off[r.table][r.chain] })
+                       exec("iptables -t %s -D %s %d 2>/dev/null"
+                               %{ esc(r.table), esc(r.chain), r.index - off[r.table][r.chain] })
 
                        off[r.table][r.chain] = off[r.table][r.chain] + 1
                end
@@ -353,8 +357,8 @@ function ipt6_delete_all(args, comp, off)
                        off[r.table] = off[r.table] or { }
                        off[r.table][r.chain] = off[r.table][r.chain] or 0
 
-                       exec("ip6tables -t %q -D %q %d 2>/dev/null"
-                               %{ r.table, r.chain, r.index - off[r.table][r.chain] })
+                       exec("ip6tables -t %s -D %s %d 2>/dev/null"
+                               %{ esc(r.table), esc(r.chain), r.index - off[r.table][r.chain] })
 
                        off[r.table][r.chain] = off[r.table][r.chain] + 1
                end
@@ -460,13 +464,13 @@ function remove_whitelist_tc(mac)
                        end
                        local handle = get_filter_handle('ffff:', 'src', device, mac)
                        if handle then
-                               exec('tc filter del dev "%s" parent ffff: protocol ip prio 1 handle %s u32' % { device, handle })
+                               exec('tc filter del dev %s parent ffff: protocol ip prio 1 handle %s u32' % { esc(device), esc(handle) })
                        else
                                print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
                        end
                        local handle = get_filter_handle('1:', 'dest', device, mac)
                        if handle then
-                               exec('tc filter del dev "%s" parent 1:0 protocol ip prio 1 handle %s u32' % { device, handle })
+                               exec('tc filter del dev %s parent 1:0 protocol ip prio 1 handle %s u32' % { esc(device), esc(handle) })
                        else
                                print('Warning! Could not get a handle for %s parent 1:0 on interface %s' % { mac, device })
                        end
@@ -492,37 +496,37 @@ function add_lease_rule(mac, ipaddr, device)
                id = get_id(ipaddr)
        end
 
-       exec("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j RETURN" % mac)
+       exec("iptables -t mangle -I luci_splash_mark_out -m mac --mac-source %s -j RETURN" % esc(mac))
 
        -- Mark incoming packets to a splashed host
        -- for ipv4 - by iptables and destination
        if id and device then
-               exec("iptables -t mangle -I luci_splash_mark_in -d %q -j MARK --set-mark 0x1%s -m comment --comment %s" % {ipaddr, id, mac:upper()})
+               exec("iptables -t mangle -I luci_splash_mark_in -d %s -j MARK --set-mark 0x1%s -m comment --comment %s" % { esc(ipaddr), esc(id), esc(mac:upper())})
        end
 
        --for ipv6: need to use the mac here
 
        if has_ipv6 then
-               exec("ip6tables -t mangle -I luci_splash_mark_out -m mac --mac-source %q -j MARK --set-mark 79" % mac)
+               exec("ip6tables -t mangle -I luci_splash_mark_out -m mac --mac-source %s -j MARK --set-mark 79" % esc(mac))
                if id and device and tonumber(limit_down) then
-                       exec("tc filter add dev %s parent 1:0 protocol ipv6 prio 1 u32 match ether dst %s classid 1:%s" % {device, mac:lower(), id})
+                       exec("tc filter add dev %s parent 1:0 protocol ipv6 prio 1 u32 match ether dst %s classid 1:%s" % { esc(device), esc(mac:lower()), esc(id) })
                end
        end
 
 
        if device and tonumber(limit_up) > 0 then
-               exec('tc filter add dev "%s" parent ffff: protocol all prio 2 u32 match ether src %s police rate %skbit mtu 6k burst 6k drop' % {device, mac, limit_up})
+               exec('tc filter add dev %s parent ffff: protocol all prio 2 u32 match ether src %s police rate %skbit mtu 6k burst 6k drop' % { esc(device), esc(mac), esc(limit_up) })
        end
 
        if id and device and tonumber(limit_down) > 0 then
-               exec("tc class add dev %s parent 1: classid 1:0x%s htb rate %skbit" % { device, id, limit_down })
-               exec("tc qdisc add dev %s parent 1:%s sfq perturb 10" % { device, id })
+               exec("tc class add dev %s parent 1: classid 1:0x%s htb rate %skbit" % { esc(device), esc(id), esc(limit_down) })
+               exec("tc qdisc add dev %s parent 1:%s sfq perturb 10" % { esc(device), esc(id) })
        end
 
-       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
-       exec("iptables -t nat    -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
+       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %s -j RETURN" % esc(mac))
+       exec("iptables -t nat    -I luci_splash_leases -m mac --mac-source %s -j RETURN" % esc(mac))
        if has_ipv6 then
-               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
+               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %s -j RETURN" % esc(mac))
        end
 end
 
@@ -548,32 +552,32 @@ function remove_lease_rule(mac, ipaddr, device, limit_up, limit_down)
        if device and tonumber(limit_up) > 0 then
                local handle = get_filter_handle('ffff:', 'src', device, mac)
                if handle then
-                       exec('tc filter del dev "%s" parent ffff: protocol all prio 2 handle %s u32 police rate %skbit mtu 6k burst 6k drop' % {device, handle, limit_up})
+                       exec('tc filter del dev %s parent ffff: protocol all prio 2 handle %s u32 police rate %skbit mtu 6k burst 6k drop' % { esc(device), esc(handle), esc(limit_up) })
                else
                        print('Warning! Could not get a handle for %s parent :ffff on interface %s' % { mac, device })
                end
        end
        -- remove clients class
        if device and id then
-               exec('tc class del dev "%s" classid 1:%s' % {device, id})
-               exec('tc filter del dev "%s" parent 1:0 prio 1' % device) -- ipv6 rule
-               --exec('tc qdisc del dev "%s" parent 1:%s sfq perturb 10' % { device, id })
+               exec('tc class del dev %s classid 1:%s' % { esc(device), esc(id) })
+               exec('tc filter del dev %s parent 1:0 prio 1' % esc(device)) -- ipv6 rule
+               --exec('tc qdisc del dev %s parent 1:%s sfq perturb 10' % { esc(device), esc(id) })
        end
 end
 
 
 -- Add whitelist rules
 function add_whitelist_rule(mac)
-       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
-       exec("iptables -t nat    -I luci_splash_leases -m mac --mac-source %q -j RETURN" % mac)
+       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %s -j RETURN" % esc(mac))
+       exec("iptables -t nat    -I luci_splash_leases -m mac --mac-source %s -j RETURN" % esc(mac))
        if has_ipv6 then
-               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j RETURN" % mac)
+               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %s -j RETURN" % esc(mac))
        end
         uci:foreach("luci_splash", "iface", function(s)
                local device = get_physdev(s['.name'])
                if device and device ~= "" then
-                       exec('tc filter add dev "%s" parent ffff: protocol ip prio 1 u32 match ether src %s police pass' % { device, mac })
-                       exec('tc filter add dev "%s" parent 1:0 protocol ip prio 1 u32 match ether dst %s classid 1:1' % { device, mac })
+                       exec('tc filter add dev %s parent ffff: protocol ip prio 1 u32 match ether src %s police pass' % { esc(device), esc(mac) })
+                       exec('tc filter add dev %s parent 1:0 protocol ip prio 1 u32 match ether dst %s classid 1:1' % { esc(device), esc(mac) })
                end
         end)
 end
@@ -581,9 +585,9 @@ end
 
 -- Add blacklist rules
 function add_blacklist_rule(mac)
-       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
+       exec("iptables -t filter -I luci_splash_filter -m mac --mac-source %s -j DROP" % esc(mac))
        if has_ipv6 then
-               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %q -j DROP" % mac)
+               exec("ip6tables -t filter -I luci_splash_filter -m mac --mac-source %s -j DROP" % esc(mac))
        end
 end
 
@@ -596,15 +600,15 @@ function sync()
 
        -- Current leases in state files
        local leases = uci:get_all("luci_splash_leases")
-       
+
        -- Convert leasetime to seconds
        local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime")) * 3600
-       
+
        -- Clean state file
        uci:load("luci_splash_leases")
        uci:revert("luci_splash_leases")
 
-        
+
        local blackwhitelist = uci:get_all("luci_splash")
        local whitelist_total = 0
        local whitelist_online = 0
@@ -628,7 +632,7 @@ function sync()
                                 end
 
                                -- Rewrite state
-                               uci:section("luci_splash_leases", "lease", convert_mac_to_secname(v.mac), {             
+                               uci:section("luci_splash_leases", "lease", convert_mac_to_secname(v.mac), {
                                        mac    = v.mac,
                                        ipaddr = v.ipaddr,
                                        device = v.device,
@@ -639,7 +643,7 @@ function sync()
                        end
                end
        end
-       
+
        -- Whitelist, Blacklist
        for _, s in utl.spairs(blackwhitelist,
                function(a,b) return blackwhitelist[a][".type"] > blackwhitelist[b][".type"] end
@@ -666,7 +670,7 @@ function sync()
 
        -- ToDo:
         -- include a new field "leases_online" in stats to differ between active clients and leases:
-        -- update_stats(leasecount, leases_online, whitelist_online, whitelist_total, blacklist_online, blacklist_total) later: 
+        -- update_stats(leasecount, leases_online, whitelist_online, whitelist_total, blacklist_online, blacklist_total) later:
         update_stats(leases_online, whitelist_online, whitelist_total, blacklist_online, blacklist_total)
 
        uci:save("luci_splash_leases")
index e29a2e1..47e1696 100644 (file)
@@ -87,7 +87,7 @@ function Graph._rrdtool( self, def, rrd )
        fs.mkdirr( dir )
 
        -- construct commandline
-       local cmdline = "rrdtool graph"
+       local cmdline = { "rrdtool", "graph" }
 
        -- copy default arguments to def stack
        for i, opt in ipairs(self.args) do
@@ -102,15 +102,11 @@ function Graph._rrdtool( self, def, rrd )
                        opt = opt:gsub( "{file}", rrd )
                end
 
-               if opt:match("[^%w]") then
-                       cmdline = cmdline .. " '" .. opt .. "'"
-               else
-                       cmdline = cmdline .. " " .. opt
-               end
+               cmdline[#cmdline+1] = luci.util.shellquote(opt)
        end
 
        -- execute rrdtool
-       local rrdtool = io.popen( cmdline )
+       local rrdtool = io.popen(table.concat(cmdline, " "))
        rrdtool:close()
 end
 
index d43a887..2ba9ddd 100644 (file)
@@ -13,7 +13,11 @@ if luci.http.formvalue("frame") == "1" then
                end)
 
        local data = false
-       local wget = io.popen("wget -qO- http://%s:%s" % { addr, port })
+       local wget = io.popen("wget -qO- http://%s:%s" %{
+               luci.util.shellquote(addr),
+               luci.util.shellquote(port)
+       })
+
        if wget then
                while true do
                        local l = wget:read("*l")
@@ -30,7 +34,10 @@ if luci.http.formvalue("frame") == "1" then
 
        if not data then
                luci.http.write(translate("Failed to retrieve statistics from url:"))
-               luci.http.write(" http://%s:%s" % { addr, port })
+               luci.http.write(" http://%s:%s" %{
+                       luci.util.pcdata(addr),
+                       luci.util.pcdata(port)
+               })
        end
 
        return
@@ -43,7 +50,7 @@ end
 <div class="cbi-map">
        <h2 name="content"><%:Tinyproxy Status%></h2>
        <div class="cbi-section">
-               <iframe src="<%=REQUESTURL%>?frame=1" style="width:100%; height:350px; border:none"></iframe>
+               <iframe src="<%=REQUEST_URI%>?frame=1" style="width:100%; height:350px; border:none"></iframe>
        </div>
 </div>
 
index 2bd25bc..58d9bf3 100644 (file)
@@ -5,7 +5,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=LuCI support for Travelmate
-LUCI_DEPENDS:=+travelmate +luci-lib-jsonc +qrencode
+LUCI_DEPENDS:=+travelmate +luci-lib-jsonc
 LUCI_PKGARCH:=all
 
 include ../../luci.mk
index 14b8d77..493a387 100644 (file)
@@ -14,27 +14,27 @@ function index()
        entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false
        entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
        entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true
-       entry({"admin", "services", "travelmate", "apqr"}, template("travelmate/ap_qr"), _("AP QR-Codes"), 30).leaf = true
-       entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 40).leaf = true
+       entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 30).leaf = true
        entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100)
-       entry({"admin", "services", "travelmate", "advanced", "configuration"}, cbi("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true
-       entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, cbi("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true
-       entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, cbi("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true
-       entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, cbi("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true
+       entry({"admin", "services", "travelmate", "advanced", "configuration"}, form("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true
+       entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, form("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true
+       entry({"admin", "services", "travelmate", "advanced", "cfg_network"}, form("travelmate/cfg_network_tab"), _("Edit Network Configuration"), 130).leaf = true
+       entry({"admin", "services", "travelmate", "advanced", "cfg_firewall"}, form("travelmate/cfg_firewall_tab"), _("Edit Firewall Configuration"), 140).leaf = true
 
+       entry({"admin", "services", "travelmate", "apqr"}, template("travelmate/ap_qr")).leaf = true
        entry({"admin", "services", "travelmate", "wifiscan"}, template("travelmate/wifi_scan")).leaf = true
-       entry({"admin", "services", "travelmate", "wifiadd"}, cbi("travelmate/wifi_add", {hideresetbtn=true, hidesavebtn=true})).leaf = true
-       entry({"admin", "services", "travelmate", "wifiedit"}, cbi("travelmate/wifi_edit", {hideresetbtn=true, hidesavebtn=true})).leaf = true
-       entry({"admin", "services", "travelmate", "wifidelete"}, cbi("travelmate/wifi_delete", {hideresetbtn=true, hidesavebtn=true})).leaf = true
-       entry({"admin", "services", "travelmate", "wifiorder"}, cbi("travelmate/wifi_order", {hideresetbtn=true, hidesavebtn=true})).leaf = true
+       entry({"admin", "services", "travelmate", "wifiadd"}, form("travelmate/wifi_add", {hideresetbtn=true, hidesavebtn=true})).leaf = true
+       entry({"admin", "services", "travelmate", "wifiedit"}, form("travelmate/wifi_edit", {hideresetbtn=true, hidesavebtn=true})).leaf = true
+       entry({"admin", "services", "travelmate", "wifidelete"}, form("travelmate/wifi_delete", {hideresetbtn=true, hidesavebtn=true})).leaf = true
+       entry({"admin", "services", "travelmate", "wifiorder"}, form("travelmate/wifi_order", {hideresetbtn=true, hidesavebtn=true})).leaf = true
 end
 
 function logread()
-       local logfile
+       local logfile = ""
 
        if nixio.fs.access("/var/log/messages") then
                logfile = util.trim(util.exec("grep -F 'travelmate-' /var/log/messages"))
-       else
+       elseif nixio.fs.access("/sbin/logread") then
                logfile = util.trim(util.exec("logread -e 'travelmate-'"))
        end
        templ.render("travelmate/logread", {title = i18n.translate("Travelmate Logfile"), content = logfile})
index 860ce22..7b6b965 100644 (file)
@@ -73,45 +73,34 @@ o1 = s:option(Flag, "trm_enabled", translate("Enable travelmate"))
 o1.default = o1.disabled
 o1.rmempty = false
 
-o2 = s:option(Flag, "trm_automatic", translate("Enable 'automatic' mode"),
-       translate("Keep travelmate in an active state. Check every n seconds the connection status, i.e. the uplink availability."))
+o2 = s:option(Flag, "trm_captive", translate("Captive Portal Detection"),
+       translate("Check the internet availability, log captive portal redirections and keep the uplink connection 'alive'."))
 o2.default = o2.enabled
 o2.rmempty = false
 
-o3 = s:option(Flag, "trm_captive", translate("Captive Portal Detection"),
-       translate("Check the internet availability, log captive portal redirections and keep the uplink connection 'alive'."))
-o3.default = o3.enabled
-o3.rmempty = false
-
-o4 = s:option(ListValue, "trm_iface", translate("Uplink / Trigger interface"),
+o3 = s:option(ListValue, "trm_iface", translate("Uplink / Trigger interface"),
        translate("Name of the used uplink interface."))
 if dump then
        local i, v
        for i, v in ipairs(dump.interface) do
                if v.interface ~= "loopback" and v.interface ~= "lan" then
-                       o4:value(v.interface)
+                       o3:value(v.interface)
                end
        end
 end
-o4.default = trmiface
-o4.rmempty = false
+o3.default = trmiface
+o3.rmempty = false
 
-o5 = s:option(Value, "trm_triggerdelay", translate("Trigger Delay"),
-       translate("Additional trigger delay in seconds before travelmate processing begins."))
-o5.datatype = "range(1,60)"
-o5.default = 2
-o5.rmempty = false
-
-btn = s:option(Button, "", translate("Manual Rescan"),
-       translate("Force a manual uplink rescan / reconnect in 'trigger' mode."))
-btn:depends("trm_automatic", "")
-btn.inputtitle = translate("Rescan")
-btn.inputstyle = "find"
-btn.disabled = false
-
-function btn.write()
-       luci.sys.call("env -i /etc/init.d/travelmate start >/dev/null 2>&1")
-       luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate"))
+if fs.access("/usr/bin/qrencode") then
+       btn = s:option(Button, "btn", translate("View AP QR-Codes"),
+               translate("Connect your Android or iOS devices to your router's WiFi using the shown QR code."))
+       btn.inputtitle = translate("QR-Codes")
+       btn.inputstyle = "apply"
+       btn.disabled = false
+
+       function btn.write()
+               luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate", "apqr"))
+       end
 end
 
 -- Runtime information
@@ -180,28 +169,34 @@ e2 = e:option(Value, "trm_radio", translate("Radio selection"),
 e2.datatype = "and(uciname,rangelength(6,6))"
 e2.rmempty = true
 
-e3 = e:option(Value, "trm_maxretry", translate("Connection Limit"),
-       translate("Retry limit to connect to an uplink."))
-e3.default = 3
-e3.datatype = "range(1,10)"
+e3 = e:option(Value, "trm_triggerdelay", translate("Trigger Delay"),
+       translate("Additional trigger delay in seconds before travelmate processing begins."))
+e3.datatype = "range(1,60)"
+e3.default = 2
 e3.rmempty = false
 
-e4 = e:option(Value, "trm_minquality", translate("Signal Quality Threshold"),
-       translate("Minimum signal quality threshold as percent for conditional uplink (dis-) connections."))
-e4.default = 35
-e4.datatype = "range(20,80)"
+e4 = e:option(Value, "trm_maxretry", translate("Connection Limit"),
+       translate("Retry limit to connect to an uplink."))
+e4.default = 3
+e4.datatype = "range(1,10)"
 e4.rmempty = false
 
-e5 = e:option(Value, "trm_maxwait", translate("Interface Timeout"),
-       translate("How long should travelmate wait for a successful wlan uplink connection."))
-e5.default = 30
-e5.datatype = "range(20,40)"
+e5 = e:option(Value, "trm_minquality", translate("Signal Quality Threshold"),
+       translate("Minimum signal quality threshold as percent for conditional uplink (dis-) connections."))
+e5.default = 35
+e5.datatype = "range(20,80)"
 e5.rmempty = false
 
-e6 = e:option(Value, "trm_timeout", translate("Overall Timeout"),
-       translate("Timeout in seconds between retries in 'automatic' mode."))
-e6.default = 60
-e6.datatype = "range(30,300)"
+e6 = e:option(Value, "trm_maxwait", translate("Interface Timeout"),
+       translate("How long should travelmate wait for a successful wlan uplink connection."))
+e6.default = 30
+e6.datatype = "range(20,40)"
 e6.rmempty = false
 
+e7 = e:option(Value, "trm_timeout", translate("Overall Timeout"),
+       translate("Overall retry timeout in seconds."))
+e7.default = 60
+e7.datatype = "range(30,300)"
+e7.rmempty = false
+
 return m
index 50edd17..83011e9 100644 (file)
@@ -26,18 +26,23 @@ m.hidden = {
        wpa_version = http.formvalue("wpa_version")
 }
 
-if m.hidden.ssid ~= "" then
-       wssid = m:field(Value, "ssid", translate("SSID"))
-       wssid.datatype = "rangelength(1,32)"
-       wssid.default = m.hidden.ssid or ""
-else
+if m.hidden.ssid == "" then
        wssid = m:field(Value, "ssid", translate("SSID (hidden)"))
+else
+       wssid = m:field(Value, "ssid", translate("SSID"))
 end
+wssid.datatype = "rangelength(1,32)"
+wssid.default = m.hidden.ssid or ""
 
 nobssid = m:field(Flag, "no_bssid", translate("Ignore BSSID"))
-nobssid.default = nobssid.enabled
+if m.hidden.ssid == "" then
+       nobssid.default = nobssid.disabled
+else
+       nobssid.default = nobssid.enabled
+end
 
-bssid = m:field(Value, "bssid", translate("BSSID"))
+bssid = m:field(Value, "bssid", translate("BSSID"),
+       translatef("The BSSID information '%s' is optional and only required for hidden networks", m.hidden.bssid or ""))
 bssid:depends("no_bssid", 0)
 bssid.datatype = "macaddr"
 bssid.default = m.hidden.bssid or ""
@@ -171,6 +176,7 @@ function wssid.write(self, section, value)
        end
        uci:save("wireless")
        uci:commit("wireless")
+       luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
        http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
 end
 
index 0c3cc18..0a7678f 100644 (file)
@@ -9,5 +9,6 @@ if cfg ~= nil then
        uci:delete("wireless", cfg)
        uci:save("wireless")
        uci:commit("wireless")
+       luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
 end
 http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations"))
index ee4d342..f3ad762 100644 (file)
@@ -162,6 +162,7 @@ function wssid.write(self, section, value)
        end
        uci:save("wireless")
        uci:commit("wireless")
+       luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1")
        m.on_cancel()
 end
 
index 13342a3..a92dbe1 100644 (file)
@@ -44,9 +44,7 @@ This is free software, licensed under the Apache License, Version 2.0
         local e_ssid = string.gsub(ssid,"[\"\\';:, ]",[[\\\%1]])
         local e_key = string.gsub(key,"[\"\\';:, ]",[[\\\%1]])
         local qrcode = ""
-        if nixio.fs.access("/usr/bin/qrencode") then
-          qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'")
-        end
+        qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'")
 -%>
     <fieldset class="cbi-section">
         <legend>AP on <%=device%> with SSID "<%=ssid%>"</legend>
@@ -58,5 +56,10 @@ This is free software, licensed under the Apache License, Version 2.0
   end)
 %>
 </div>
+<div class="cbi-page-actions right">
+    <form class="inline" action="<%=luci.dispatcher.build_url('admin/services/travelmate/tab_from_cbi')%>" method="post">
+        <input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>"/>
+    </form>
+</div>
 
 <%+footer%>
index 30f34ef..535a9db 100644 (file)
@@ -12,9 +12,6 @@ msgstr ""
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Language: ja\n"
 
-msgid "AP QR-Codes"
-msgstr "AP QR-コード"
-
 msgid "Actions"
 msgstr "操作"
 
@@ -65,6 +62,12 @@ msgid ""
 msgstr ""
 "トラベル ルーター機能を有効化するための、 Travelmate パッケージの設定です。"
 
+msgid ""
+"Connect your Android or iOS devices to your router's WiFi using the shown QR "
+"code."
+msgstr ""
+"Android や iOS デバイスを、表示される QR コードを使用して WiFi に接続します。"
+
 msgid "Connection Limit"
 msgstr "接続制限"
 
@@ -110,9 +113,6 @@ msgstr "無線アップリンク設定の編集"
 msgid "Edit this Uplink"
 msgstr "このアップリンクを編集"
 
-msgid "Enable 'automatic' mode"
-msgstr "'automatic' モードの有効化"
-
 msgid "Enable travelmate"
 msgstr "Travelmate の有効化"
 
@@ -144,10 +144,6 @@ msgstr "TKIP"
 msgid "Force TKIP and CCMP (AES)"
 msgstr "TKIP と CCMP (AES)"
 
-msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
-msgstr ""
-"'trigger' モード時に、手動でアップリンクの再スキャンと再接続を行います。"
-
 msgid ""
 "Here you'll find the QR codes from all of your configured Access Points. It "
 "allows you to connect your Android or iOS devices to your router's WiFi "
@@ -176,19 +172,9 @@ msgstr "インターフェース タイムアウト"
 msgid "Interface Wizard"
 msgstr "インターフェース ウィザード"
 
-msgid ""
-"Keep travelmate in an active state. Check every n seconds the connection "
-"status, i.e. the uplink availability."
-msgstr ""
-"Travelmate をアクティブ状態で維持します。\"実行間隔\" で設定された時間毎"
-"(秒)に、アップリンクの可用性を確認するために接続状態をチェックします"
-
 msgid "Last rundate"
 msgstr "最終実行日時"
 
-msgid "Manual Rescan"
-msgstr "手動再スキャン"
-
 msgid ""
 "Minimum signal quality threshold as percent for conditional uplink (dis-) "
 "connections."
@@ -215,6 +201,9 @@ msgstr "デフォルトの設定が適切でない場合、さらに設定する
 msgid "Overall Timeout"
 msgstr "実行間隔"
 
+msgid "Overall retry timeout in seconds."
+msgstr ""
+
 msgid "Overview"
 msgstr "概要"
 
@@ -246,15 +235,15 @@ msgstr ""
 "ンクを追加することができます。現在使用されているアップリンクは、青色で強調さ"
 "れます。"
 
+msgid "QR-Codes"
+msgstr "QR-コード"
+
 msgid "Radio selection"
 msgstr "無線の選択"
 
 msgid "Repeat scan"
 msgstr "再スキャン"
 
-msgid "Rescan"
-msgstr "再スキャン"
-
 msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
 msgstr "Travelmate が指定された無線に接続するよう制御します。(例: 'radio0')"
 
@@ -292,6 +281,10 @@ msgid "Station Radio"
 msgstr "ステーション電波"
 
 msgid ""
+"The BSSID information '%s' is optional and only required for hidden networks"
+msgstr ""
+
+msgid ""
 "This form allows you to modify the content of the main firewall "
 "configuration file (/etc/config/firewall)."
 msgstr ""
@@ -326,9 +319,6 @@ msgstr ""
 "このフォームには、システムログ内の Travelmate に関するメッセージのみが表示さ"
 "れます。"
 
-msgid "Timeout in seconds between retries in 'automatic' mode."
-msgstr "'automatic' モード時に接続を確認または再試行する間隔(秒)です。"
-
 msgid "Travelmate"
 msgstr "Travelmate"
 
@@ -359,6 +349,9 @@ msgstr "アップリンク SSID"
 msgid "Uplink interface"
 msgstr "アップリンク インターフェース"
 
+msgid "View AP QR-Codes"
+msgstr "AP QR-コードを確認"
+
 msgid "View Logfile"
 msgstr "ログファイルの確認"
 
@@ -397,3 +390,26 @@ msgstr "(不明)"
 
 msgid "n/a"
 msgstr "利用不可"
+
+#~ msgid "Enable 'automatic' mode"
+#~ msgstr "'automatic' モードの有効化"
+
+#~ msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
+#~ msgstr ""
+#~ "'trigger' モード時に、手動でアップリンクの再スキャンと再接続を行います。"
+
+#~ msgid ""
+#~ "Keep travelmate in an active state. Check every n seconds the connection "
+#~ "status, i.e. the uplink availability."
+#~ msgstr ""
+#~ "Travelmate をアクティブ状態で維持します。\"実行間隔\" で設定された時間毎"
+#~ "(秒)に、アップリンクの可用性を確認するために接続状態をチェックします"
+
+#~ msgid "Manual Rescan"
+#~ msgstr "手動再スキャン"
+
+#~ msgid "Rescan"
+#~ msgstr "再スキャン"
+
+#~ msgid "Timeout in seconds between retries in 'automatic' mode."
+#~ msgstr "'automatic' モード時に接続を確認または再試行する間隔(秒)です。"
index 7cb6ac0..5ea4d4a 100644 (file)
@@ -12,9 +12,6 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "Language: pt_BR\n"
 
-msgid "AP QR-Codes"
-msgstr ""
-
 msgid "Actions"
 msgstr ""
 
@@ -62,6 +59,11 @@ msgid ""
 "functionality."
 msgstr ""
 
+msgid ""
+"Connect your Android or iOS devices to your router's WiFi using the shown QR "
+"code."
+msgstr ""
+
 msgid "Connection Limit"
 msgstr ""
 
@@ -105,9 +107,6 @@ msgstr ""
 msgid "Edit this Uplink"
 msgstr ""
 
-msgid "Enable 'automatic' mode"
-msgstr ""
-
 msgid "Enable travelmate"
 msgstr ""
 
@@ -137,9 +136,6 @@ msgstr ""
 msgid "Force TKIP and CCMP (AES)"
 msgstr ""
 
-msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
-msgstr ""
-
 msgid ""
 "Here you'll find the QR codes from all of your configured Access Points. It "
 "allows you to connect your Android or iOS devices to your router's WiFi "
@@ -165,17 +161,9 @@ msgstr ""
 msgid "Interface Wizard"
 msgstr ""
 
-msgid ""
-"Keep travelmate in an active state. Check every n seconds the connection "
-"status, i.e. the uplink availability."
-msgstr ""
-
 msgid "Last rundate"
 msgstr ""
 
-msgid "Manual Rescan"
-msgstr ""
-
 msgid ""
 "Minimum signal quality threshold as percent for conditional uplink (dis-) "
 "connections."
@@ -200,6 +188,9 @@ msgstr ""
 msgid "Overall Timeout"
 msgstr ""
 
+msgid "Overall retry timeout in seconds."
+msgstr ""
+
 msgid "Overview"
 msgstr ""
 
@@ -227,13 +218,13 @@ msgid ""
 "one. The currently used uplink is emphasized in blue."
 msgstr ""
 
-msgid "Radio selection"
+msgid "QR-Codes"
 msgstr ""
 
-msgid "Repeat scan"
+msgid "Radio selection"
 msgstr ""
 
-msgid "Rescan"
+msgid "Repeat scan"
 msgstr ""
 
 msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
@@ -273,6 +264,10 @@ msgid "Station Radio"
 msgstr ""
 
 msgid ""
+"The BSSID information '%s' is optional and only required for hidden networks"
+msgstr ""
+
+msgid ""
 "This form allows you to modify the content of the main firewall "
 "configuration file (/etc/config/firewall)."
 msgstr ""
@@ -297,9 +292,6 @@ msgid ""
 "messages only."
 msgstr ""
 
-msgid "Timeout in seconds between retries in 'automatic' mode."
-msgstr ""
-
 msgid "Travelmate"
 msgstr "Travelmate"
 
@@ -330,6 +322,9 @@ msgstr ""
 msgid "Uplink interface"
 msgstr ""
 
+msgid "View AP QR-Codes"
+msgstr ""
+
 msgid "View Logfile"
 msgstr ""
 
index 0b04e27..fad31bb 100644 (file)
@@ -15,9 +15,6 @@ msgstr ""
 "Project-Info: Это технический перевод, не дословный. Главное-удобный русский "
 "интерфейс, все проверялось в графическом режиме, совместим с другими apps\n"
 
-msgid "AP QR-Codes"
-msgstr ""
-
 msgid "Actions"
 msgstr "Действия"
 
@@ -65,6 +62,11 @@ msgid ""
 "functionality."
 msgstr "Настройка утилиты TravelMate - помощника путешественника. "
 
+msgid ""
+"Connect your Android or iOS devices to your router's WiFi using the shown QR "
+"code."
+msgstr ""
+
 msgid "Connection Limit"
 msgstr "Ограничение соединений"
 
@@ -110,9 +112,6 @@ msgstr "Редактировать настройки беспроводной 
 msgid "Edit this Uplink"
 msgstr "Редактировать настройки сети"
 
-msgid "Enable 'automatic' mode"
-msgstr "Включить режим 'автоматически'"
-
 msgid "Enable travelmate"
 msgstr "Включить Travelmate"
 
@@ -144,11 +143,6 @@ msgstr "Назначить TKIP"
 msgid "Force TKIP and CCMP (AES)"
 msgstr "Назначить TKIP и CCMP (AES)"
 
-msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
-msgstr ""
-"Принудительно выполнить повторное сканирование/повторное подключение внешних "
-"сетей в режиме 'ручной'."
-
 msgid ""
 "Here you'll find the QR codes from all of your configured Access Points. It "
 "allows you to connect your Android or iOS devices to your router's WiFi "
@@ -174,19 +168,9 @@ msgstr "Временная задержка интерфейса"
 msgid "Interface Wizard"
 msgstr "Помощник настройки интерфейса"
 
-msgid ""
-"Keep travelmate in an active state. Check every n seconds the connection "
-"status, i.e. the uplink availability."
-msgstr ""
-"Поддержка TravelMate в активном состоянии.<br />Проверка состояния "
-"соединения каждые n секунд, т.е. доступность внешней сети."
-
 msgid "Last rundate"
 msgstr "Дата последнего запуска"
 
-msgid "Manual Rescan"
-msgstr "Поиск сети вручную"
-
 msgid ""
 "Minimum signal quality threshold as percent for conditional uplink (dis-) "
 "connections."
@@ -213,6 +197,9 @@ msgstr ""
 msgid "Overall Timeout"
 msgstr "Общее время ожидания"
 
+msgid "Overall retry timeout in seconds."
+msgstr ""
+
 msgid "Overview"
 msgstr "Главное меню"
 
@@ -244,15 +231,15 @@ msgstr ""
 "упорядочивать существующий список внешних сетей или выполнять их поиск.<br /"
 ">Используемое сетевое соединение выделено синим цветом."
 
+msgid "QR-Codes"
+msgstr ""
+
 msgid "Radio selection"
 msgstr "Выбор Wi-Fi устройства"
 
 msgid "Repeat scan"
 msgstr "Повторить поиск"
 
-msgid "Rescan"
-msgstr "Пересканировать"
-
 msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
 msgstr "Выделить TravelMate-у конкретное Wi-Fi устройство, например 'radio0'."
 
@@ -290,6 +277,10 @@ msgid "Station Radio"
 msgstr "Wi-Fi устройство клиента"
 
 msgid ""
+"The BSSID information '%s' is optional and only required for hidden networks"
+msgstr ""
+
+msgid ""
 "This form allows you to modify the content of the main firewall "
 "configuration file (/etc/config/firewall)."
 msgstr ""
@@ -324,11 +315,6 @@ msgstr ""
 "Страница просмотра системного журнала, показаны только события связанные с "
 "работой утилиты TravelMate."
 
-msgid "Timeout in seconds between retries in 'automatic' mode."
-msgstr ""
-"Время ожидания в секундах между повторными попытками соединения в режиме "
-"'автоматически'."
-
 msgid "Travelmate"
 msgstr "TravelMate"
 
@@ -359,6 +345,9 @@ msgstr "SSID внешней сети"
 msgid "Uplink interface"
 msgstr "Интерфейс внешней сети"
 
+msgid "View AP QR-Codes"
+msgstr ""
+
 msgid "View Logfile"
 msgstr "Показать системный журнал"
 
@@ -396,6 +385,32 @@ msgstr "скрытый"
 msgid "n/a"
 msgstr "нет данных"
 
+#~ msgid "Enable 'automatic' mode"
+#~ msgstr "Включить режим 'автоматически'"
+
+#~ msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
+#~ msgstr ""
+#~ "Принудительно выполнить повторное сканирование/повторное подключение "
+#~ "внешних сетей в режиме 'ручной'."
+
+#~ msgid ""
+#~ "Keep travelmate in an active state. Check every n seconds the connection "
+#~ "status, i.e. the uplink availability."
+#~ msgstr ""
+#~ "Поддержка TravelMate в активном состоянии.<br />Проверка состояния "
+#~ "соединения каждые n секунд, т.е. доступность внешней сети."
+
+#~ msgid "Manual Rescan"
+#~ msgstr "Поиск сети вручную"
+
+#~ msgid "Rescan"
+#~ msgstr "Пересканировать"
+
+#~ msgid "Timeout in seconds between retries in 'automatic' mode."
+#~ msgstr ""
+#~ "Время ожидания в секундах между повторными попытками соединения в режиме "
+#~ "'автоматически'."
+
 #~ msgid ""
 #~ "How long should travelmate wait for a successful wlan interface reload."
 #~ msgstr ""
index e27c61a..8ba1766 100644 (file)
@@ -1,9 +1,6 @@
 msgid ""
 msgstr "Content-Type: text/plain; charset=UTF-8"
 
-msgid "AP QR-Codes"
-msgstr ""
-
 msgid "Actions"
 msgstr ""
 
@@ -51,6 +48,11 @@ msgid ""
 "functionality."
 msgstr ""
 
+msgid ""
+"Connect your Android or iOS devices to your router's WiFi using the shown QR "
+"code."
+msgstr ""
+
 msgid "Connection Limit"
 msgstr ""
 
@@ -94,9 +96,6 @@ msgstr ""
 msgid "Edit this Uplink"
 msgstr ""
 
-msgid "Enable 'automatic' mode"
-msgstr ""
-
 msgid "Enable travelmate"
 msgstr ""
 
@@ -126,9 +125,6 @@ msgstr ""
 msgid "Force TKIP and CCMP (AES)"
 msgstr ""
 
-msgid "Force a manual uplink rescan / reconnect in 'trigger' mode."
-msgstr ""
-
 msgid ""
 "Here you'll find the QR codes from all of your configured Access Points. It "
 "allows you to connect your Android or iOS devices to your router's WiFi "
@@ -154,17 +150,9 @@ msgstr ""
 msgid "Interface Wizard"
 msgstr ""
 
-msgid ""
-"Keep travelmate in an active state. Check every n seconds the connection "
-"status, i.e. the uplink availability."
-msgstr ""
-
 msgid "Last rundate"
 msgstr ""
 
-msgid "Manual Rescan"
-msgstr ""
-
 msgid ""
 "Minimum signal quality threshold as percent for conditional uplink (dis-) "
 "connections."
@@ -189,6 +177,9 @@ msgstr ""
 msgid "Overall Timeout"
 msgstr ""
 
+msgid "Overall retry timeout in seconds."
+msgstr ""
+
 msgid "Overview"
 msgstr ""
 
@@ -216,13 +207,13 @@ msgid ""
 "one. The currently used uplink is emphasized in blue."
 msgstr ""
 
-msgid "Radio selection"
+msgid "QR-Codes"
 msgstr ""
 
-msgid "Repeat scan"
+msgid "Radio selection"
 msgstr ""
 
-msgid "Rescan"
+msgid "Repeat scan"
 msgstr ""
 
 msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'."
@@ -262,6 +253,10 @@ msgid "Station Radio"
 msgstr ""
 
 msgid ""
+"The BSSID information '%s' is optional and only required for hidden networks"
+msgstr ""
+
+msgid ""
 "This form allows you to modify the content of the main firewall "
 "configuration file (/etc/config/firewall)."
 msgstr ""
@@ -286,9 +281,6 @@ msgid ""
 "messages only."
 msgstr ""
 
-msgid "Timeout in seconds between retries in 'automatic' mode."
-msgstr ""
-
 msgid "Travelmate"
 msgstr ""
 
@@ -319,6 +311,9 @@ msgstr ""
 msgid "Uplink interface"
 msgstr ""
 
+msgid "View AP QR-Codes"
+msgstr ""
+
 msgid "View Logfile"
 msgstr ""
 
index b44bf03..730ca72 100644 (file)
@@ -47,12 +47,12 @@ function index()
     if valman ~= "1" then
       entry({"admin", "services", "unbound", "files", "base"}, call("ShowUnboundConf"), _("UCI: Unbound"), 10).leaf = true
     else
-      entry({"admin", "services", "unbound", "files", "base"}, cbi("unbound/manual"), _("Edit: Unbound"), 10).leaf = true
+      entry({"admin", "services", "unbound", "files", "base"}, form("unbound/manual"), _("Edit: Unbound"), 10).leaf = true
     end
 
 
-    entry({"admin", "services", "unbound", "files", "server"}, cbi("unbound/server"), _("Edit: Server"), 20).leaf = true
-    entry({"admin", "services", "unbound", "files", "extended"}, cbi("unbound/extended"), _("Edit: Extended"), 30).leaf = true
+    entry({"admin", "services", "unbound", "files", "server"}, form("unbound/server"), _("Edit: Server"), 20).leaf = true
+    entry({"admin", "services", "unbound", "files", "extended"}, form("unbound/extended"), _("Edit: Extended"), 30).leaf = true
 
 
     if nixio.fs.access("/var/lib/unbound/unbound_dhcp.conf") then
index cdf7757..c92e379 100644 (file)
@@ -4,9 +4,12 @@
 -- Licensed to the public under the Apache License 2.0.
 
 local m1, s1
-local ena, mcf, lci, lsv, rlh, rpv, vld, nvd, eds, prt, tlm
-local ctl, dlk, dom, dty, lfq, wfq, exa, dp6, d64, pfx, qry, qrs
+local ena, mcf, lci, lsv
+local rlh, rpv, vld, nvd, eds, prt, tlm
+local ctl, dlk, dom, dty, lfq, wfq, exa
+local dp6, d64, pfx, qry, qrs
 local pro, tgr, rsc, rsn, ag2, stt
+local rpn, din, dfw
 local ucl = luci.model.uci.cursor()
 local valman = ucl:get_first("unbound", "unbound", "manual_conf")
 
@@ -19,10 +22,10 @@ s1.anonymous = true
 --LuCI, Unbound, or Not
 s1:tab("basic", translate("Basic"),
   translatef("<h3>Unbound Basic Settings</h3>\n"
-  .. "<a href=\"%s\" target=\"_blank\">Unbound</a>"
+  .. "<a href=\"%s\" target=\"_blank\">Unbound (link)</a>"
   .. " is a validating, recursive, and caching DNS resolver. "
-  .. "UCI help can be found on "
-  .. "<a href=\"%s\" target=\"_blank\">github</a>.",
+  .. "UCI documentation can be found on "
+  .. "<a href=\"%s\" target=\"_blank\">github (link)</a>.",
   "https://www.unbound.net/",
   "https://github.com/openwrt/packages/blob/master/net/unbound/files/README.md"))
 
@@ -34,8 +37,8 @@ mcf = s1:taboption("basic", Flag, "manual_conf", translate("Manual Conf:"),
   translate("Skip UCI and use /etc/unbound/unbound.conf"))
 mcf.rmempty = false
 
-lci = s1:taboption("basic", Flag, "extended_luci", translate("Advanced LuCI:"),
-  translate("See detailed tabs for debug and advanced manual configuration"))
+lci = s1:taboption("basic", Flag, "extended_luci", translate("Extended Tabs:"),
+  translate("See detailed tabs for statistics, debug, and manual configuration"))
 lci.rmempty = false
 
 
@@ -61,29 +64,23 @@ if valman ~= "1" then
   -- Not in manual configuration mode; show UCI
   s1:tab("advanced", translate("Advanced"),
     translatef("<h3>Unbound Advanced Settings</h3>\n"
-    .. "Advanced setttings and plugin modules for "
-    .. "<a href=\"%s\" target=\"_blank\">Unbound</a>"
+    .. "Link DHCP-DNS, Manipulate DNS, or protect your local domain in "
+    .. "<a href=\"%s\" target=\"_blank\">Unbound </a>"
     .. " DNS resolver.", "https://www.unbound.net/"))
 
+
   s1:tab("resource", translate("Resource"),
     translatef("<h3>Unbound Resource Settings</h3>\n"
     .. "Memory and protocol setttings for "
-    .. "<a href=\"%s\" target=\"_blank\">Unbound</a>"
+    .. "<a href=\"%s\" target=\"_blank\">Unbound </a>"
     .. " DNS resolver.", "https://www.unbound.net/"))
 
+
   --Basic Tab
   lsv = s1:taboption("basic", Flag, "localservice", translate("Local Service:"),
     translate("Accept queries only from local subnets"))
   lsv.rmempty = false
 
-  rlh = s1:taboption("basic", Flag, "rebind_localhost", translate("Block Localhost Rebind:"),
-    translate("Prevent upstream response of 127.0.0.0/8"))
-  rlh.rmempty = false
-
-  rpv = s1:taboption("basic", Flag, "rebind_protection", translate("Block Private Rebind:"),
-    translate("Prevent upstream response of RFC1918 ranges"))
-  rpv.rmempty = false
-
   vld = s1:taboption("basic", Flag, "validator", translate("Enable DNSSEC:"),
     translate("Enable the DNSSEC validator module"))
   vld.rmempty = false
@@ -93,31 +90,37 @@ if valman ~= "1" then
   nvd.rmempty = false
   nvd:depends({ validator = true })
 
-  eds = s1:taboption("basic", Value, "edns_size", translate("EDNS Size:"),
-    translate("Limit extended DNS packet size"))
-  eds.datatype = "and(uinteger,min(512),max(4096))"
-  eds.rmempty = false
+  din = s1:taboption("basic", DynamicList, "domain_insecure",
+    translate("Domain Insecure:"),
+    translate("List domains to bypass checks of DNSSEC"))
+  din:depends({ validator = true })
+
+  d64 = s1:taboption("basic", Flag, "dns64", translate("Enable DNS64:"),
+    translate("Enable the DNS64 module"))
+  d64.rmempty = false
+
+  pfx = s1:taboption("basic", Value, "dns64_prefix", translate("DNS64 Prefix:"),
+    translate("Prefix for generated DNS64 addresses"))
+  pfx.datatype = "ip6addr"
+  pfx.placeholder = "64:ff9b::/96"
+  pfx.optional = true
+  pfx:depends({ dns64 = true })
+
+  qry = s1:taboption("basic", Flag, "query_minimize", translate("Query Minimize:"),
+    translate("Break down query components for limited added privacy"))
+  qry.rmempty = false
+
+  qrs = s1:taboption("basic", Flag, "query_min_strict", translate("Strict Minimize:"),
+    translate("Strict version of 'query minimize' but it can break DNS"))
+  qrs.rmempty = false
+  qrs:depends({ query_minimize = true })
 
   prt = s1:taboption("basic", Value, "listen_port", translate("Listening Port:"),
     translate("Choose Unbounds listening port"))
   prt.datatype = "port"
   prt.rmempty = false
 
-  tlm = s1:taboption("basic", Value, "ttl_min", translate("TTL Minimum:"),
-    translate("Prevent excessively short cache periods"))
-  tlm.datatype = "and(uinteger,min(0),max(600))"
-  tlm.rmempty = false
-
-  --Advanced Tab
-  ctl = s1:taboption("advanced", ListValue, "unbound_control", translate("Unbound Control App:"),
-    translate("Enable access for unbound-control"))
-  ctl.rmempty = false
-  ctl:value("0", translate("No Remote Control"))
-  ctl:value("1", translate("Local Host, No Encryption"))
-  ctl:value("2", translate("Local Host, Encrypted"))
-  ctl:value("3", translate("Local Subnet, Encrypted"))
-  ctl:value("4", translate("Local Subnet, Static Encryption"))
-
+  --Avanced Tab
   dlk = s1:taboption("advanced", ListValue, "dhcp_link", translate("DHCP Link:"),
     translate("Link to supported programs to load DHCP into DNS"))
   dlk:value("none", translate("No Link"))
@@ -125,6 +128,11 @@ if valman ~= "1" then
   dlk:value("odhcpd", "odhcpd")
   dlk.rmempty = false
 
+  dp6 = s1:taboption("advanced", Flag, "dhcp4_slaac6", translate("DHCPv4 to SLAAC:"),
+    translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
+  dp6.rmempty = false
+  dp6:depends({ dhcp_link = "odhcpd" })
+
   dom = s1:taboption("advanced", Value, "domain", translate("Local Domain:"),
     translate("Domain suffix for this router and DHCP clients"))
   dom.placeholder = "lan"
@@ -142,7 +150,7 @@ if valman ~= "1" then
 
   lfq = s1:taboption("advanced", ListValue, "add_local_fqdn", translate("LAN DNS:"),
     translate("How to enter the LAN or local network router in DNS"))
-  lfq:value("0", translate("No DNS"))
+  lfq:value("0", translate("No Entry"))
   lfq:value("1", translate("Hostname, Primary Address"))
   lfq:value("2", translate("Hostname, All Addresses"))
   lfq:value("3", translate("Host FQDN, All Addresses"))
@@ -152,7 +160,7 @@ if valman ~= "1" then
 
   wfq = s1:taboption("advanced", ListValue, "add_wan_fqdn", translate("WAN DNS:"),
     translate("Override the WAN side router entry in DNS"))
-  wfq:value("0", translate("Upstream"))
+  wfq:value("0", translate("Use Upstream"))
   wfq:value("1", translate("Hostname, Primary Address"))
   wfq:value("2", translate("Hostname, All Addresses"))
   wfq:value("3", translate("Host FQDN, All Addresses"))
@@ -169,33 +177,41 @@ if valman ~= "1" then
   exa:depends({ dhcp_link = "none" })
   exa:depends({ dhcp_link = "odhcpd" })
 
-  dp6 = s1:taboption("advanced", Flag, "dhcp4_slaac6", translate("DHCPv4 to SLAAC:"),
-    translate("Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)"))
-  dp6.rmempty = false
+  dfw = s1:taboption("advanced", DynamicList, "domain_forward",
+    translate("Domain Forward:"),
+    translate("List domains to simply forward to stub resolvers in /tmp/resolve.auto"))
 
-  d64 = s1:taboption("advanced", Flag, "dns64", translate("Enable DNS64:"),
-    translate("Enable the DNS64 module"))
-  d64.rmempty = false
+  rlh = s1:taboption("advanced", Flag, "rebind_localhost", translate("Filter Localhost Rebind:"),
+    translate("Protect against upstream response of 127.0.0.0/8"))
+  rlh.rmempty = false
 
-  pfx = s1:taboption("advanced", Value, "dns64_prefix", translate("DNS64 Prefix:"),
-    translate("Prefix for generated DNS64 addresses"))
-  pfx.datatype = "ip6addr"
-  pfx.placeholder = "64:ff9b::/96"
-  pfx.optional = true
-  pfx:depends({ dns64 = true })
+  rpv = s1:taboption("advanced", ListValue, "rebind_protection", translate("Filter Private Rebind:"),
+    translate("Protect against upstream responses within local subnets"))
+  rpv:value("0", translate("No Filter"))
+  rpv:value("1", translate("Filter RFC1918/4193"))
+  rpv:value("2", translate("Filter Entire Subnet"))
+  rpv.rmempty = false
 
-  qry = s1:taboption("advanced", Flag, "query_minimize", translate("Query Minimize:"),
-    translate("Break down query components for limited added privacy"))
-  qry.rmempty = false
-
-  qrs = s1:taboption("advanced", Flag, "query_min_strict", translate("Strict Minimize:"),
-    translate("Strict version of 'query minimize' but it can break DNS"))
-  qrs.rmempty = false
-  qrs:depends({ query_minimize = true })
+  rpn = s1:taboption("advanced", Value, "rebind_interface", translate("Rebind Network Filter:"),
+    translate("Network subnets to filter from upstream responses"))
+  rpn.template = "cbi/network_netlist"
+  rpn.widget = "checkbox"
+  rpn.cast = "string"
+  rpn:depends({ rebind_protection = 2 })
+  rpn:depends({ rebind_protection = 3 })
 
   --TODO: dnsmasq needs to not reference resolve-file and get off port 53.
 
   --Resource Tuning Tab
+  ctl = s1:taboption("resource", ListValue, "unbound_control", translate("Unbound Control App:"),
+    translate("Enable access for unbound-control"))
+  ctl.rmempty = false
+  ctl:value("0", translate("No Remote Control"))
+  ctl:value("1", translate("Local Host, No Encryption"))
+  ctl:value("2", translate("Local Host, Encrypted"))
+  ctl:value("3", translate("Local Subnet, Encrypted"))
+  ctl:value("4", translate("Local Subnet, Static Encryption"))
+
   pro = s1:taboption("resource", ListValue, "protocol", translate("Recursion Protocol:"),
     translate("Chose the protocol recursion queries leave on"))
   pro:value("mixed", translate("IP4 and IP6"))
@@ -220,7 +236,7 @@ if valman ~= "1" then
   rsc.rmempty = false
 
   ag2 = s1:taboption("resource", Value, "root_age", translate("Root DSKEY Age:"),
-    translate("Limit days between RFC5011 to reduce flash writes"))
+    translate("Limit days between RFC 5011 copies to reduce flash writes"))
   ag2.datatype = "and(uinteger,min(1),max(99))"
   ag2:value("3", "3")
   ag2:value("9", "9 ("..translate("default")..")")
@@ -228,11 +244,21 @@ if valman ~= "1" then
   ag2:value("24", "24")
   ag2:value("99", "99 ("..translate("never")..")")
 
+  eds = s1:taboption("resource", Value, "edns_size", translate("EDNS Size:"),
+    translate("Limit extended DNS packet size"))
+  eds.datatype = "and(uinteger,min(512),max(4096))"
+  eds.rmempty = false
+
+  tlm = s1:taboption("resource", Value, "ttl_min", translate("TTL Minimum:"),
+    translate("Prevent excessively short cache periods"))
+  tlm.datatype = "and(uinteger,min(0),max(600))"
+  tlm.rmempty = false
+
   stt = s1:taboption("resource", Flag, "extended_stats", translate("Extended Statistics:"),
     translate("Extended statistics are printed from unbound-control"))
   stt.rmempty = false
 
-  tgr = s1:taboption("resource", Value, "trigger", translate("Trigger Networks:"),
+  tgr = s1:taboption("resource", Value, "trigger_interface", translate("Trigger Networks:"),
     translate("Networks that may trigger Unbound to reload (avoid wan6)"))
   tgr.template = "cbi/network_netlist"
   tgr.widget = "checkbox"
index e485708..95a0ef4 100644 (file)
@@ -21,7 +21,7 @@ end
 function act_status()
        local uci = luci.model.uci.cursor()
        local lease_file = uci:get("upnpd", "config", "upnp_lease_file")
-       
+
        local ipt = io.popen("iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null")
        if ipt then
                local upnpf = lease_file and io.open(lease_file, "r")
@@ -39,7 +39,7 @@ function act_status()
                                        num     = tonumber(num)
                                        extport = tonumber(extport)
                                        intport = tonumber(intport)
-                                       
+
                                        if upnpf then
                                                local uln = upnpf:read("*l")
                                                if uln then descr = uln:match(string.format("^%s:%d:%s:%d:%%d*:(.*)$", proto:upper(), extport, intaddr, intport)) end
@@ -76,7 +76,7 @@ function act_delete(num)
 
                local lease_file = uci:get("upnpd", "config", "upnp_lease_file")
                if lease_file and nixio.fs.access(lease_file) then
-                       luci.sys.call("sed -i -e '%dd' %q" %{ idx, lease_file })
+                       luci.sys.call("sed -i -e '%dd' %s" %{ idx, luci.util.shellquote(lease_file) })
                end
 
                luci.http.status(200, "OK")
index 6620d93..894de1c 100644 (file)
@@ -16,31 +16,31 @@ msgstr ""
 msgid ""
 "ACLs specify which external ports may be redirected to which internal "
 "addresses and ports"
-msgstr "指定外部端口的ACL可能会被重定向至某些内部地址及端口"
+msgstr "ACL 指定哪些外部端口可以被重定向至哪些内部地址及端口"
 
 msgid "Action"
 msgstr "动作"
 
 msgid "Active UPnP Redirects"
-msgstr "活动的UPnP重定向"
+msgstr "活动的 UPnP 重定向"
 
 msgid "Advanced Settings"
 msgstr "高级设置"
 
 msgid "Allow adding forwards only to requesting ip addresses"
-msgstr "允许添加只转发给请求的IP地址(当启用时,UPnP的客户可以只转发到其IP)"
+msgstr "允许只向请求的 IP 地址添加转发"
 
 msgid "Announced model number"
-msgstr "公布的型号"
+msgstr "通告的型号"
 
 msgid "Announced serial number"
-msgstr "公布的序列号"
+msgstr "通告的序列号"
 
 msgid "Clean rules interval"
-msgstr "定时自动清除无效规则"
+msgstr "定时清除规则"
 
 msgid "Clean rules threshold"
-msgstr "启动时清除端口转发"
+msgstr "清除规则阈值"
 
 msgid "Client Address"
 msgstr "客户端地址"
@@ -49,31 +49,31 @@ msgid "Client Port"
 msgstr "客户端端口"
 
 msgid "Collecting data..."
-msgstr "正在收集数据"
+msgstr "正在收集数据..."
 
 msgid "Comment"
 msgstr "备注"
 
 msgid "Delete"
-msgstr ""
+msgstr "删除"
 
 msgid "Description"
-msgstr ""
+msgstr "描述"
 
 msgid "Device UUID"
-msgstr "设备UUID"
+msgstr "设备 UUID"
 
 msgid "Downlink"
 msgstr "下行速率"
 
 msgid "Enable NAT-PMP functionality"
-msgstr "启用NAT-PMP功能"
+msgstr "启用 NAT-PMP 功能"
 
 msgid "Enable UPnP functionality"
-msgstr "启用UPnP功能"
+msgstr "启用 UPnP 功能"
 
 msgid "Enable additional logging"
-msgstr "启用额外的日志记录"
+msgstr "启用额外的日志"
 
 msgid "Enable secure mode"
 msgstr "启用安全模式"
@@ -94,19 +94,19 @@ msgid "Internal ports"
 msgstr "内部端口"
 
 msgid "MiniUPnP ACLs"
-msgstr "MiniUPnPACL"
+msgstr "MiniUPnP 的 ACL"
 
 msgid "MiniUPnP settings"
-msgstr "MiniUPnP设置"
+msgstr "MiniUPnP 设置"
 
 msgid "Notify interval"
-msgstr "è­¦æ\8a¥é\97´é\9a\94"
+msgstr "é\80\9aç\9f¥é\97´é\9a\94"
 
 msgid "Port"
 msgstr "端口"
 
 msgid "Presentation URL"
-msgstr "显示URL"
+msgstr "显示 URL"
 
 msgid "Protocol"
 msgstr "协议"
@@ -118,10 +118,10 @@ msgid "Report system instead of daemon uptime"
 msgstr "用系统运行时间代替进程运行时间"
 
 msgid "Start UPnP and NAT-PMP service"
-msgstr "启动UPnP与NAT-PMP服务"
+msgstr "启动 UPnP 与 NAT-PMP 服务"
 
 msgid "There are no active redirects."
-msgstr "没有活动的重定向"
+msgstr "没有活动的重定向"
 
 msgid "UPnP"
 msgstr "UPnP"
@@ -129,19 +129,19 @@ msgstr "UPnP"
 msgid ""
 "UPnP allows clients in the local network to automatically configure the "
 "router."
-msgstr "UPnP允许局域网内客户端自动设置路由上的端口转发。"
+msgstr "UPnP 允许局域网内客户端自动设置路由器上的端口转发。"
 
 msgid "UPnP lease file"
-msgstr "UPnP租约文件"
+msgstr "UPnP 租约文件"
 
 msgid "Universal Plug & Play"
-msgstr "通用即插即用(UPnP)"
+msgstr "通用即插即用(UPnP)"
 
 msgid "Uplink"
 msgstr "上行速率"
 
 msgid "Value in KByte/s, informational only"
-msgstr "值为KByte/s,仅供参考"
+msgstr "值为 KByte/s,仅供参考"
 
 #~ msgid "Delete Redirect"
 #~ msgstr "删除转发规则"
index 2b8d9ff..42d7d24 100644 (file)
@@ -21,12 +21,13 @@ style = (style and #style > 0) and style or "s"
 -- render image
 --
 if iface then
-       style = style:gsub("[^%w]", "")
-       iface = iface:gsub("[^%w%.%-%_]", "")
-
        luci.http.prepare_content("image/png")
 
-       local png = io.popen("vnstati -i '%s' '-%s' -o -" % { iface, style })
+       local png = io.popen("vnstati -i %s -%s -o -" %{
+               utl.shellquote(iface),
+               utl.shellquote(style)
+       })
+
        luci.http.write(png:read("*a"))
        png:close()
 
@@ -89,7 +90,7 @@ dbdir = dbdir or "/var/lib/vnstat"
 <%
        end
      end
-   end 
+   end
 %>
 
 <% if empty then %>
index 838840e..f426acc 100644 (file)
@@ -10,7 +10,7 @@ LUCI_TITLE:=VPN Bypass Web UI
 LUCI_DESCRIPTION:=Provides Web UI for VPNBypass service.
 LUCI_DEPENDS:=+luci +vpnbypass
 LUCI_PKGARCH:=all
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 include ../../luci.mk
 
index 9d2f5f4..6545154 100644 (file)
@@ -30,7 +30,7 @@ p2.optional = false
 -- Local Subnets
 r1 = s:option(DynamicList, "localsubnet", translate("Local IP Addresses to Bypass"), translate("Local IP addresses or subnets with direct internet access (outside of the VPN tunnel)"))
 r1.datatype    = "ip4addr"
--- r1.placeholder = luci.ip.new(uci.cursor():get("network", "lan", "ipaddr") .. "/" .. uci.cursor():get("network", "lan", "netmask"))
+-- r1.placeholder = luci.ip.new(m.uci:get("network", "lan", "ipaddr"), m.uci:get("network", "lan", "netmask"))
 r1.addremove = false
 r1.optional = false
 
index 05e2193..d41cfac 100644 (file)
@@ -28,14 +28,14 @@ msgid ""
 "Local IP addresses or subnets with direct internet access (outside of the "
 "VPN tunnel)"
 msgstr ""
-"Ð\9bокалÑ\8cнÑ\8bе IP-адÑ\80еÑ\81а Ð¸Ð»Ð¸ Ð¿Ð¾Ð´Ñ\81еÑ\82и Ñ\81 Ð¿Ñ\80Ñ\8fмÑ\8bм Ð´Ð¾Ñ\81Ñ\82Ñ\83пом Ð² Ð\98нтернет (вне VPN-"
+"Ð\9bокалÑ\8cнÑ\8bе IP-адÑ\80еÑ\81а Ð¸Ð»Ð¸ Ð¿Ð¾Ð´Ñ\81еÑ\82и Ñ\81 Ð¿Ñ\80Ñ\8fмÑ\8bм Ð´Ð¾Ñ\81Ñ\82Ñ\83пом Ð² Ð¸нтернет (вне VPN-"
 "туннеля)."
 
 msgid "Local Ports to Bypass"
-msgstr "Локальные порты<br />для обхода VPN"
+msgstr "Локальные порты для запуска обхода VPN"
 
 msgid "Local ports to trigger VPN Bypass"
-msgstr "Локальные порты для запуска обхода VPN."
+msgstr "Локальные порты<br />для обхода VPN"
 
 msgid "README"
 msgstr "Описание"
@@ -54,10 +54,10 @@ msgid "Remote Ports to Bypass"
 msgstr "Удаленные порты<br />для обхода VPN"
 
 msgid "Remote ports to trigger VPN Bypass"
-msgstr "Удаленные порты для запуска обхода VPN."
+msgstr "Удаленные порты для запуска обхода VPN"
 
 msgid "Start VPNBypass service"
-msgstr "Запуск сервиса VPNBypass"
+msgstr ""
 
 msgid "VPN Bypass"
 msgstr "Обход VPN"
@@ -66,4 +66,7 @@ msgid "VPN Bypass Settings"
 msgstr "Настройка обхода VPN"
 
 msgid "for syntax"
-msgstr "для синтаксиса."
+msgstr "для синтаксиса"
+
+#~ msgid "Enable/start service"
+#~ msgstr "Включение / Запуск сервиса"
index 92cdcf2..ae315bd 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=WireGuard Status
-LUCI_DEPENDS:=+wireguard-tools +kmod-wireguard
+LUCI_DEPENDS:=+wireguard-tools +kmod-wireguard +luci-proto-wireguard
 LUCI_PKGARCH:=all
 
 PKG_MAINTAINER:=Dan Luedtke <mail@danrl.com>
index dbbfdde..43ab84a 100644 (file)
@@ -1,6 +1,6 @@
 module("luci.controller.wol", package.seeall)
 
 function index()
-       entry({"admin", "services", "wol"}, cbi("wol"), _("Wake on LAN"), 90)
-       entry({"mini", "services", "wol"}, cbi("wol"), _("Wake on LAN"), 90)
+       entry({"admin", "services", "wol"}, form("wol"), _("Wake on LAN"), 90)
+       entry({"mini", "services", "wol"}, form("wol"), _("Wake on LAN"), 90)
 end
index d40dde0..43b87dd 100644 (file)
@@ -1,6 +1,7 @@
 -- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
 -- Licensed to the public under the Apache License 2.0.
 
+local utl = require "luci.util"
 local sys = require "luci.sys"
 local ipc = require "luci.ip"
 local fs  = require "nixio.fs"
@@ -69,8 +70,8 @@ function host.write(self, s, val)
                if util == "/usr/bin/etherwake" then
                        local iface = luci.http.formvalue("cbid.wol.1.iface")
                        local broadcast = luci.http.formvalue("cbid.wol.1.broadcast")
-                       cmd = "%s -D%s %s %q" %{
-                               util, (iface ~= "" and " -i %q" % iface or ""),
+                       cmd = "%s -D%s %s %q 2>&1" %{
+                               util, (iface ~= "" and " -i %s" % utl.shellquote(iface) or ""),
                                (broadcast == "1" and " -b" or ""), mac
                        }
                else
@@ -78,7 +79,7 @@ function host.write(self, s, val)
                end
 
                local msg = "<p><strong>%s</strong><br /><br /><code>%s<br /><br />" %{
-                       translate("Starting WoL utility:"), cmd
+                       translate("Starting WoL utility:"), utl.pcdata(cmd)
                }
 
                local p = io.popen(cmd .. " 2>&1")
diff --git a/build/check-controllers.sh b/build/check-controllers.sh
new file mode 100755 (executable)
index 0000000..573e6f8
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+[ -d build ] || {
+       echo "Execute as ./build/check-controllers.sh" >&2
+       exit 1
+}
+
+find . -type f -name '*.lua' -path '*/controller/*' | while read controller; do
+       controller="${controller#./}"
+       base="${controller%%/controller/*}"
+
+       sed -rne 's#^.*\b(cbi|form)\([[:space:]]*("([^"]*)"|\047([^\047]*)\047)[[:space:]]*[,)].*$#\1 \3\4#gp' "$controller" | while read type map; do
+               model="$base/model/cbi/$map.lua"
+               package="${controller##*/controller/}"; package="${package%.lua}"; package="luci.controller.${package//\//.}"
+
+               if ! grep -sqE '\bmodule[[:space:]]*\(?[[:space:]]*("|\047|\[=*\[)'"$package" "$controller"; then
+                       echo "'$controller' does not containt the expected\n\t'module(\"$package\", ...)' line.\n"
+               fi
+
+               grep -sqE '\b(Form|SimpleForm)[[:space:]]*\(' "$model" && ! grep -sqE '\bMap[[:space:]]*\(' "$model" && is_form=1 || is_form=0
+
+               if [ ! -f "$model" ]; then
+                       echo -e "'$controller' references $type('$map')\n\tbut expected file '$model' does not exist.\n"
+               elif [ $type = "cbi" -a $is_form = 1 ]; then
+                       echo -e "'$controller' references $type('$map')\n\tbut '$model' looks like a Form or SimpleForm.\n"
+               elif [ $type = "form" -a $is_form = 0 ]; then
+                       echo -e "'$controller' references $type('$map')\n\tbut '$model' does not look like a Form or SimpleForm.\n"
+               fi
+       done
+done
index 1bfc8ed..e1e4eda 100644 (file)
@@ -33,7 +33,7 @@ config 'defaults' 'ssidscheme'
 
 config 'defaults' 'interface'
        option 'netmask' '255.255.255.255'
-       option 'dns' '85.214.20.141 213.73.91.35 194.150.168.168 2001:4ce8::53 2001:910:800::12'
+       option 'dns' '85.214.20.141 194.150.168.168 2001:4ce8::53 2001:910:800::12'
 
 config 'dhcp' 'dhcp'
        option leasetime '5m'
index 6f395a1..9b08acc 100644 (file)
@@ -31,7 +31,7 @@ config 'defaults' 'ssidscheme'
 
 config 'defaults' 'interface'
        option 'netmask' '255.255.255.255'
-       option 'dns' '85.214.20.141 213.73.91.35 194.150.168.168 2001:4ce8::53 2001:910:800::12'
+       option 'dns' '85.214.20.141 194.150.168.168 2001:4ce8::53 2001:910:800::12'
 
 config 'dhcp' 'dhcp'
        option 'leasetime' '5m'
index 6a8f1f1..84bbdfe 100644 (file)
@@ -11,7 +11,7 @@ config 'community' 'profile'
 
 config 'defaults' 'interface'
        option 'netmask' '255.255.0.0'
-       option 'dns' '85.214.20.141 213.73.91.35 194.150.168.168'
+       option 'dns' '85.214.20.141 194.150.168.168'
        option 'delegate' '0'
 
 config 'defaults' 'wifi_device'
index ecc6f9b..c028a66 100644 (file)
@@ -7,4 +7,4 @@ config 'community' 'profile'
        option 'splash_prefix' '28'
 
 config 'defaults' 'interface'
-       option 'dns' '213.73.91.35 216.87.84.211'
+       option 'dns' '216.87.84.211'
index 2b9336f..f7128b6 100644 (file)
@@ -15,6 +15,7 @@ define Package/freifunk-common
   CATEGORY:=LuCI
   SUBMENU:=9. Freifunk
   TITLE:=Freifunk common files
+  DEPENDS:=+libuci-lua
 endef
 
 define Package/freifunk-common/description
diff --git a/contrib/package/lucihttp/Makefile b/contrib/package/lucihttp/Makefile
new file mode 100644 (file)
index 0000000..f1926a8
--- /dev/null
@@ -0,0 +1,54 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=lucihttp
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=https://github.com/jow-/lucihttp.git
+PKG_SOURCE_DATE:=2018-04-22
+PKG_SOURCE_VERSION:=ccc685e5c366490fc9f50a2e211ec79b7cf5962e
+PKG_MIRROR_HASH:=48608971cdfe20a6ad476fbf461527e4bf4786afeb8316fd6c38412bfeed4a3c
+CMAKE_INSTALL:=1
+
+PKG_LICENSE:=ISC
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_liblucihttp-lua
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/liblucihttp
+  SECTION:=libs
+  CATEGORY:=Libraries
+  ABI_VERSION:=$(PKG_VERSION)
+  TITLE:=LuCI HTTP utility library
+endef
+
+define Package/liblucihttp-lua
+  SECTION:=libs
+  CATEGORY:=Libraries
+  DEPENDS:=+liblucihttp +liblua
+  TITLE:=Lua binding for the LuCI HTTP utility library
+endef
+
+TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
+
+CMAKE_OPTIONS = \
+       -DLUAPATH=/usr/lib/lua \
+       -DBUILD_LUA=$(if $(CONFIG_PACKAGE_liblucihttp-lua),ON,OFF) \
+       -DBUILD_TESTS=OFF
+
+define Package/liblucihttp/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/liblucihttp.so $(1)/usr/lib/
+endef
+
+define Package/liblucihttp-lua/install
+       $(INSTALL_DIR) $(1)/usr/lib/lua
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/lua/lucihttp.so $(1)/usr/lib/lua/
+endef
+
+$(eval $(call BuildPackage,liblucihttp))
+$(eval $(call BuildPackage,liblucihttp-lua))
index c762b9b..5e3f3c2 100644 (file)
        </li>
 
        <li>
-               <a href="modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
        </tr>
 
        <tr>
-               <td class="name"><a href="modules/luci.http.protocol.html">luci.http.protocol</a></td>
-               <td class="summary"></td>
-       </tr>
-
-       <tr>
-               <td class="name"><a href="modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a></td>
+               <td class="name"><a href="modules/luci.http.conditionals.html">luci.http.conditionals</a></td>
                <td class="summary"></td>
        </tr>
 
        <tr>
-               <td class="name"><a href="modules/luci.http.protocol.date.html">luci.http.protocol.date</a></td>
+               <td class="name"><a href="modules/luci.http.date.html">luci.http.date</a></td>
                <td class="summary"></td>
        </tr>
 
        <tr>
-               <td class="name"><a href="modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a></td>
+               <td class="name"><a href="modules/luci.http.mime.html">luci.http.mime</a></td>
                <td class="summary"></td>
        </tr>
 
index 4ae88fe..e4b12e6 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
@@ -321,7 +317,6 @@ Create a CBI form model dispatching target.</td>
        <td class="summary">
  
 Fetch or create a dispatching node without setting the target module or 
 enabling the node.</td>
        </tr>
 
@@ -333,6 +328,13 @@ Dispatch an HTTP request.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#lookup">lookup</a>&nbsp;(...)</td>
+       <td class="summary">
+Lookup node in dispatching tree.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#modifier">modifier</a>&nbsp;(func, order)</td>
        <td class="summary">
  
@@ -857,8 +859,8 @@ Create a CBI form model dispatching target.
 
  
 Fetch or create a dispatching node without setting the target module or 
-enabling the node.
+enabling the node. 
+
 
 
 <h3>Parameters</h3>
@@ -914,6 +916,38 @@ Dispatch an HTTP request.
 
 
 
+<dt><a name="lookup"></a><strong>lookup</strong>&nbsp;(...)</dt>
+<dd>
+
+Lookup node in dispatching tree. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         ...: Virtual path
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+Node object, canonical url or nil if the path was not found.
+
+
+
+</dd>
+
+
+
+
 <dt><a name="modifier"></a><strong>modifier</strong>&nbsp;(func, order)</dt>
 <dd>
 
index ea04fc2..d75863f 100644 (file)
        <li><strong>luci.http</strong></li>
        
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
@@ -256,7 +252,6 @@ Get the value of a certain HTTP-Cookie.</td>
        <td class="summary">
  
 Get the value of a certain HTTP environment variable 
 or the environment table itself.</td>
        </tr>
 
@@ -268,6 +263,20 @@ Send a HTTP-Header.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#mimedecode_message_body">mimedecode_message_body</a>&nbsp;(src, msg, filecb)</td>
+       <td class="summary">
+Decode a mime encoded http message body with multipart/form-data Content-Type.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#parse_message_body">parse_message_body</a>&nbsp;(src, msg, filecb)</td>
+       <td class="summary">
+Try to extract and decode a http message body from the given ltn12 source.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#prepare_content">prepare_content</a>&nbsp;(mime)</td>
        <td class="summary">
  
@@ -311,6 +320,44 @@ Set the HTTP status code and status message.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#urldecode">urldecode</a>&nbsp;(str, no_plus)</td>
+       <td class="summary">
+Return the URL-decoded equivalent of a string.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#urldecode_message_body">urldecode_message_body</a>&nbsp;(src, msg)</td>
+       <td class="summary">
+Decode an urlencoded http message body with application/x-www-urlencoded 
+Content-Type.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#urldecode_params">urldecode_params</a>&nbsp;(url, tbl)</td>
+       <td class="summary">
+Extract and split urlencoded data pairs, separated bei either "&" or ";" 
+from given url or string.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#urlencode">urlencode</a>&nbsp;(str)</td>
+       <td class="summary">
+Return the URL-encoded equivalent of a string.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#urlencode_params">urlencode_params</a>&nbsp;(tbl)</td>
+       <td class="summary">
+Encode each key-value-pair in given table to x-www-urlencoded format, 
+separated by "&".</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#write">write</a>&nbsp;(content, src_err)</td>
        <td class="summary">
  
@@ -377,7 +424,6 @@ Encoded HTTP query string
 
  
 Close the HTTP-Connection. 
 
 
 
@@ -527,8 +573,8 @@ String containing cookie data
 
  
 Get the value of a certain HTTP environment variable 
-or the environment table itself.
+or the environment table itself. 
+
 
 
 <h3>Parameters</h3>
@@ -588,6 +634,135 @@ Send a HTTP-Header.
 
 
 
+<dt><a name="mimedecode_message_body"></a><strong>mimedecode_message_body</strong>&nbsp;(src, msg, filecb)</dt>
+<dd>
+
+Decode a mime encoded http message body with multipart/form-data Content-Type. 
+Stores all extracted data associated with its parameter name 
+in the params table within the given message object. Multiple parameter 
+values are stored as tables, ordinary ones as strings. 
+If an optional file callback function is given then it is feeded with the 
+file contents chunk by chunk and only the extracted file name is stored 
+within the params table. The callback function will be called subsequently 
+with three arguments: 
+ o Table containing decoded (name, file) and raw (headers) mime header data 
+ o String value containing a chunk of the file data 
+ o Boolean which indicates wheather the current chunk is the last one (eof) 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         src: Ltn12 source function
+       </li>
+       
+       <li>
+         msg: HTTP message object
+       </li>
+       
+       <li>
+         filecb: File callback function (optional)
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return values:</h3>
+<ol>
+       
+       <li>Value indicating successful operation (not nil means "ok")
+       
+       <li>String containing the error if unsuccessful
+       
+</ol>
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="">
+               parse_message_header
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="parse_message_body"></a><strong>parse_message_body</strong>&nbsp;(src, msg, filecb)</dt>
+<dd>
+
+Try to extract and decode a http message body from the given ltn12 source. 
+This function will examine the Content-Type within the given message object 
+to select the appropriate content decoder. 
+Currently the application/x-www-urlencoded and application/form-data 
+mime types are supported. If the encountered content encoding can't be 
+handled then the whole message body will be stored unaltered as "content" 
+property within the given message object. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         src: Ltn12 source function
+       </li>
+       
+       <li>
+         msg: HTTP message object
+       </li>
+       
+       <li>
+         filecb: File data callback (optional, see mimedecode_message_body())
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return values:</h3>
+<ol>
+       
+       <li>Value indicating successful operation (not nil means "ok")
+       
+       <li>String containing the error if unsuccessful
+       
+</ol>
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="">
+               parse_message_header
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
 <dt><a name="prepare_content"></a><strong>prepare_content</strong>&nbsp;(mime)</dt>
 <dd>
 
@@ -764,6 +939,243 @@ Set the HTTP status code and status message.
 
 
 
+<dt><a name="urldecode"></a><strong>urldecode</strong>&nbsp;(str, no_plus)</dt>
+<dd>
+
+Return the URL-decoded equivalent of a string. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         str: URL-encoded string
+       </li>
+       
+       <li>
+         no_plus: Don't decode + to " "
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+URL-decoded string
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urlencode">
+               urlencode
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="urldecode_message_body"></a><strong>urldecode_message_body</strong>&nbsp;(src, msg)</dt>
+<dd>
+
+Decode an urlencoded http message body with application/x-www-urlencoded 
+Content-Type. 
+Stores all extracted data associated with its parameter name in the params 
+table within the given message object. Multiple parameter values are stored 
+as tables, ordinary ones as strings. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         src: Ltn12 source function
+       </li>
+       
+       <li>
+         msg: HTTP message object
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return values:</h3>
+<ol>
+       
+       <li>Value indicating successful operation (not nil means "ok")
+       
+       <li>String containing the error if unsuccessful
+       
+</ol>
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="">
+               parse_message_header
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="urldecode_params"></a><strong>urldecode_params</strong>&nbsp;(url, tbl)</dt>
+<dd>
+
+Extract and split urlencoded data pairs, separated bei either "&" or ";" 
+from given url or string. Returns a table with urldecoded values. 
+Simple parameters are stored as string values associated with the parameter 
+name within the table. Parameters with multiple values are stored as array 
+containing the corresponding values. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         url: The url or string which contains x-www-urlencoded form data
+       </li>
+       
+       <li>
+         tbl: Use the given table for storing values (optional)
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+Table containing the urldecoded parameters
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urlencode_params">
+               urlencode_params
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="urlencode"></a><strong>urlencode</strong>&nbsp;(str)</dt>
+<dd>
+
+Return the URL-encoded equivalent of a string. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         str: Source string
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+URL-encoded string
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urldecode">
+               urldecode
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="urlencode_params"></a><strong>urlencode_params</strong>&nbsp;(tbl)</dt>
+<dd>
+
+Encode each key-value-pair in given table to x-www-urlencoded format, 
+separated by "&". 
+Tables are encoded as parameters with multiple values by repeating the 
+parameter name with each value. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         tbl: Table with the values
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+String containing encoded values
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urldecode_params">
+               urldecode_params
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
 <dt><a name="write"></a><strong>write</strong>&nbsp;(content, src_err)</dt>
 <dd>
 
@@ -771,7 +1183,8 @@ Set the HTTP status code and status message.
 Send a chunk of content data to the client. 
  
 This function is as a valid LTN12 sink. 
-If the content chunk is nil this function will automatically invoke close.
+If the content chunk is nil this function will automatically invoke close. 
+
 
 
 <h3>Parameters</h3>
index 0111cb2..3f0738b 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li><strong>luci.i18n</strong></li>
index 5a2b06e..50633a7 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 1f89626..fc13e31 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 761bd6e..db2d1da 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index f82eb40..79deb93 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index e8e145f..709cb9a 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 921153c..a0af318 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index c84d1eb..77a81fd 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
@@ -310,6 +306,13 @@ Get the directory for uncomitted changes.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#Cursor.get_session_id">Cursor:get_session_id</a>&nbsp;()</td>
+       <td class="summary">
+Get the effective session ID.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#Cursor.load">Cursor:load</a>&nbsp;(config)</td>
        <td class="summary">
  
@@ -366,6 +369,13 @@ Set the directory for uncommited changes.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#Cursor.set_session_id">Cursor:set_session_id</a>&nbsp;(id)</td>
+       <td class="summary">
+Set the effective session ID.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#Cursor.substate">Cursor:substate</a>&nbsp;()</td>
        <td class="summary">
  
@@ -631,8 +641,8 @@ Delete all sections of a given type that match certain criteria.
        </li>
        
        <li>
-         comparator: Function that will be called for each section and 
-returns a boolean whether to delete the current section (optional)
+         comparator: Function that will be called for each section and returns 
+                                       a boolean whether to delete the current section (optional)
        </li>
        
 </ul>
@@ -903,8 +913,8 @@ Get an option or list and return values as table.
 
 
 <h3>Return value:</h3>
-table.  If the option was not found, you will simply get 
-               an empty table.
+table.         If the option was not found, you will simply get an empty 
+                                       table.
 
 
 
@@ -936,6 +946,29 @@ Save directory
 
 
 
+<dt><a name="Cursor.get_session_id"></a><strong>Cursor:get_session_id</strong>&nbsp;()</dt>
+<dd>
+
+Get the effective session ID. 
+
+
+
+
+
+
+
+
+<h3>Return value:</h3>
+String containing the session ID
+
+
+
+</dd>
+
+
+
+
 <dt><a name="Cursor.load"></a><strong>Cursor:load</strong>&nbsp;(config)</dt>
 <dd>
 
@@ -1222,7 +1255,8 @@ has the same effect as deleting the option.
        </li>
        
        <li>
-         value: value or table. Raw values will become a single item table.
+         value: Value or table. Non-table values will be set as single 
+                                       item UCI list.
        </li>
        
 </ul>
@@ -1274,14 +1308,47 @@ Boolean whether operation succeeded
 
 
 
+<dt><a name="Cursor.set_session_id"></a><strong>Cursor:set_session_id</strong>&nbsp;(id)</dt>
+<dd>
+
+Set the effective session ID. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         id: String containing the session ID to set
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+Boolean whether operation succeeded
+
+
+
+</dd>
+
+
+
+
 <dt><a name="Cursor.substate"></a><strong>Cursor:substate</strong>&nbsp;()</dt>
 <dd>
 
  
-Create a sub-state of this cursor. The sub-state is tied to the parent 
+Create a sub-state of this cursor. 
  
-curser, means it the parent unloads or loads configs, the sub state will 
-do so as well.
+The sub-state is tied to the parent curser, means it the parent unloads or 
+loads configs, the sub state will do so as well. 
+
 
 
 
index f7cb020..1806578 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 203779c..7348f19 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 860c5fb..6342a51 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 596fb7c..e2c51f9 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 122afcc..5928281 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 09cef17..e7802bb 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 9c4f0a5..ffe09bd 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 37126dd..04f8bf0 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index eb1f6b3..6c89324 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 70d27d3..d3d45a1 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
@@ -275,13 +271,6 @@ This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
        </tr>
 
        <tr>
-       <td class="name" nowrap><a href="#dtable">dtable</a>&nbsp;()</td>
-       <td class="summary">
-Create a dynamic table which automatically creates subtables.</td>
-       </tr>
-
-       <tr>
        <td class="name" nowrap><a href="#dumptable">dumptable</a>&nbsp;(t, maxdepth)</td>
        <td class="summary">
  
@@ -349,7 +338,6 @@ Returns the absolute path to LuCI base directory.</td>
        <td class="summary">
  
 Parse certain units from the given string and return the canonical integer 
 value or 0 if the unit is unknown.</td>
        </tr>
 
@@ -379,7 +367,6 @@ Restore data previously serialized with serialize_data().</td>
        <td class="summary">
  
 Recursively serialize given data to lua code, suitable for restoring 
 with loadstring().</td>
        </tr>
 
@@ -392,11 +379,17 @@ Convert data structure to JSON
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#shellquote">shellquote</a>&nbsp;(value)</td>
+       <td class="summary">
+Safely quote value for use in shell commands.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#spairs">spairs</a>&nbsp;(t, f)</td>
        <td class="summary">
  
 Return a key, value iterator which returns the values sorted according to 
 the provided callback function.</td>
        </tr>
 
@@ -405,7 +398,6 @@ the provided callback function.</td>
        <td class="summary">
  
 Splits given string on a defined separator sequence and return a table 
 containing the resulting substrings.</td>
        </tr>
 
@@ -428,7 +420,6 @@ Strip HTML tags from given string.</td>
        <td class="summary">
  
 Create a new or get an already existing thread local store associated with 
 the current active coroutine.</td>
        </tr>
 
@@ -454,6 +445,20 @@ Update values in given table with the values from the second given table.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#urldecode">urldecode</a>&nbsp;(str, decode_plus)</td>
+       <td class="summary">
+Decode an URL-encoded string - optionally decoding the "+" sign to space.</td>
+       </tr>
+
+       <tr>
+       <td class="name" nowrap><a href="#urlencode">urlencode</a>&nbsp;(str)</td>
+       <td class="summary">
+URL-encode given string.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#vspairs">vspairs</a>&nbsp;(t)</td>
        <td class="summary">
  
@@ -549,7 +554,8 @@ Classes can inherit member functions and values from a base class.
 Class can be instantiated by calling them. All parameters will be passed 
 to the __init__ function of this class - if such a function exists. 
 The __init__ function must be used to set any object parameters that are not shared 
-with other objects of this class. Any return values will be ignored.
+with other objects of this class. Any return values will be ignored. 
+
 
 
 <h3>Parameters</h3>
@@ -728,8 +734,8 @@ Checks whether the given table contains the given value.
 
 
 <h3>Return value:</h3>
-number indicating the first index at which the given value occurs 
-                       within table or false.
+Number indicating the first index at which the given value occurs 
+                                       within table or false.
 
 
 
@@ -766,7 +772,7 @@ This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
 
 <h3>Return value:</h3>
 A boolean whether the function call succeeded and the returns 
-                               values of the function or the error object
+                                       values of the function or the error object
 
 
 
@@ -807,30 +813,7 @@ This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
 
 <h3>Return value:</h3>
 A boolean whether the function call succeeded and the return 
-                               values of either the function or the error handler
-
-
-
-</dd>
-
-
-
-
-<dt><a name="dtable"></a><strong>dtable</strong>&nbsp;()</dt>
-<dd>
-
-Create a dynamic table which automatically creates subtables. 
-
-
-
-
-
-
-
-
-<h3>Return value:</h3>
-Dynamic Table
+                                       values of either the function or the error handler
 
 
 
@@ -944,8 +927,8 @@ Iterator
 
  
 Return the current runtime bytecode of the given data. The byte code 
-will be stripped before it is returned.
+will be stripped before it is returned. 
+
 
 
 <h3>Parameters</h3>
@@ -976,11 +959,12 @@ String value containing the bytecode of the given data
 <dd>
 
  
-Return a matching iterator for the given value. The iterator will return 
+Return a matching iterator for the given value. 
  
-one token per invocation, the tokens are separated by whitespace. If the 
-input value is a table, it is transformed into a string first. A nil value 
-will result in a valid interator which aborts with the first invocation.
+The iterator will return one token per invocation, the tokens are separated by 
+whitespace. If the input value is a table, it is transformed into a string first. 
+A nil value will result in a valid interator which aborts with the first invocation. 
+
 
 
 <h3>Parameters</h3>
@@ -1094,7 +1078,8 @@ Sorted table containing the keys
  
 Return a key, value iterator for the given table. 
  
-The table pairs are sorted by key.
+The table pairs are sorted by key. 
+
 
 
 <h3>Parameters</h3>
@@ -1149,9 +1134,11 @@ String containing the directory path
 
  
 Parse certain units from the given string and return the canonical integer 
+value or 0 if the unit is unknown. 
  
-value or 0 if the unit is unknown. Upper- or lower case is irrelevant. 
+Upper- or lower case is irrelevant. 
 Recognized units are: 
        o "y"   - one year   (60*60*24*366) 
  o "m" - one month  (60*60*24*31) 
  o "w" - one week   (60*60*24*7) 
@@ -1163,7 +1150,8 @@ Recognized units are:
  o "gb"        - one gigabyte (1024*1024*1024) 
  o "kib" - one si kilobyte (1000) 
  o "mib"       - one si megabyte (1000*1000) 
- o "gib"       - one si gigabyte (1000*1000*1000)
+ o "gib"       - one si gigabyte (1000*1000*1000) 
+
 
 
 <h3>Parameters</h3>
@@ -1304,8 +1292,8 @@ Value containing the restored data structure
 
  
 Recursively serialize given data to lua code, suitable for restoring 
-with loadstring().
+with loadstring(). 
+
 
 
 <h3>Parameters</h3>
@@ -1381,13 +1369,45 @@ String containing the JSON if called without write callback
 
 
 
+<dt><a name="shellquote"></a><strong>shellquote</strong>&nbsp;(value)</dt>
+<dd>
+
+Safely quote value for use in shell commands. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         value: String containing the value to quote
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+Single-quote enclosed string with embedded quotes escaped
+
+
+
+</dd>
+
+
+
+
 <dt><a name="spairs"></a><strong>spairs</strong>&nbsp;(t, f)</dt>
 <dd>
 
  
 Return a key, value iterator which returns the values sorted according to 
-the provided callback function.
+the provided callback function. 
+
 
 
 <h3>Parameters</h3>
@@ -1423,11 +1443,13 @@ Function value containing the corresponding iterator
 
  
 Splits given string on a defined separator sequence and return a table 
+containing the resulting substrings. 
  
-containing the resulting substrings. The optional max parameter specifies 
-the number of bytes to process, regardless of the actual length of the given 
-string. The optional last parameter, regex, specifies whether the separator 
-sequence is interpreted as regular expression.
+The optional max parameter specifies the number of bytes to process, 
+regardless of the actual length of the given string. The optional last 
+parameter, regex, specifies whether the separator sequence is 
+nterpreted as regular expression. 
+
 
 
 <h3>Parameters</h3>
@@ -1471,10 +1493,11 @@ Table containing the resulting substrings
 <dd>
 
  
-Strips unnescessary lua bytecode from given string. Information like line 
+Strips unnescessary lua bytecode from given string. 
  
-numbers and debugging numbers will be discarded. Original version by 
-Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
+Information like line numbers and debugging numbers will be discarded. 
+Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) 
+
 
 
 <h3>Parameters</h3>
@@ -1538,9 +1561,11 @@ String with HTML tags stripped of
 
  
 Create a new or get an already existing thread local store associated with 
+the current active coroutine. 
  
-the current active coroutine. A thread local store is private a table object 
-whose values can't be accessed from outside of the running coroutine.
+A thread local store is private a table object 
+whose values can't be accessed from outside of the running coroutine. 
+
 
 
 
@@ -1636,7 +1661,8 @@ Table containin the ubus result
  
 Update values in given table with the values from the second given table. 
  
-Both table are - in fact - merged together.
+Both table are - in fact - merged together. 
+
 
 
 <h3>Parameters</h3>
@@ -1667,13 +1693,100 @@ Always nil
 
 
 
+<dt><a name="urldecode"></a><strong>urldecode</strong>&nbsp;(str, decode_plus)</dt>
+<dd>
+
+Decode an URL-encoded string - optionally decoding the "+" sign to space. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         str: Input string in x-www-urlencoded format
+       </li>
+       
+       <li>
+         decode_plus: Decode "+" signs to spaces if true (optional)
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+The decoded string
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urlencode">
+               urlencode
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
+<dt><a name="urlencode"></a><strong>urlencode</strong>&nbsp;(str)</dt>
+<dd>
+
+URL-encode given string. 
+
+
+
+<h3>Parameters</h3>
+<ul>
+       
+       <li>
+         str: String to encode
+       </li>
+       
+</ul>
+
+
+
+
+
+
+<h3>Return value:</h3>
+String containing the encoded data
+
+
+
+<h3>See also:</h3>
+<ul>
+       
+       <li><a href="#urldecode">
+               urldecode
+       </a>
+       
+</ul>
+
+</dd>
+
+
+
+
 <dt><a name="vspairs"></a><strong>vspairs</strong>&nbsp;(t)</dt>
 <dd>
 
  
 Return a key, value iterator for the given table. 
  
-The table pairs are sorted by value.
+The table pairs are sorted by value. 
+
 
 
 <h3>Parameters</h3>
index 48bedc8..7d98747 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 6158a77..7d2f48b 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index d9e67ea..7a7500a 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 99e036b..22dd793 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 7d258fc..1850991 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index a91b1ee..c84d318 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 3d99a64..5d6098a 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 700485d..6410ffb 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index fd82879..48e6fcd 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index b29c29d..4197363 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 79a7458..b91fe28 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 476e7fd..c9d3459 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 8ee0f62..65294a6 100644 (file)
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.html">luci.http.protocol</a>
+               <a href="../modules/luci.http.conditionals.html">luci.http.conditionals</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.conditionals.html">luci.http.protocol.conditionals</a>
+               <a href="../modules/luci.http.date.html">luci.http.date</a>
        </li>
 
        <li>
-               <a href="../modules/luci.http.protocol.date.html">luci.http.protocol.date</a>
-       </li>
-
-       <li>
-               <a href="../modules/luci.http.protocol.mime.html">luci.http.protocol.mime</a>
+               <a href="../modules/luci.http.mime.html">luci.http.mime</a>
        </li>
 
        <li>
index 1e7fd1b..b8bd428 100644 (file)
@@ -7,7 +7,7 @@
 include $(TOPDIR)/rules.mk
 
 LUCI_TITLE:=HTTP(S) client library
-LUCI_DEPENDS:=+luci-base +luci-lib-nixio
+LUCI_DEPENDS:=+luci-base +luci-lib-nixio +luci-lib-httpprotoutils
 
 include ../../luci.mk
 
index c76cc54..3e8d727 100644 (file)
@@ -7,8 +7,8 @@ local nixio = require "nixio"
 local ltn12 = require "luci.ltn12"
 local util = require "luci.util"
 local table = require "table"
-local http = require "luci.http.protocol"
-local date = require "luci.http.protocol.date"
+local http = require "luci.http"
+local date = require "luci.http.date"
 
 local type, pairs, ipairs, tonumber = type, pairs, ipairs, tonumber
 local unpack = unpack
diff --git a/libs/luci-lib-httpprotoutils/Makefile b/libs/luci-lib-httpprotoutils/Makefile
new file mode 100644 (file)
index 0000000..851a362
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2018 The LuCI Team <luci@lists.subsignal.org>
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=HTTP protocol utility functions
+LUCI_DEPENDS:=+luci-base
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/conditionals.lua b/libs/luci-lib-httpprotoutils/luasrc/http/conditionals.lua
new file mode 100644 (file)
index 0000000..86b4db2
--- /dev/null
@@ -0,0 +1,110 @@
+-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
+-- Licensed to the public under the Apache License 2.0.
+
+-- This class provides basic ETag handling and implements most of the
+-- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
+module("luci.http.conditionals", package.seeall)
+
+local date = require("luci.http.date")
+
+
+function mk_etag( stat )
+       if stat ~= nil then
+               return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
+       end
+end
+
+-- Test whether the given message object contains an "If-Match" header and
+-- compare it against the given stat object.
+function if_match( req, stat )
+       local h    = req.headers
+       local etag = mk_etag( stat )
+
+       -- Check for matching resource
+       if type(h['If-Match']) == "string" then
+               for ent in h['If-Match']:gmatch("([^, ]+)") do
+                       if ( ent == '*' or ent == etag ) and stat ~= nil then
+                               return true
+                       end
+               end
+
+               return false, 412
+       end
+
+       return true
+end
+
+-- Test whether the given message object contains an "If-Modified-Since" header
+-- and compare it against the given stat object.
+function if_modified_since( req, stat )
+       local h = req.headers
+
+       -- Compare mtimes
+       if type(h['If-Modified-Since']) == "string" then
+               local since = date.to_unix( h['If-Modified-Since'] )
+
+               if stat == nil or since < stat.mtime then
+                       return true
+               end
+
+               return false, 304, {
+                       ["ETag"]          = mk_etag( stat );
+                       ["Date"]          = date.to_http( os.time() );
+                       ["Last-Modified"] = date.to_http( stat.mtime )
+               }
+       end
+
+       return true
+end
+
+-- Test whether the given message object contains an "If-None-Match" header and
+-- compare it against the given stat object.
+function if_none_match( req, stat )
+       local h      = req.headers
+       local etag   = mk_etag( stat )
+       local method = req.env and req.env.REQUEST_METHOD or "GET"
+
+       -- Check for matching resource
+       if type(h['If-None-Match']) == "string" then
+               for ent in h['If-None-Match']:gmatch("([^, ]+)") do
+                       if ( ent == '*' or ent == etag ) and stat ~= nil then
+                               if method == "GET" or method == "HEAD" then
+                                       return false, 304, {
+                                               ["ETag"]          = etag;
+                                               ["Date"]          = date.to_http( os.time() );
+                                               ["Last-Modified"] = date.to_http( stat.mtime )
+                                       }
+                               else
+                                       return false, 412
+                               end
+                       end
+               end
+       end
+
+       return true
+end
+
+-- The If-Range header is currently not implemented due to the lack of general
+-- byte range stuff in luci.http.protocol . This function will always return
+-- false, 412 to indicate a failed precondition.
+function if_range( req, stat )
+       -- Sorry, no subranges (yet)
+       return false, 412
+end
+
+-- Test whether the given message object contains an "If-Unmodified-Since"
+-- header and compare it against the given stat object.
+function if_unmodified_since( req, stat )
+       local h = req.headers
+
+       -- Compare mtimes
+       if type(h['If-Unmodified-Since']) == "string" then
+               local since = date.to_unix( h['If-Unmodified-Since'] )
+
+               if stat ~= nil and since <= stat.mtime then
+                       return false, 412
+               end
+       end
+
+       return true
+end
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/conditionals.luadoc b/libs/luci-lib-httpprotoutils/luasrc/http/conditionals.luadoc
new file mode 100644 (file)
index 0000000..7ce0b5e
--- /dev/null
@@ -0,0 +1,85 @@
+---[[
+LuCI http protocol implementation - HTTP/1.1 bits.
+
+This class provides basic ETag handling and implements most of the
+conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
+]]
+module "luci.http.conditionals"
+
+---[[
+Implement 14.19 / ETag.
+
+@class function
+@name mk_etag
+@param stat    A file.stat structure
+@return                String containing the generated tag suitable for ETag headers
+]]
+
+---[[
+14.24 / If-Match
+
+Test whether the given message object contains an "If-Match" header and
+compare it against the given stat object.
+@class function
+@name if_match
+@param req     HTTP request message object
+@param stat    A file.stat object
+@return                Boolean indicating whether the precondition is ok
+@return                Alternative status code if the precondition failed
+]]
+
+---[[
+14.25 / If-Modified-Since
+
+Test whether the given message object contains an "If-Modified-Since" header
+and compare it against the given stat object.
+@class function
+@name if_modified_since
+@param req     HTTP request message object
+@param stat    A file.stat object
+@return                Boolean indicating whether the precondition is ok
+@return                Alternative status code if the precondition failed
+@return                Table containing extra HTTP headers if the precondition failed
+]]
+
+---[[
+14.26 / If-None-Match
+
+Test whether the given message object contains an "If-None-Match" header and
+compare it against the given stat object.
+@class function
+@name if_none_match
+@param req     HTTP request message object
+@param stat    A file.stat object
+@return                Boolean indicating whether the precondition is ok
+@return                Alternative status code if the precondition failed
+@return                Table containing extra HTTP headers if the precondition failed
+]]
+
+---[[
+14.27 / If-Range
+
+The If-Range header is currently not implemented due to the lack of general
+byte range stuff in luci.http.protocol . This function will always return
+false, 412 to indicate a failed precondition.
+@class function
+@name if_range
+@param req     HTTP request message object
+@param stat    A file.stat object
+@return                Boolean indicating whether the precondition is ok
+@return                Alternative status code if the precondition failed
+]]
+
+---[[
+14.28 / If-Unmodified-Since
+
+Test whether the given message object contains an "If-Unmodified-Since"
+header and compare it against the given stat object.
+@class function
+@name if_unmodified_since
+@param req     HTTP request message object
+@param stat    A file.stat object
+@return                Boolean indicating whether the precondition is ok
+@return                Alternative status code if the precondition failed
+]]
+
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/date.lua b/libs/luci-lib-httpprotoutils/luasrc/http/date.lua
new file mode 100644 (file)
index 0000000..72f1bdb
--- /dev/null
@@ -0,0 +1,87 @@
+-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
+-- Licensed to the public under the Apache License 2.0.
+
+-- This class contains functions to parse, compare and format http dates.
+module("luci.http.date", package.seeall)
+
+require("luci.sys.zoneinfo")
+
+
+MONTHS = {
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
+       "Sep", "Oct", "Nov", "Dec"
+}
+
+function tz_offset(tz)
+
+       if type(tz) == "string" then
+
+               -- check for a numeric identifier
+               local s, v = tz:match("([%+%-])([0-9]+)")
+               if s == '+' then s = 1 else s = -1 end
+               if v then v = tonumber(v) end
+
+               if s and v then
+                       return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) )
+
+               -- lookup symbolic tz
+               elseif luci.sys.zoneinfo.OFFSET[tz:lower()] then
+                       return luci.sys.zoneinfo.OFFSET[tz:lower()]
+               end
+
+       end
+
+       -- bad luck
+       return 0
+end
+
+function to_unix(date)
+
+       local wd, day, mon, yr, hr, min, sec, tz = date:match(
+               "([A-Z][a-z][a-z]), ([0-9]+) " ..
+               "([A-Z][a-z][a-z]) ([0-9]+) " ..
+               "([0-9]+):([0-9]+):([0-9]+) " ..
+               "([A-Z0-9%+%-]+)"
+       )
+
+       if day and mon and yr and hr and min and sec then
+               -- find month
+               local month = 1
+               for i = 1, 12 do
+                       if MONTHS[i] == mon then
+                               month = i
+                               break
+                       end
+               end
+
+               -- convert to epoch time
+               return tz_offset(tz) + os.time( {
+                       year  = yr,
+                       month = month,
+                       day   = day,
+                       hour  = hr,
+                       min   = min,
+                       sec   = sec
+               } )
+       end
+
+       return 0
+end
+
+function to_http(time)
+       return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
+end
+
+function compare(d1, d2)
+
+       if d1:match("[^0-9]") then d1 = to_unix(d1) end
+       if d2:match("[^0-9]") then d2 = to_unix(d2) end
+
+       if d1 == d2 then
+               return 0
+       elseif d1 < d2 then
+               return -1
+       else
+               return 1
+       end
+end
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/date.luadoc b/libs/luci-lib-httpprotoutils/luasrc/http/date.luadoc
new file mode 100644 (file)
index 0000000..6028fb4
--- /dev/null
@@ -0,0 +1,46 @@
+---[[
+LuCI http protocol implementation - date helper class.
+
+This class contains functions to parse, compare and format http dates.
+]]
+module "luci.http.date"
+
+---[[
+Return the time offset in seconds between the UTC and given time zone.
+
+@class function
+@name tz_offset
+@param tz      Symbolic or numeric timezone specifier
+@return                Time offset to UTC in seconds
+]]
+
+---[[
+Parse given HTTP date string and convert it to unix epoch time.
+
+@class function
+@name to_unix
+@param data    String containing the date
+@return                Unix epoch time
+]]
+
+---[[
+Convert the given unix epoch time to valid HTTP date string.
+
+@class function
+@name to_http
+@param time    Unix epoch time
+@return                String containing the formatted date
+]]
+
+---[[
+Compare two dates which can either be unix epoch times or HTTP date strings.
+
+@class function
+@name compare
+@param d1      The first date or epoch time to compare
+@param d2      The first date or epoch time to compare
+@return                -1  -  if d1 is lower then d2
+@return                0   -  if both dates are equal
+@return                1   -  if d1 is higher then d2
+]]
+
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/mime.lua b/libs/luci-lib-httpprotoutils/luasrc/http/mime.lua
new file mode 100644 (file)
index 0000000..0bcff8a
--- /dev/null
@@ -0,0 +1,78 @@
+-- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
+-- Licensed to the public under the Apache License 2.0.
+
+-- This class provides functions to guess mime types from file extensions and
+-- vice versa.
+module("luci.http.mime", package.seeall)
+
+require("luci.util")
+
+MIME_TYPES = {
+    ["txt"]   = "text/plain";
+    ["js"]    = "text/javascript";
+    ["css"]   = "text/css";
+    ["htm"]   = "text/html";
+    ["html"]  = "text/html";
+    ["patch"] = "text/x-patch";
+    ["c"]     = "text/x-csrc";
+    ["h"]     = "text/x-chdr";
+    ["o"]     = "text/x-object";
+    ["ko"]    = "text/x-object";
+
+    ["bmp"]   = "image/bmp";
+    ["gif"]   = "image/gif";
+    ["png"]   = "image/png";
+    ["jpg"]   = "image/jpeg";
+    ["jpeg"]  = "image/jpeg";
+    ["svg"]   = "image/svg+xml";
+
+    ["zip"]   = "application/zip";
+    ["pdf"]   = "application/pdf";
+    ["xml"]   = "application/xml";
+    ["xsl"]   = "application/xml";
+    ["doc"]   = "application/msword";
+    ["ppt"]   = "application/vnd.ms-powerpoint";
+    ["xls"]   = "application/vnd.ms-excel";
+    ["odt"]   = "application/vnd.oasis.opendocument.text";
+    ["odp"]   = "application/vnd.oasis.opendocument.presentation";
+    ["pl"]    = "application/x-perl";
+    ["sh"]    = "application/x-shellscript";
+    ["php"]   = "application/x-php";
+    ["deb"]   = "application/x-deb";
+    ["iso"]   = "application/x-cd-image";
+    ["tgz"]   = "application/x-compressed-tar";
+
+    ["mp3"]   = "audio/mpeg";
+    ["ogg"]   = "audio/x-vorbis+ogg";
+    ["wav"]   = "audio/x-wav";
+
+    ["mpg"]   = "video/mpeg";
+    ["mpeg"]  = "video/mpeg";
+    ["avi"]   = "video/x-msvideo";
+}
+
+-- "application/octet-stream" if the extension is unknown.
+function to_mime(filename)
+       if type(filename) == "string" then
+               local ext = filename:match("[^%.]+$")
+
+               if ext and MIME_TYPES[ext:lower()] then
+                       return MIME_TYPES[ext:lower()]
+               end
+       end
+
+       return "application/octet-stream"
+end
+
+-- given mime-type is unknown.
+function to_ext(mimetype)
+       if type(mimetype) == "string" then
+               for ext, type in luci.util.kspairs( MIME_TYPES ) do
+                       if type == mimetype then
+                               return ext
+                       end
+               end
+       end
+
+       return nil
+end
diff --git a/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc b/libs/luci-lib-httpprotoutils/luasrc/http/mime.luadoc
new file mode 100644 (file)
index 0000000..7751e2b
--- /dev/null
@@ -0,0 +1,34 @@
+---[[
+LuCI http protocol implementation - mime helper class.
+
+This class provides functions to guess mime types from file extensions and
+vice versa.
+]]
+module "luci.http.mime"
+
+---[[
+MIME mapping table containg extension - mimetype relations.
+
+@class table
+]]
+
+---[[
+Extract extension from a filename and return corresponding mime-type or
+
+"application/octet-stream" if the extension is unknown.
+@class function
+@name to_mime
+@param filename        The filename for which the mime type is guessed
+@return                        String containign the determined mime type
+]]
+
+---[[
+Return corresponding extension for a given mime type or nil if the
+
+given mime-type is unknown.
+@class function
+@name to_ext
+@param mimetype        The mimetype to retrieve the extension from
+@return                        String with the extension or nil for unknown type
+]]
+
index d3039ef..7f7d7e7 100644 (file)
@@ -12,8 +12,7 @@ LUCI_TYPE:=mod
 LUCI_BASENAME:=base
 
 LUCI_TITLE:=LuCI core libraries
-LUCI_DEPENDS:=+lua +libuci-lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc
-LUCI_EXTRA_DEPENDS:=libuci-lua (>= 2018-01-01)
+LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua
 
 PKG_SOURCE:=LuaSrcDiet-0.12.1.tar.bz2
 PKG_SOURCE_URL:=https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/luasrcdiet
index d40ec34..6c35372 100644 (file)
@@ -218,12 +218,13 @@ var cbi_validators = {
                        ((ipv4only == 1) && cbi_validators.ip4addr.apply(this));
        },
 
-       'hostname': function()
+       'hostname': function(strict)
        {
                if (this.length <= 253)
-                       return (this.match(/^[a-zA-Z0-9]+$/) != null ||
+                       return (this.match(/^[a-zA-Z0-9_]+$/) != null ||
                                (this.match(/^[a-zA-Z0-9_][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$/) &&
-                                this.match(/[^0-9.]/)));
+                                this.match(/[^0-9.]/))) &&
+                              (!strict || !this.match(/^_/));
 
                return false;
        },
index 3385f8f..91dcf3f 100644 (file)
@@ -39,7 +39,7 @@ XHR = function()
                        this._xmlHttp.abort();
        }
 
-       this.get = function(url,data,callback)
+       this.get = function(url,data,callback,timeout)
        {
                this.reinit();
 
@@ -54,6 +54,9 @@ XHR = function()
                        else
                                url += '?' + code;
 
+               if (!isNaN(timeout))
+                       xhr.timeout = timeout;
+
                xhr.open('GET', url, true);
 
                xhr.onreadystatechange = function()
@@ -76,7 +79,7 @@ XHR = function()
                xhr.send(null);
        }
 
-       this.post = function(url,data,callback)
+       this.post = function(url,data,callback,timeout)
        {
                this.reinit();
 
@@ -89,6 +92,9 @@ XHR = function()
                                callback(xhr);
                }
 
+               if (!isNaN(timeout))
+                       xhr.timeout = timeout;
+
                xhr.open('POST', url, true);
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                xhr.send(code);
@@ -168,7 +174,7 @@ XHR.get = function(url, data, callback)
        (new XHR()).get(url, data, callback);
 }
 
-XHR.poll = function(interval, url, data, callback)
+XHR.poll = function(interval, url, data, callback, post)
 {
        if (isNaN(interval) || interval < 1)
                interval = 5;
@@ -181,22 +187,38 @@ XHR.poll = function(interval, url, data, callback)
                        for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
                        {
                                if (!(XHR._t % e.interval) && !e.xhr.busy())
-                                       e.xhr.get(e.url, e.data, e.callback);
+                                       e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 - 5);
                        }
 
                        XHR._t++;
                };
        }
 
-       XHR._q.push({
+       var e = {
                interval: interval,
                callback: callback,
                url:      url,
                data:     data,
                xhr:      new XHR()
-       });
+       };
 
+       XHR._q.push(e);
        XHR.run();
+
+       return e;
+}
+
+XHR.stop = function(e)
+{
+       for (var i = 0; XHR._q && XHR._q[i]; i++) {
+               if (XHR._q[i] === e) {
+                       e.xhr.cancel();
+                       XHR._q.splice(i, 1);
+                       return true;
+               }
+       }
+
+       return false;
 }
 
 XHR.halt = function()
index 55cdf8a..99113e0 100644 (file)
@@ -199,13 +199,13 @@ function macaddr(val)
        return ip.checkmac(val) and true or false
 end
 
-function hostname(val)
+function hostname(val, strict)
        if val and (#val < 254) and (
           val:match("^[a-zA-Z_]+$") or
           (val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and
            val:match("[^0-9%.]"))
        ) then
-               return true
+               return (not strict or not val:match("^_"))
        end
        return false
 end
index 16b3254..1984fc4 100644 (file)
@@ -75,11 +75,16 @@ function error404(message)
        http.status(404, "Not Found")
        message = message or "Not Found"
 
-       require("luci.template")
-       if not util.copcall(luci.template.render, "error404") then
+       local function render()
+               local template = require "luci.template"
+               template.render("error404")
+       end
+
+       if not util.copcall(render) then
                http.prepare_content("text/plain")
                http.write(message)
        end
+
        return false
 end
 
@@ -113,7 +118,8 @@ function httpdispatch(request, prefix)
                end
        end
 
-       for node in pathinfo:gmatch("[^/]+") do
+       local node
+       for node in pathinfo:gmatch("[^/%z]+") do
                r[#r+1] = node
        end
 
@@ -136,8 +142,7 @@ local function require_post_security(target)
 
                                if (type(required_val) == "string" and
                                    request_val ~= required_val) or
-                                  (required_val == true and
-                                   (request_val == nil or request_val == ""))
+                                  (required_val == true and request_val == nil)
                                then
                                        return false
                                end
@@ -346,15 +351,23 @@ function dispatch(request)
                   ifattr      = function(...) return _ifattr(...) end;
                   attr        = function(...) return _ifattr(true, ...) end;
                   url         = build_url;
-               }, {__index=function(table, key)
+               }, {__index=function(tbl, key)
                        if key == "controller" then
                                return build_url()
                        elseif key == "REQUEST_URI" then
                                return build_url(unpack(ctx.requestpath))
+                       elseif key == "FULL_REQUEST_URI" then
+                               local url = { http.getenv("SCRIPT_NAME"), http.getenv("PATH_INFO") }
+                               local query = http.getenv("QUERY_STRING")
+                               if query and #query > 0 then
+                                       url[#url+1] = "?"
+                                       url[#url+1] = query
+                               end
+                               return table.concat(url, "")
                        elseif key == "token" then
                                return ctx.authtoken
                        else
-                               return rawget(table, key) or _G[key]
+                               return rawget(tbl, key) or _G[key]
                        end
                end})
        end
@@ -429,6 +442,13 @@ function dispatch(request)
                ctx.authuser = sdat.username
        end
 
+       if track.cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then
+               luci.http.status(200, "OK")
+               luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*")
+               luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
+               return
+       end
+
        if c and require_post_security(c.target) then
                if not test_post_security(c) then
                        return
@@ -650,6 +670,23 @@ function node(...)
        return c
 end
 
+function lookup(...)
+       local i, path = nil, {}
+       for i = 1, select('#', ...) do
+               local name, arg = nil, tostring(select(i, ...))
+               for name in arg:gmatch("[^/]+") do
+                       path[#path+1] = name
+               end
+       end
+
+       for i = #path, 1, -1 do
+               local node = context.treecache[table.concat(path, ".", 1, i)]
+               if node and (i == #path or node.leaf) then
+                       return node, build_url(unpack(path))
+               end
+       end
+end
+
 function _create_node(path)
        if #path == 0 then
                return context.tree
@@ -791,7 +828,16 @@ local function _cbi(self, ...)
 
        local state = nil
 
+       local i, res
        for i, res in ipairs(maps) do
+               if util.instanceof(res, cbi.SimpleForm) then
+                       io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n"
+                               % self.model)
+
+                       io.stderr:write("please change %s to use the form() action instead.\n"
+                               % table.concat(context.request, "/"))
+               end
+
                res.flow = config
                local cstate = res:parse()
                if cstate and (not state or cstate < state) then
@@ -884,7 +930,7 @@ end
 function cbi(model, config)
        return {
                type = "cbi",
-               post = { ["cbi.submit"] = "1" },
+               post = { ["cbi.submit"] = true },
                config = config,
                model = model,
                target = _cbi
@@ -912,6 +958,7 @@ local function _form(self, ...)
        local maps = luci.cbi.load(self.model, ...)
        local state = nil
 
+       local i, res
        for i, res in ipairs(maps) do
                local cstate = res:parse()
                if cstate and (not state or cstate < state) then
@@ -930,7 +977,7 @@ end
 function form(model)
        return {
                type = "cbi",
-               post = { ["cbi.submit"] = "1" },
+               post = { ["cbi.submit"] = true },
                model = model,
                target = _form
        }
index 743463c..ddf534b 100644 (file)
@@ -116,8 +116,8 @@ Create a new dispatching node and define common parameters.
 
 ---[[
 Fetch or create a dispatching node without setting the target module or
-
 enabling the node.
+
 @class function
 @name get
 @param ...             Virtual path
@@ -134,6 +134,15 @@ Fetch or create a new dispatching node.
 ]]
 
 ---[[
+Lookup node in dispatching tree.
+
+@class function
+@name lookup
+@param  ...            Virtual path
+@return Node object, canonical url or nil if the path was not found.
+]]
+
+---[[
 Alias the first (lowest order) page automatically
 
 
index 9cc9857..16fb04c 100644 (file)
@@ -1,18 +1,21 @@
 -- Copyright 2008 Steven Barth <steven@midlink.org>
+-- Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io>
 -- Licensed to the public under the Apache License 2.0.
 
-local ltn12 = require "luci.ltn12"
-local protocol = require "luci.http.protocol"
 local util  = require "luci.util"
-local string = require "string"
 local coroutine = require "coroutine"
 local table = require "table"
+local lhttp = require "lucihttp"
+local nixio = require "nixio"
+local ltn12 = require "luci.ltn12"
 
-local ipairs, pairs, next, type, tostring, error =
-       ipairs, pairs, next, type, tostring, error
+local table, ipairs, pairs, type, tostring, tonumber, error =
+       table, ipairs, pairs, type, tostring, tonumber, error
 
 module "luci.http"
 
+HTTP_MAX_CONTENT      = 1024*8         -- 8 kB maximum content size
+
 context = util.threadlocal()
 
 Request = util.class()
@@ -28,7 +31,7 @@ function Request.__init__(self, env, sourcein, sinkerr)
        self.message = {
                env = env,
                headers = {},
-               params = protocol.urldecode_params(env.QUERY_STRING or ""),
+               params = urldecode_params(env.QUERY_STRING or ""),
        }
 
        self.parsed_input = false
@@ -73,10 +76,7 @@ function Request.content(self)
 end
 
 function Request.getcookie(self, name)
-  local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
-  local p = ";" .. name .. "=(.-);"
-  local i, j, value = c:find(p)
-  return value and urldecode(value)
+       return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name)
 end
 
 function Request.getenv(self, name)
@@ -90,40 +90,34 @@ end
 function Request.setfilehandler(self, callback)
        self.filehandler = callback
 
-       -- If input has already been parsed then any files are either in temporary files
-       -- or are in self.message.params[key]
-       if self.parsed_input then
-               for param, value in pairs(self.message.params) do
-               repeat
-                       -- We're only interested in files
-                       if (not value["file"]) then break end
-                       -- If we were able to write to temporary file
-                       if (value["fd"]) then 
-                               fd = value["fd"]
-                               local eof = false
-                               repeat  
-                                       filedata = fd:read(1024)
-                                       if (filedata:len() < 1024) then
-                                               eof = true
-                                       end
-                                       callback({ name=value["name"], file=value["file"] }, filedata, eof)
-                               until (eof)
-                               fd:close()
-                               value["fd"] = nil
-                       -- We had to read into memory
-                       else
-                               -- There should only be one numbered value in table - the data
-                               for k, v in ipairs(value) do
-                                       callback({ name=value["name"], file=value["file"] }, v, true)
+       if not self.parsed_input then
+               return
+       end
+
+       -- If input has already been parsed then uploads are stored as unlinked
+       -- temporary files pointed to by open file handles in the parameter
+       -- value table. Loop all params, and invoke the file callback for any
+       -- param with an open file handle.
+       local name, value
+       for name, value in pairs(self.message.params) do
+               if type(value) == "table" then
+                       while value.fd do
+                               local data = value.fd:read(1024)
+                               local eof = (not data or data == "")
+
+                               callback(value, data, eof)
+
+                               if eof then
+                                       value.fd:close()
+                                       value.fd = nil
                                end
                        end
-               until true
                end
        end
 end
 
 function Request._parse_input(self)
-       protocol.parse_message_body(
+       parse_message_body(
                 self.input,
                 self.message,
                 self.filehandler
@@ -254,23 +248,307 @@ function redirect(url)
 end
 
 function build_querystring(q)
-       local s = { "?" }
+       local s, n, k, v = {}, 1, nil, nil
 
        for k, v in pairs(q) do
-               if #s > 1 then s[#s+1] = "&" end
-
-               s[#s+1] = urldecode(k)
-               s[#s+1] = "="
-               s[#s+1] = urldecode(v)
+               s[n+0] = (n == 1) and "?" or "&"
+               s[n+1] = util.urlencode(k)
+               s[n+2] = "="
+               s[n+3] = util.urlencode(v)
+               n = n + 4
        end
 
        return table.concat(s, "")
 end
 
-urldecode = protocol.urldecode
+urldecode = util.urldecode
 
-urlencode = protocol.urlencode
+urlencode = util.urlencode
 
 function write_json(x)
        util.serialize_json(x, write)
 end
+
+-- from given url or string. Returns a table with urldecoded values.
+-- Simple parameters are stored as string values associated with the parameter
+-- name within the table. Parameters with multiple values are stored as array
+-- containing the corresponding values.
+function urldecode_params(url, tbl)
+       local parser, name
+       local params = tbl or { }
+
+       parser = lhttp.urlencoded_parser(function (what, buffer, length)
+               if what == parser.TUPLE then
+                       name, value = nil, nil
+               elseif what == parser.NAME then
+                       name = lhttp.urldecode(buffer)
+               elseif what == parser.VALUE and name then
+                       params[name] = lhttp.urldecode(buffer) or ""
+               end
+
+               return true
+       end)
+
+       if parser then
+               parser:parse((url or ""):match("[^?]*$"))
+               parser:parse(nil)
+       end
+
+       return params
+end
+
+-- separated by "&". Tables are encoded as parameters with multiple values by
+-- repeating the parameter name with each value.
+function urlencode_params(tbl)
+       local k, v
+       local n, enc = 1, {}
+       for k, v in pairs(tbl) do
+               if type(v) == "table" then
+                       local i, v2
+                       for i, v2 in ipairs(v) do
+                               if enc[1] then
+                                       enc[n] = "&"
+                                       n = n + 1
+                               end
+
+                               enc[n+0] = lhttp.urlencode(k)
+                               enc[n+1] = "="
+                               enc[n+2] = lhttp.urlencode(v2)
+                               n = n + 3
+                       end
+               else
+                       if enc[1] then
+                               enc[n] = "&"
+                               n = n + 1
+                       end
+
+                       enc[n+0] = lhttp.urlencode(k)
+                       enc[n+1] = "="
+                       enc[n+2] = lhttp.urlencode(v)
+                       n = n + 3
+               end
+       end
+
+       return table.concat(enc, "")
+end
+
+-- Content-Type. Stores all extracted data associated with its parameter name
+-- in the params table within the given message object. Multiple parameter
+-- values are stored as tables, ordinary ones as strings.
+-- If an optional file callback function is given then it is feeded with the
+-- file contents chunk by chunk and only the extracted file name is stored
+-- within the params table. The callback function will be called subsequently
+-- with three arguments:
+--  o Table containing decoded (name, file) and raw (headers) mime header data
+--  o String value containing a chunk of the file data
+--  o Boolean which indicates wheather the current chunk is the last one (eof)
+function mimedecode_message_body(src, msg, file_cb)
+       local parser, header, field
+       local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
+
+       parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length)
+               if what == parser.PART_INIT then
+                       field = { }
+
+               elseif what == parser.HEADER_NAME then
+                       header = buffer:lower()
+
+               elseif what == parser.HEADER_VALUE and header then
+                       if header:lower() == "content-disposition" and
+                          lhttp.header_attribute(buffer, nil) == "form-data"
+                       then
+                               field.name = lhttp.header_attribute(buffer, "name")
+                               field.file = lhttp.header_attribute(buffer, "filename")
+                               field[1] = field.file
+                       end
+
+                       if field.headers then
+                               field.headers[header] = buffer
+                       else
+                               field.headers = { [header] = buffer }
+                       end
+
+               elseif what == parser.PART_BEGIN then
+                       return not field.file
+
+               elseif what == parser.PART_DATA and field.name and length > 0 then
+                       if field.file then
+                               if file_cb then
+                                       file_cb(field, buffer, false)
+                                       msg.params[field.name] = msg.params[field.name] or field
+                               else
+                                       if not field.fd then
+                                               field.fd = nixio.mkstemp(field.name)
+                                       end
+
+                                       if field.fd then
+                                               field.fd:write(buffer)
+                                               msg.params[field.name] = msg.params[field.name] or field
+                                       end
+                               end
+                       else
+                               field.value = buffer
+                       end
+
+               elseif what == parser.PART_END and field.name then
+                       if field.file and msg.params[field.name] then
+                               if file_cb then
+                                       file_cb(field, "", true)
+                               elseif field.fd then
+                                       field.fd:seek(0, "set")
+                               end
+                       else
+                               local val = msg.params[field.name]
+
+                               if type(val) == "table" then
+                                       val[#val+1] = field.value or ""
+                               elseif val ~= nil then
+                                       msg.params[field.name] = { val, field.value or "" }
+                               else
+                                       msg.params[field.name] = field.value or ""
+                               end
+                       end
+
+                       field = nil
+
+               elseif what == parser.ERROR then
+                       err = buffer
+               end
+
+               return true
+       end)
+
+       return ltn12.pump.all(src, function (chunk)
+               len = len + (chunk and #chunk or 0)
+
+               if maxlen and len > maxlen + 2 then
+                       return nil, "Message body size exceeds Content-Length"
+               end
+
+               if not parser or not parser:parse(chunk) then
+                       return nil, err
+               end
+
+               return true
+       end)
+end
+
+-- Content-Type. Stores all extracted data associated with its parameter name
+-- in the params table within the given message object. Multiple parameter
+-- values are stored as tables, ordinary ones as strings.
+function urldecode_message_body(src, msg)
+       local err, name, value, parser
+       local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
+
+       parser = lhttp.urlencoded_parser(function (what, buffer, length)
+               if what == parser.TUPLE then
+                       name, value = nil, nil
+               elseif what == parser.NAME then
+                       name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS)
+               elseif what == parser.VALUE and name then
+                       local val = msg.params[name]
+
+                       if type(val) == "table" then
+                               val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
+                       elseif val ~= nil then
+                               msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" }
+                       else
+                               msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
+                       end
+               elseif what == parser.ERROR then
+                       err = buffer
+               end
+
+               return true
+       end)
+
+       return ltn12.pump.all(src, function (chunk)
+               len = len + (chunk and #chunk or 0)
+
+               if maxlen and len > maxlen + 2 then
+                       return nil, "Message body size exceeds Content-Length"
+               elseif len > HTTP_MAX_CONTENT then
+                       return nil, "Message body size exceeds maximum allowed length"
+               end
+
+               if not parser or not parser:parse(chunk) then
+                       return nil, err
+               end
+
+               return true
+       end)
+end
+
+-- This function will examine the Content-Type within the given message object
+-- to select the appropriate content decoder.
+-- Currently the application/x-www-urlencoded and application/form-data
+-- mime types are supported. If the encountered content encoding can't be
+-- handled then the whole message body will be stored unaltered as "content"
+-- property within the given message object.
+function parse_message_body(src, msg, filecb)
+       if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then
+               local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil)
+
+               -- Is it multipart/mime ?
+               if ctype == "multipart/form-data" then
+                       return mimedecode_message_body(src, msg, filecb)
+
+               -- Is it application/x-www-form-urlencoded ?
+               elseif ctype == "application/x-www-form-urlencoded" then
+                       return urldecode_message_body(src, msg)
+
+               end
+
+               -- Unhandled encoding
+               -- If a file callback is given then feed it chunk by chunk, else
+               -- store whole buffer in message.content
+               local sink
+
+               -- If we have a file callback then feed it
+               if type(filecb) == "function" then
+                       local meta = {
+                               name = "raw",
+                               encoding = msg.env.CONTENT_TYPE
+                       }
+                       sink = function( chunk )
+                               if chunk then
+                                       return filecb(meta, chunk, false)
+                               else
+                                       return filecb(meta, nil, true)
+                               end
+                       end
+               -- ... else append to .content
+               else
+                       msg.content = ""
+                       msg.content_length = 0
+
+                       sink = function( chunk )
+                               if chunk then
+                                       if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
+                                               msg.content        = msg.content        .. chunk
+                                               msg.content_length = msg.content_length + #chunk
+                                               return true
+                                       else
+                                               return nil, "POST data exceeds maximum allowed length"
+                                       end
+                               end
+                               return true
+                       end
+               end
+
+               -- Pump data...
+               while true do
+                       local ok, err = ltn12.pump.step( src, sink )
+
+                       if not ok and err then
+                               return nil, err
+                       elseif not ok then -- eof
+                               return true
+                       end
+               end
+
+               return true
+       end
+
+       return false
+end
index 8a325db..f812123 100644 (file)
@@ -6,25 +6,24 @@ module "luci.http"
 ---[[
 Close the HTTP-Connection.
 
-
-@class function
-@name close
+@class                 function
+@name                  close
 ]]
 
 ---[[
 Return the request content if the request was of unknown type.
 
-@class function
-@name content
-@return        HTTP request body
-@return        HTTP request body length
+@class                 function
+@name                  content
+@return                        HTTP request body
+@return                        HTTP request body length
 ]]
 
 ---[[
 Get a certain HTTP input value or a table of all input values.
 
-@class function
-@name formvalue
+@class                 function
+@name                  formvalue
 @param name            Name of the GET or POST variable to fetch
 @param noparse Don't parse POST data before getting the value
 @return                        HTTP input value or table of all input value
@@ -33,8 +32,8 @@ Get a certain HTTP input value or a table of all input values.
 ---[[
 Get a table of all HTTP input values with a certain prefix.
 
-@class function
-@name formvaluetable
+@class                 function
+@name                  formvaluetable
 @param prefix  Prefix
 @return                        Table of all HTTP input values with given prefix
 ]]
@@ -42,18 +41,18 @@ Get a table of all HTTP input values with a certain prefix.
 ---[[
 Get the value of a certain HTTP-Cookie.
 
-@class function
-@name getcookie
+@class                 function
+@name                  getcookie
 @param name            Cookie Name
 @return                        String containing cookie data
 ]]
 
 ---[[
 Get the value of a certain HTTP environment variable
-
 or the environment table itself.
-@class function
-@name getenv
+
+@class                 function
+@name                  getenv
 @param name            Environment variable
 @return                        HTTP environment value or environment table
 ]]
@@ -61,41 +60,41 @@ or the environment table itself.
 ---[[
 Set a handler function for incoming user file uploads.
 
-@class function
-@name setfilehandler
+@class                 function
+@name                  setfilehandler
 @param callback        Handler function
 ]]
 
 ---[[
 Send a HTTP-Header.
 
-@class function
-@name header
-@param key     Header key
-@param value Header value
+@class                 function
+@name                  header
+@param key             Header key
+@param value   Header value
 ]]
 
 ---[[
 Set the mime type of following content data.
 
-@class function
-@name prepare_content
-@param mime    Mimetype of following content
+@class                 function
+@name                  prepare_content
+@param mime            Mimetype of following content
 ]]
 
 ---[[
 Get the RAW HTTP input source
 
-@class function
-@name source
-@return        HTTP LTN12 source
+@class                 function
+@name                  source
+@return                        HTTP LTN12 source
 ]]
 
 ---[[
 Set the HTTP status code and status message.
 
-@class function
-@name status
+@class                 function
+@name                  status
 @param code            Status code
 @param message Status message
 ]]
@@ -105,8 +104,9 @@ Send a chunk of content data to the client.
 
 This function is as a valid LTN12 sink.
 If the content chunk is nil this function will automatically invoke close.
-@class function
-@name write
+
+@class                 function
+@name                  write
 @param content Content chunk
 @param src_err Error object from source (optional)
 @see close
@@ -115,51 +115,146 @@ If the content chunk is nil this function will automatically invoke close.
 ---[[
 Splice data from a filedescriptor to the client.
 
-@class function
-@name splice
-@param fp      File descriptor
-@param size    Bytes to splice (optional)
+@class                 function
+@name                  splice
+@param fp              File descriptor
+@param size            Bytes to splice (optional)
 ]]
 
 ---[[
 Redirects the client to a new URL and closes the connection.
 
-@class function
-@name redirect
-@param url     Target URL
+@class                 function
+@name                  redirect
+@param url             Target URL
 ]]
 
 ---[[
 Create a querystring out of a table of key - value pairs.
 
-@class function
-@name build_querystring
-@param table           Query string source table
+@class                 function
+@name                  build_querystring
+@param table   Query string source table
 @return                        Encoded HTTP query string
 ]]
 
 ---[[
 Return the URL-decoded equivalent of a string.
 
+@class                 function
+@name                  urldecode
 @param str             URL-encoded string
 @param no_plus Don't decode + to " "
 @return                        URL-decoded string
-@see urlencode
+@see                   urlencode
 ]]
 
 ---[[
 Return the URL-encoded equivalent of a string.
 
+@class                 function
+@name                  urlencode
 @param str             Source string
 @return                        URL-encoded string
-@see urldecode
+@see                   urldecode
 ]]
 
 ---[[
 Send the given data as JSON encoded string.
 
-@class function
-@name write_json
+@class                 function
+@name                  write_json
 @param data            Data to send
 ]]
 
+---[[
+Extract and split urlencoded data pairs, separated bei either "&" or ";"
+from given url or string. Returns a table with urldecoded values.
+
+Simple parameters are stored as string values associated with the parameter
+name within the table. Parameters with multiple values are stored as array
+containing the corresponding values.
+
+@class                 function
+@name                  urldecode_params
+@param url             The url or string which contains x-www-urlencoded form data
+@param tbl             Use the given table for storing values (optional)
+@return                        Table containing the urldecoded parameters
+@see                   urlencode_params
+]]
+
+---[[
+Encode each key-value-pair in given table to x-www-urlencoded format,
+separated by "&".
+
+Tables are encoded as parameters with multiple values by repeating the
+parameter name with each value.
+
+@class                 function
+@name                  urlencode_params
+@param tbl             Table with the values
+@return                        String containing encoded values
+@see                   urldecode_params
+]]
+
+---[[
+Decode a mime encoded http message body with multipart/form-data Content-Type.
+
+Stores all extracted data associated with its parameter name
+in the params table within the given message object. Multiple parameter
+values are stored as tables, ordinary ones as strings.
+
+If an optional file callback function is given then it is feeded with the
+file contents chunk by chunk and only the extracted file name is stored
+within the params table. The callback function will be called subsequently
+with three arguments:
+ o Table containing decoded (name, file) and raw (headers) mime header data
+ o String value containing a chunk of the file data
+ o Boolean which indicates wheather the current chunk is the last one (eof)
+
+@class                 function
+@name                  mimedecode_message_body
+@param src             Ltn12 source function
+@param msg             HTTP message object
+@param filecb  File callback function (optional)
+@return                        Value indicating successful operation (not nil means "ok")
+@return                        String containing the error if unsuccessful
+@see                   parse_message_header
+]]
+
+---[[
+Decode an urlencoded http message body with application/x-www-urlencoded
+Content-Type.
+
+Stores all extracted data associated with its parameter name in the params
+table within the given message object. Multiple parameter values are stored
+as tables, ordinary ones as strings.
+
+@class                 function
+@name                  urldecode_message_body
+@param src             Ltn12 source function
+@param msg             HTTP message object
+@return                        Value indicating successful operation (not nil means "ok")
+@return                        String containing the error if unsuccessful
+@see                   parse_message_header
+]]
+
+---[[
+Try to extract and decode a http message body from the given ltn12 source.
+This function will examine the Content-Type within the given message object
+to select the appropriate content decoder.
+
+Currently the application/x-www-urlencoded and application/form-data
+mime types are supported. If the encountered content encoding can't be
+handled then the whole message body will be stored unaltered as "content"
+property within the given message object.
+
+@class                 function
+@name                  parse_message_body
+@param src             Ltn12 source function
+@param msg             HTTP message object
+@param filecb  File data callback (optional, see mimedecode_message_body())
+@return                        Value indicating successful operation (not nil means "ok")
+@return                        String containing the error if unsuccessful
+@see                   parse_message_header
+]]
diff --git a/modules/luci-base/luasrc/http/protocol.lua b/modules/luci-base/luasrc/http/protocol.lua
deleted file mode 100644 (file)
index 0a8b2fb..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- This class contains several functions useful for http message- and content
--- decoding and to retrive form data from raw http messages.
-module("luci.http.protocol", package.seeall)
-
-local ltn12 = require("luci.ltn12")
-
-HTTP_MAX_CONTENT      = 1024*8         -- 8 kB maximum content size
-
--- the "+" sign to " " - and return the decoded string.
-function urldecode( str, no_plus )
-
-       local function __chrdec( hex )
-               return string.char( tonumber( hex, 16 ) )
-       end
-
-       if type(str) == "string" then
-               if not no_plus then
-                       str = str:gsub( "+", " " )
-               end
-
-               str = str:gsub( "%%([a-fA-F0-9][a-fA-F0-9])", __chrdec )
-       end
-
-       return str
-end
-
--- from given url or string. Returns a table with urldecoded values.
--- Simple parameters are stored as string values associated with the parameter
--- name within the table. Parameters with multiple values are stored as array
--- containing the corresponding values.
-function urldecode_params( url, tbl )
-
-       local params = tbl or { }
-
-       if url:find("?") then
-               url = url:gsub( "^.+%?([^?]+)", "%1" )
-       end
-
-       for pair in url:gmatch( "[^&;]+" ) do
-
-               -- find key and value
-               local key = urldecode( pair:match("^([^=]+)")     )
-               local val = urldecode( pair:match("^[^=]+=(.+)$") )
-
-               -- store
-               if type(key) == "string" and key:len() > 0 then
-                       if type(val) ~= "string" then val = "" end
-
-                       if not params[key] then
-                               params[key] = val
-                       elseif type(params[key]) ~= "table" then
-                               params[key] = { params[key], val }
-                       else
-                               table.insert( params[key], val )
-                       end
-               end
-       end
-
-       return params
-end
-
-function urlencode( str )
-
-       local function __chrenc( chr )
-               return string.format(
-                       "%%%02x", string.byte( chr )
-               )
-       end
-
-       if type(str) == "string" then
-               str = str:gsub(
-                       "([^a-zA-Z0-9$_%-%.%~])",
-                       __chrenc
-               )
-       end
-
-       return str
-end
-
--- separated by "&". Tables are encoded as parameters with multiple values by
--- repeating the parameter name with each value.
-function urlencode_params( tbl )
-       local enc = ""
-
-       for k, v in pairs(tbl) do
-               if type(v) == "table" then
-                       for i, v2 in ipairs(v) do
-                               enc = enc .. ( #enc > 0 and "&" or "" ) ..
-                                       urlencode(k) .. "=" .. urlencode(v2)
-                       end
-               else
-                       enc = enc .. ( #enc > 0 and "&" or "" ) ..
-                               urlencode(k) .. "=" .. urlencode(v)
-               end
-       end
-
-       return enc
-end
-
--- (Internal function)
--- Initialize given parameter and coerce string into table when the parameter
--- already exists.
-local function __initval( tbl, key )
-       if tbl[key] == nil then
-               tbl[key] = ""
-       elseif type(tbl[key]) == "string" then
-               tbl[key] = { tbl[key], "" }
-       else
-               table.insert( tbl[key], "" )
-       end
-end
-
--- (Internal function)
--- Initialize given file parameter.
-local function __initfileval( tbl, key, filename, fd )
-       if tbl[key] == nil then
-               tbl[key] = { file=filename, fd=fd, name=key, "" }
-       else
-               table.insert( tbl[key], "" )
-       end
-end
-
--- (Internal function)
--- Append given data to given parameter, either by extending the string value
--- or by appending it to the last string in the parameter's value table.
-local function __appendval( tbl, key, chunk )
-       if type(tbl[key]) == "table" then
-               tbl[key][#tbl[key]] = tbl[key][#tbl[key]] .. chunk
-       else
-               tbl[key] = tbl[key] .. chunk
-       end
-end
-
--- (Internal function)
--- Finish the value of given parameter, either by transforming the string value
--- or - in the case of multi value parameters - the last element in the
--- associated values table.
-local function __finishval( tbl, key, handler )
-       if handler then
-               if type(tbl[key]) == "table" then
-                       tbl[key][#tbl[key]] = handler( tbl[key][#tbl[key]] )
-               else
-                       tbl[key] = handler( tbl[key] )
-               end
-       end
-end
-
-
--- Table of our process states
-local process_states = { }
-
--- Extract "magic", the first line of a http message.
--- Extracts the message type ("get", "post" or "response"), the requested uri
--- or the status code if the line descripes a http response.
-process_states['magic'] = function( msg, chunk, err )
-
-       if chunk ~= nil then
-               -- ignore empty lines before request
-               if #chunk == 0 then
-                       return true, nil
-               end
-
-               -- Is it a request?
-               local method, uri, http_ver = chunk:match("^([A-Z]+) ([^ ]+) HTTP/([01]%.[019])$")
-
-               -- Yup, it is
-               if method then
-
-                       msg.type           = "request"
-                       msg.request_method = method:lower()
-                       msg.request_uri    = uri
-                       msg.http_version   = tonumber( http_ver )
-                       msg.headers        = { }
-
-                       -- We're done, next state is header parsing
-                       return true, function( chunk )
-                               return process_states['headers']( msg, chunk )
-                       end
-
-               -- Is it a response?
-               else
-
-                       local http_ver, code, message = chunk:match("^HTTP/([01]%.[019]) ([0-9]+) ([^\r\n]+)$")
-
-                       -- Is a response
-                       if code then
-
-                               msg.type           = "response"
-                               msg.status_code    = code
-                               msg.status_message = message
-                               msg.http_version   = tonumber( http_ver )
-                               msg.headers        = { }
-
-                               -- We're done, next state is header parsing
-                               return true, function( chunk )
-                                       return process_states['headers']( msg, chunk )
-                               end
-                       end
-               end
-       end
-
-       -- Can't handle it
-       return nil, "Invalid HTTP message magic"
-end
-
-
--- Extract headers from given string.
-process_states['headers'] = function( msg, chunk )
-
-       if chunk ~= nil then
-
-               -- Look for a valid header format
-               local hdr, val = chunk:match( "^([A-Za-z][A-Za-z0-9%-_]+): +(.+)$" )
-
-               if type(hdr) == "string" and hdr:len() > 0 and
-                  type(val) == "string" and val:len() > 0
-               then
-                       msg.headers[hdr] = val
-
-                       -- Valid header line, proceed
-                       return true, nil
-
-               elseif #chunk == 0 then
-                       -- Empty line, we won't accept data anymore
-                       return false, nil
-               else
-                       -- Junk data
-                       return nil, "Invalid HTTP header received"
-               end
-       else
-               return nil, "Unexpected EOF"
-       end
-end
-
-
--- data line by line with the trailing \r\n stripped of.
-function header_source( sock )
-       return ltn12.source.simplify( function()
-
-               local chunk, err, part = sock:receive("*l")
-
-               -- Line too long
-               if chunk == nil then
-                       if err ~= "timeout" then
-                               return nil, part
-                                       and "Line exceeds maximum allowed length"
-                                       or  "Unexpected EOF"
-                       else
-                               return nil, err
-                       end
-
-               -- Line ok
-               elseif chunk ~= nil then
-
-                       -- Strip trailing CR
-                       chunk = chunk:gsub("\r$","")
-
-                       return chunk, nil
-               end
-       end )
-end
-
--- Content-Type. Stores all extracted data associated with its parameter name
--- in the params table within the given message object. Multiple parameter
--- values are stored as tables, ordinary ones as strings.
--- If an optional file callback function is given then it is feeded with the
--- file contents chunk by chunk and only the extracted file name is stored
--- within the params table. The callback function will be called subsequently
--- with three arguments:
---  o Table containing decoded (name, file) and raw (headers) mime header data
---  o String value containing a chunk of the file data
---  o Boolean which indicates wheather the current chunk is the last one (eof)
-function mimedecode_message_body( src, msg, filecb )
-
-       if msg and msg.env.CONTENT_TYPE then
-               msg.mime_boundary = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)$")
-       end
-
-       if not msg.mime_boundary then
-               return nil, "Invalid Content-Type found"
-       end
-
-
-       local tlen   = 0
-       local inhdr  = false
-       local field  = nil
-       local store  = nil
-       local lchunk = nil
-
-       local function parse_headers( chunk, field )
-
-               local stat
-               repeat
-                       chunk, stat = chunk:gsub(
-                               "^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n",
-                               function(k,v)
-                                       field.headers[k] = v
-                                       return ""
-                               end
-                       )
-               until stat == 0
-
-               chunk, stat = chunk:gsub("^\r\n","")
-
-               -- End of headers
-               if stat > 0 then
-                       if field.headers["Content-Disposition"] then
-                               if field.headers["Content-Disposition"]:match("^form%-data; ") then
-                                       field.name = field.headers["Content-Disposition"]:match('name="(.-)"')
-                                       field.file = field.headers["Content-Disposition"]:match('filename="(.+)"$')
-                               end
-                       end
-
-                       if not field.headers["Content-Type"] then
-                               field.headers["Content-Type"] = "text/plain"
-                       end
-
-                       if field.name and field.file and filecb then
-                               __initval( msg.params, field.name )
-                               __appendval( msg.params, field.name, field.file )
-
-                               store = filecb
-                       elseif field.name and field.file then
-                               local nxf = require "nixio"
-                               local fd = nxf.mkstemp(field.name)
-                               __initfileval ( msg.params, field.name, field.file, fd )
-                               if fd then
-                                       store = function(hdr, buf, eof)
-                                               fd:write(buf)
-                                               if (eof) then
-                                                       fd:seek(0, "set")
-                                               end
-                                       end
-                               else
-                                       store = function( hdr, buf, eof )
-                                               __appendval( msg.params, field.name, buf )
-                                       end
-                               end
-                       elseif field.name then
-                               __initval( msg.params, field.name )
-
-                               store = function( hdr, buf, eof )
-                                       __appendval( msg.params, field.name, buf )
-                               end
-                       else
-                               store = nil
-                       end
-
-                       return chunk, true
-               end
-
-               return chunk, false
-       end
-
-       local function snk( chunk )
-
-               tlen = tlen + ( chunk and #chunk or 0 )
-
-               if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then
-                       return nil, "Message body size exceeds Content-Length"
-               end
-
-               if chunk and not lchunk then
-                       lchunk = "\r\n" .. chunk
-
-               elseif lchunk then
-                       local data = lchunk .. ( chunk or "" )
-                       local spos, epos, found
-
-                       repeat
-                               spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "\r\n", 1, true )
-
-                               if not spos then
-                                       spos, epos = data:find( "\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true )
-                               end
-
-
-                               if spos then
-                                       local predata = data:sub( 1, spos - 1 )
-
-                                       if inhdr then
-                                               predata, eof = parse_headers( predata, field )
-
-                                               if not eof then
-                                                       return nil, "Invalid MIME section header"
-                                               elseif not field.name then
-                                                       return nil, "Invalid Content-Disposition header"
-                                               end
-                                       end
-
-                                       if store then
-                                               store( field, predata, true )
-                                       end
-
-
-                                       field = { headers = { } }
-                                       found = found or true
-
-                                       data, eof = parse_headers( data:sub( epos + 1, #data ), field )
-                                       inhdr = not eof
-                               end
-                       until not spos
-
-                       if found then
-                               -- We found at least some boundary. Save
-                               -- the unparsed remaining data for the
-                               -- next chunk.
-                               lchunk, data = data, nil
-                       else
-                               -- There was a complete chunk without a boundary. Parse it as headers or
-                               -- append it as data, depending on our current state.
-                               if inhdr then
-                                       lchunk, eof = parse_headers( data, field )
-                                       inhdr = not eof
-                               else
-                                       -- We're inside data, so append the data. Note that we only append
-                                       -- lchunk, not all of data, since there is a chance that chunk
-                                       -- contains half a boundary. Assuming that each chunk is at least the
-                                       -- boundary in size, this should prevent problems
-                                       store( field, lchunk, false )
-                                       lchunk, chunk = chunk, nil
-                               end
-                       end
-               end
-
-               return true
-       end
-
-       return ltn12.pump.all( src, snk )
-end
-
--- Content-Type. Stores all extracted data associated with its parameter name
--- in the params table within the given message object. Multiple parameter
--- values are stored as tables, ordinary ones as strings.
-function urldecode_message_body( src, msg )
-
-       local tlen   = 0
-       local lchunk = nil
-
-       local function snk( chunk )
-
-               tlen = tlen + ( chunk and #chunk or 0 )
-
-               if msg.env.CONTENT_LENGTH and tlen > tonumber(msg.env.CONTENT_LENGTH) + 2 then
-                       return nil, "Message body size exceeds Content-Length"
-               elseif tlen > HTTP_MAX_CONTENT then
-                       return nil, "Message body size exceeds maximum allowed length"
-               end
-
-               if not lchunk and chunk then
-                       lchunk = chunk
-
-               elseif lchunk then
-                       local data = lchunk .. ( chunk or "&" )
-                       local spos, epos
-
-                       repeat
-                               spos, epos = data:find("^.-[;&]")
-
-                               if spos then
-                                       local pair = data:sub( spos, epos - 1 )
-                                       local key  = pair:match("^(.-)=")
-                                       local val  = pair:match("=([^%s]*)%s*$")
-
-                                       if key and #key > 0 then
-                                               __initval( msg.params, key )
-                                               __appendval( msg.params, key, val )
-                                               __finishval( msg.params, key, urldecode )
-                                       end
-
-                                       data = data:sub( epos + 1, #data )
-                               end
-                       until not spos
-
-                       lchunk = data
-               end
-
-               return true
-       end
-
-       return ltn12.pump.all( src, snk )
-end
-
--- version, message headers and resulting CGI environment variables from the
--- given ltn12 source.
-function parse_message_header( src )
-
-       local ok   = true
-       local msg  = { }
-
-       local sink = ltn12.sink.simplify(
-               function( chunk )
-                       return process_states['magic']( msg, chunk )
-               end
-       )
-
-       -- Pump input data...
-       while ok do
-
-               -- get data
-               ok, err = ltn12.pump.step( src, sink )
-
-               -- error
-               if not ok and err then
-                       return nil, err
-
-               -- eof
-               elseif not ok then
-
-                       -- Process get parameters
-                       if ( msg.request_method == "get" or msg.request_method == "post" ) and
-                          msg.request_uri:match("?")
-                       then
-                               msg.params = urldecode_params( msg.request_uri )
-                       else
-                               msg.params = { }
-                       end
-
-                       -- Populate common environment variables
-                       msg.env = {
-                               CONTENT_LENGTH    = msg.headers['Content-Length'];
-                               CONTENT_TYPE      = msg.headers['Content-Type'] or msg.headers['Content-type'];
-                               REQUEST_METHOD    = msg.request_method:upper();
-                               REQUEST_URI       = msg.request_uri;
-                               SCRIPT_NAME       = msg.request_uri:gsub("?.+$","");
-                               SCRIPT_FILENAME   = "";         -- XXX implement me
-                               SERVER_PROTOCOL   = "HTTP/" .. string.format("%.1f", msg.http_version);
-                               QUERY_STRING      = msg.request_uri:match("?")
-                                       and msg.request_uri:gsub("^.+?","") or ""
-                       }
-
-                       -- Populate HTTP_* environment variables
-                       for i, hdr in ipairs( {
-                               'Accept',
-                               'Accept-Charset',
-                               'Accept-Encoding',
-                               'Accept-Language',
-                               'Connection',
-                               'Cookie',
-                               'Host',
-                               'Referer',
-                               'User-Agent',
-                       } ) do
-                               local var = 'HTTP_' .. hdr:upper():gsub("%-","_")
-                               local val = msg.headers[hdr]
-
-                               msg.env[var] = val
-                       end
-               end
-       end
-
-       return msg
-end
-
--- This function will examine the Content-Type within the given message object
--- to select the appropriate content decoder.
--- Currently the application/x-www-urlencoded and application/form-data
--- mime types are supported. If the encountered content encoding can't be
--- handled then the whole message body will be stored unaltered as "content"
--- property within the given message object.
-function parse_message_body( src, msg, filecb )
-       -- Is it multipart/mime ?
-       if msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
-          msg.env.CONTENT_TYPE:match("^multipart/form%-data")
-       then
-
-               return mimedecode_message_body( src, msg, filecb )
-
-       -- Is it application/x-www-form-urlencoded ?
-       elseif msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and
-              msg.env.CONTENT_TYPE:match("^application/x%-www%-form%-urlencoded")
-       then
-               return urldecode_message_body( src, msg, filecb )
-
-
-       -- Unhandled encoding
-       -- If a file callback is given then feed it chunk by chunk, else
-       -- store whole buffer in message.content
-       else
-
-               local sink
-
-               -- If we have a file callback then feed it
-               if type(filecb) == "function" then
-                       local meta = {
-                               name = "raw",
-                               encoding = msg.env.CONTENT_TYPE
-                       }
-                       sink = function( chunk )
-                               if chunk then
-                                       return filecb(meta, chunk, false)
-                               else
-                                       return filecb(meta, nil, true)
-                               end
-                       end
-               -- ... else append to .content
-               else
-                       msg.content = ""
-                       msg.content_length = 0
-
-                       sink = function( chunk )
-                               if chunk then
-                                       if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
-                                               msg.content        = msg.content        .. chunk
-                                               msg.content_length = msg.content_length + #chunk
-                                               return true
-                                       else
-                                               return nil, "POST data exceeds maximum allowed length"
-                                       end
-                               end
-                               return true
-                       end
-               end
-
-               -- Pump data...
-               while true do
-                       local ok, err = ltn12.pump.step( src, sink )
-
-                       if not ok and err then
-                               return nil, err
-                       elseif not ok then -- eof
-                               return true
-                       end
-               end
-
-               return true
-       end
-end
-
-statusmsg = {
-       [200] = "OK",
-       [206] = "Partial Content",
-       [301] = "Moved Permanently",
-       [302] = "Found",
-       [304] = "Not Modified",
-       [400] = "Bad Request",
-       [403] = "Forbidden",
-       [404] = "Not Found",
-       [405] = "Method Not Allowed",
-       [408] = "Request Time-out",
-       [411] = "Length Required",
-       [412] = "Precondition Failed",
-       [416] = "Requested range not satisfiable",
-       [500] = "Internal Server Error",
-       [503] = "Server Unavailable",
-}
diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc
deleted file mode 100644 (file)
index 19a0a34..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
----[[
-LuCI http protocol class.
-
-This class contains several functions useful for http message- and content
-decoding and to retrive form data from raw http messages.
-]]
-module "luci.http.protocol"
-
----[[
-Decode an urlencoded string - optionally without decoding
-
-the "+" sign to " " - and return the decoded string.
-@class function
-@name urldecode
-@param str             Input string in x-www-urlencoded format
-@param no_plus Don't decode "+" signs to spaces
-@return                        The decoded string
-@see                           urlencode
-]]
-
----[[
-Extract and split urlencoded data pairs, separated bei either "&" or ";"
-
-from given url or string. Returns a table with urldecoded values.
-Simple parameters are stored as string values associated with the parameter
-name within the table. Parameters with multiple values are stored as array
-containing the corresponding values.
-@class function
-@name urldecode_params
-@param url     The url or string which contains x-www-urlencoded form data
-@param tbl     Use the given table for storing values (optional)
-@return                Table containing the urldecoded parameters
-@see                   urlencode_params
-]]
-
----[[
-Encode given string to x-www-urlencoded format.
-
-@class function
-@name urlencode
-@param str     String to encode
-@return                String containing the encoded data
-@see                   urldecode
-]]
-
----[[
-Encode each key-value-pair in given table to x-www-urlencoded format,
-
-separated by "&". Tables are encoded as parameters with multiple values by
-repeating the parameter name with each value.
-@class function
-@name urlencode_params
-@param tbl     Table with the values
-@return                String containing encoded values
-@see                   urldecode_params
-]]
-
----[[
-Creates a ltn12 source from the given socket. The source will return it's
-
-data line by line with the trailing \r\n stripped of.
-@class function
-@name header_source
-@param sock    Readable network socket
-@return                Ltn12 source function
-]]
-
----[[
-Decode a mime encoded http message body with multipart/form-data
-
-Content-Type. Stores all extracted data associated with its parameter name
-in the params table within the given message object. Multiple parameter
-values are stored as tables, ordinary ones as strings.
-If an optional file callback function is given then it is feeded with the
-file contents chunk by chunk and only the extracted file name is stored
-within the params table. The callback function will be called subsequently
-with three arguments:
- o Table containing decoded (name, file) and raw (headers) mime header data
- o String value containing a chunk of the file data
- o Boolean which indicates wheather the current chunk is the last one (eof)
-@class function
-@name mimedecode_message_body
-@param src             Ltn12 source function
-@param msg             HTTP message object
-@param filecb  File callback function (optional)
-@return                        Value indicating successful operation (not nil means "ok")
-@return                        String containing the error if unsuccessful
-@see                           parse_message_header
-]]
-
----[[
-Decode an urlencoded http message body with application/x-www-urlencoded
-
-Content-Type. Stores all extracted data associated with its parameter name
-in the params table within the given message object. Multiple parameter
-values are stored as tables, ordinary ones as strings.
-@class function
-@name urldecode_message_body
-@param src     Ltn12 source function
-@param msg     HTTP message object
-@return                Value indicating successful operation (not nil means "ok")
-@return                String containing the error if unsuccessful
-@see                   parse_message_header
-]]
-
----[[
-Try to extract an http message header including information like protocol
-
-version, message headers and resulting CGI environment variables from the
-given ltn12 source.
-@class function
-@name parse_message_header
-@param src     Ltn12 source function
-@return                HTTP message object
-@see                   parse_message_body
-]]
-
----[[
-Try to extract and decode a http message body from the given ltn12 source.
-
-This function will examine the Content-Type within the given message object
-to select the appropriate content decoder.
-Currently the application/x-www-urlencoded and application/form-data
-mime types are supported. If the encountered content encoding can't be
-handled then the whole message body will be stored unaltered as "content"
-property within the given message object.
-@class function
-@name parse_message_body
-@param src             Ltn12 source function
-@param msg             HTTP message object
-@param filecb  File data callback (optional, see mimedecode_message_body())
-@return                        Value indicating successful operation (not nil means "ok")
-@return                        String containing the error if unsuccessful
-@see                           parse_message_header
-]]
-
----[[
-Table containing human readable messages for several http status codes.
-
-@class table
-]]
-
diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.lua b/modules/luci-base/luasrc/http/protocol/conditionals.lua
deleted file mode 100644 (file)
index d31a4e3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- This class provides basic ETag handling and implements most of the
--- conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
-module("luci.http.protocol.conditionals", package.seeall)
-
-local date = require("luci.http.protocol.date")
-
-
-function mk_etag( stat )
-       if stat ~= nil then
-               return string.format( '"%x-%x-%x"', stat.ino, stat.size, stat.mtime )
-       end
-end
-
--- Test whether the given message object contains an "If-Match" header and
--- compare it against the given stat object.
-function if_match( req, stat )
-       local h    = req.headers
-       local etag = mk_etag( stat )
-
-       -- Check for matching resource
-       if type(h['If-Match']) == "string" then
-               for ent in h['If-Match']:gmatch("([^, ]+)") do
-                       if ( ent == '*' or ent == etag ) and stat ~= nil then
-                               return true
-                       end
-               end
-
-               return false, 412
-       end
-
-       return true
-end
-
--- Test whether the given message object contains an "If-Modified-Since" header
--- and compare it against the given stat object.
-function if_modified_since( req, stat )
-       local h = req.headers
-
-       -- Compare mtimes
-       if type(h['If-Modified-Since']) == "string" then
-               local since = date.to_unix( h['If-Modified-Since'] )
-
-               if stat == nil or since < stat.mtime then
-                       return true
-               end
-
-               return false, 304, {
-                       ["ETag"]          = mk_etag( stat );
-                       ["Date"]          = date.to_http( os.time() );
-                       ["Last-Modified"] = date.to_http( stat.mtime )
-               }
-       end
-
-       return true
-end
-
--- Test whether the given message object contains an "If-None-Match" header and
--- compare it against the given stat object.
-function if_none_match( req, stat )
-       local h      = req.headers
-       local etag   = mk_etag( stat )
-       local method = req.env and req.env.REQUEST_METHOD or "GET"
-
-       -- Check for matching resource
-       if type(h['If-None-Match']) == "string" then
-               for ent in h['If-None-Match']:gmatch("([^, ]+)") do
-                       if ( ent == '*' or ent == etag ) and stat ~= nil then
-                               if method == "GET" or method == "HEAD" then
-                                       return false, 304, {
-                                               ["ETag"]          = etag;
-                                               ["Date"]          = date.to_http( os.time() );
-                                               ["Last-Modified"] = date.to_http( stat.mtime )
-                                       }
-                               else
-                                       return false, 412
-                               end
-                       end
-               end
-       end
-
-       return true
-end
-
--- The If-Range header is currently not implemented due to the lack of general
--- byte range stuff in luci.http.protocol . This function will always return
--- false, 412 to indicate a failed precondition.
-function if_range( req, stat )
-       -- Sorry, no subranges (yet)
-       return false, 412
-end
-
--- Test whether the given message object contains an "If-Unmodified-Since"
--- header and compare it against the given stat object.
-function if_unmodified_since( req, stat )
-       local h = req.headers
-
-       -- Compare mtimes
-       if type(h['If-Unmodified-Since']) == "string" then
-               local since = date.to_unix( h['If-Unmodified-Since'] )
-
-               if stat ~= nil and since <= stat.mtime then
-                       return false, 412
-               end
-       end
-
-       return true
-end
diff --git a/modules/luci-base/luasrc/http/protocol/conditionals.luadoc b/modules/luci-base/luasrc/http/protocol/conditionals.luadoc
deleted file mode 100644 (file)
index 9cfe02d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
----[[
-LuCI http protocol implementation - HTTP/1.1 bits.
-
-This class provides basic ETag handling and implements most of the
-conditional HTTP/1.1 headers specified in RFC2616 Sct. 14.24 - 14.28 .
-]]
-module "luci.http.protocol.conditionals"
-
----[[
-Implement 14.19 / ETag.
-
-@class function
-@name mk_etag
-@param stat    A file.stat structure
-@return                String containing the generated tag suitable for ETag headers
-]]
-
----[[
-14.24 / If-Match
-
-Test whether the given message object contains an "If-Match" header and
-compare it against the given stat object.
-@class function
-@name if_match
-@param req     HTTP request message object
-@param stat    A file.stat object
-@return                Boolean indicating whether the precondition is ok
-@return                Alternative status code if the precondition failed
-]]
-
----[[
-14.25 / If-Modified-Since
-
-Test whether the given message object contains an "If-Modified-Since" header
-and compare it against the given stat object.
-@class function
-@name if_modified_since
-@param req     HTTP request message object
-@param stat    A file.stat object
-@return                Boolean indicating whether the precondition is ok
-@return                Alternative status code if the precondition failed
-@return                Table containing extra HTTP headers if the precondition failed
-]]
-
----[[
-14.26 / If-None-Match
-
-Test whether the given message object contains an "If-None-Match" header and
-compare it against the given stat object.
-@class function
-@name if_none_match
-@param req     HTTP request message object
-@param stat    A file.stat object
-@return                Boolean indicating whether the precondition is ok
-@return                Alternative status code if the precondition failed
-@return                Table containing extra HTTP headers if the precondition failed
-]]
-
----[[
-14.27 / If-Range
-
-The If-Range header is currently not implemented due to the lack of general
-byte range stuff in luci.http.protocol . This function will always return
-false, 412 to indicate a failed precondition.
-@class function
-@name if_range
-@param req     HTTP request message object
-@param stat    A file.stat object
-@return                Boolean indicating whether the precondition is ok
-@return                Alternative status code if the precondition failed
-]]
-
----[[
-14.28 / If-Unmodified-Since
-
-Test whether the given message object contains an "If-Unmodified-Since"
-header and compare it against the given stat object.
-@class function
-@name if_unmodified_since
-@param req     HTTP request message object
-@param stat    A file.stat object
-@return                Boolean indicating whether the precondition is ok
-@return                Alternative status code if the precondition failed
-]]
-
diff --git a/modules/luci-base/luasrc/http/protocol/date.lua b/modules/luci-base/luasrc/http/protocol/date.lua
deleted file mode 100644 (file)
index e440219..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- This class contains functions to parse, compare and format http dates.
-module("luci.http.protocol.date", package.seeall)
-
-require("luci.sys.zoneinfo")
-
-
-MONTHS = {
-       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
-       "Sep", "Oct", "Nov", "Dec"
-}
-
-function tz_offset(tz)
-
-       if type(tz) == "string" then
-
-               -- check for a numeric identifier
-               local s, v = tz:match("([%+%-])([0-9]+)")
-               if s == '+' then s = 1 else s = -1 end
-               if v then v = tonumber(v) end
-
-               if s and v then
-                       return s * 60 * ( math.floor( v / 100 ) * 60 + ( v % 100 ) )
-
-               -- lookup symbolic tz
-               elseif luci.sys.zoneinfo.OFFSET[tz:lower()] then
-                       return luci.sys.zoneinfo.OFFSET[tz:lower()]
-               end
-
-       end
-
-       -- bad luck
-       return 0
-end
-
-function to_unix(date)
-
-       local wd, day, mon, yr, hr, min, sec, tz = date:match(
-               "([A-Z][a-z][a-z]), ([0-9]+) " ..
-               "([A-Z][a-z][a-z]) ([0-9]+) " ..
-               "([0-9]+):([0-9]+):([0-9]+) " ..
-               "([A-Z0-9%+%-]+)"
-       )
-
-       if day and mon and yr and hr and min and sec then
-               -- find month
-               local month = 1
-               for i = 1, 12 do
-                       if MONTHS[i] == mon then
-                               month = i
-                               break
-                       end
-               end
-
-               -- convert to epoch time
-               return tz_offset(tz) + os.time( {
-                       year  = yr,
-                       month = month,
-                       day   = day,
-                       hour  = hr,
-                       min   = min,
-                       sec   = sec
-               } )
-       end
-
-       return 0
-end
-
-function to_http(time)
-       return os.date( "%a, %d %b %Y %H:%M:%S GMT", time )
-end
-
-function compare(d1, d2)
-
-       if d1:match("[^0-9]") then d1 = to_unix(d1) end
-       if d2:match("[^0-9]") then d2 = to_unix(d2) end
-
-       if d1 == d2 then
-               return 0
-       elseif d1 < d2 then
-               return -1
-       else
-               return 1
-       end
-end
diff --git a/modules/luci-base/luasrc/http/protocol/date.luadoc b/modules/luci-base/luasrc/http/protocol/date.luadoc
deleted file mode 100644 (file)
index d6f1c8d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
----[[
-LuCI http protocol implementation - date helper class.
-
-This class contains functions to parse, compare and format http dates.
-]]
-module "luci.http.protocol.date"
-
----[[
-Return the time offset in seconds between the UTC and given time zone.
-
-@class function
-@name tz_offset
-@param tz      Symbolic or numeric timezone specifier
-@return                Time offset to UTC in seconds
-]]
-
----[[
-Parse given HTTP date string and convert it to unix epoch time.
-
-@class function
-@name to_unix
-@param data    String containing the date
-@return                Unix epoch time
-]]
-
----[[
-Convert the given unix epoch time to valid HTTP date string.
-
-@class function
-@name to_http
-@param time    Unix epoch time
-@return                String containing the formatted date
-]]
-
----[[
-Compare two dates which can either be unix epoch times or HTTP date strings.
-
-@class function
-@name compare
-@param d1      The first date or epoch time to compare
-@param d2      The first date or epoch time to compare
-@return                -1  -  if d1 is lower then d2
-@return                0   -  if both dates are equal
-@return                1   -  if d1 is higher then d2
-]]
-
diff --git a/modules/luci-base/luasrc/http/protocol/mime.lua b/modules/luci-base/luasrc/http/protocol/mime.lua
deleted file mode 100644 (file)
index 2b99d8e..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
--- Copyright 2008 Freifunk Leipzig / Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
--- This class provides functions to guess mime types from file extensions and
--- vice versa.
-module("luci.http.protocol.mime", package.seeall)
-
-require("luci.util")
-
-MIME_TYPES = {
-    ["txt"]   = "text/plain";
-    ["js"]    = "text/javascript";
-    ["css"]   = "text/css";
-    ["htm"]   = "text/html";
-    ["html"]  = "text/html";
-    ["patch"] = "text/x-patch";
-    ["c"]     = "text/x-csrc";
-    ["h"]     = "text/x-chdr";
-    ["o"]     = "text/x-object";
-    ["ko"]    = "text/x-object";
-
-    ["bmp"]   = "image/bmp";
-    ["gif"]   = "image/gif";
-    ["png"]   = "image/png";
-    ["jpg"]   = "image/jpeg";
-    ["jpeg"]  = "image/jpeg";
-    ["svg"]   = "image/svg+xml";
-
-    ["zip"]   = "application/zip";
-    ["pdf"]   = "application/pdf";
-    ["xml"]   = "application/xml";
-    ["xsl"]   = "application/xml";
-    ["doc"]   = "application/msword";
-    ["ppt"]   = "application/vnd.ms-powerpoint";
-    ["xls"]   = "application/vnd.ms-excel";
-    ["odt"]   = "application/vnd.oasis.opendocument.text";
-    ["odp"]   = "application/vnd.oasis.opendocument.presentation";
-    ["pl"]    = "application/x-perl";
-    ["sh"]    = "application/x-shellscript";
-    ["php"]   = "application/x-php";
-    ["deb"]   = "application/x-deb";
-    ["iso"]   = "application/x-cd-image";
-    ["tgz"]   = "application/x-compressed-tar";
-
-    ["mp3"]   = "audio/mpeg";
-    ["ogg"]   = "audio/x-vorbis+ogg";
-    ["wav"]   = "audio/x-wav";
-
-    ["mpg"]   = "video/mpeg";
-    ["mpeg"]  = "video/mpeg";
-    ["avi"]   = "video/x-msvideo";
-}
-
--- "application/octet-stream" if the extension is unknown.
-function to_mime(filename)
-       if type(filename) == "string" then
-               local ext = filename:match("[^%.]+$")
-
-               if ext and MIME_TYPES[ext:lower()] then
-                       return MIME_TYPES[ext:lower()]
-               end
-       end
-
-       return "application/octet-stream"
-end
-
--- given mime-type is unknown.
-function to_ext(mimetype)
-       if type(mimetype) == "string" then
-               for ext, type in luci.util.kspairs( MIME_TYPES ) do
-                       if type == mimetype then
-                               return ext
-                       end
-               end
-       end
-
-       return nil
-end
diff --git a/modules/luci-base/luasrc/http/protocol/mime.luadoc b/modules/luci-base/luasrc/http/protocol/mime.luadoc
deleted file mode 100644 (file)
index 195b5fc..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
----[[
-LuCI http protocol implementation - mime helper class.
-
-This class provides functions to guess mime types from file extensions and
-vice versa.
-]]
-module "luci.http.protocol.mime"
-
----[[
-MIME mapping table containg extension - mimetype relations.
-
-@class table
-]]
-
----[[
-Extract extension from a filename and return corresponding mime-type or
-
-"application/octet-stream" if the extension is unknown.
-@class function
-@name to_mime
-@param filename        The filename for which the mime type is guessed
-@return                        String containign the determined mime type
-]]
-
----[[
-Return corresponding extension for a given mime type or nil if the
-
-given mime-type is unknown.
-@class function
-@name to_ext
-@param mimetype        The mimetype to retrieve the extension from
-@return                        String with the extension or nil for unknown type
-]]
-
index e653b03..e27ea52 100644 (file)
@@ -20,12 +20,14 @@ module "luci.model.ipkg"
 
 -- Internal action function
 local function _action(cmd, ...)
-       local pkg = ""
+       local cmdline = { ipkg, cmd }
+
+       local k, v
        for k, v in pairs({...}) do
-               pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
+               cmdline[#cmdline+1] = util.shellquote(v)
        end
 
-       local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
+       local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
        local r = os.execute(c)
        local e = fs.readfile("/tmp/opkg.stderr")
        local o = fs.readfile("/tmp/opkg.stdout")
@@ -74,17 +76,17 @@ local function _parselist(rawdata)
 end
 
 -- Internal lookup function
-local function _lookup(act, pkg)
-       local cmd = ipkg .. " " .. act
+local function _lookup(cmd, pkg)
+       local cmdline = { ipkg, cmd }
        if pkg then
-               cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
+               cmdline[#cmdline+1] = util.shellquote(pkg)
        end
 
        -- OPKG sometimes kills the whole machine because it sucks
        -- Therefore we have to use a sucky approach too and use
        -- tmpfiles instead of directly reading the output
        local tmpfile = os.tmpname()
-       os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile))
+       os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
 
        local data = _parselist(io.lines(tmpfile))
        os.remove(tmpfile)
@@ -123,9 +125,12 @@ end
 
 -- List helper
 local function _list(action, pat, cb)
-       local fd = io.popen(ipkg .. " " .. action ..
-               (pat and (" '%s'" % pat:gsub("'", "")) or ""))
+       local cmdline = { ipkg, action }
+       if pat then
+               cmdline[#cmdline+1] = util.shellquote(pat)
+       end
 
+       local fd = io.popen(table.concat(cmdline, " "))
        if fd then
                local name, version, sz, desc
                while true do
index 056fc67..dfe818b 100644 (file)
@@ -629,7 +629,7 @@ function get_interface(self, i)
        if _interfaces[i] or _wifi_iface(i) then
                return interface(i)
        else
-               local netid = _wifi_netid_by_netname(i)
+               local netid = _wifi_netid_by_sid(i)
                return netid and interface(netid)
        end
 end
index 577c6cd..fc2a605 100644 (file)
@@ -2,13 +2,12 @@
 -- Licensed to the public under the Apache License 2.0.
 
 local os    = require "os"
-local uci   = require "uci"
 local util  = require "luci.util"
 local table = require "table"
 
 
 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
-local require, getmetatable = require, getmetatable
+local require, getmetatable, assert = require, getmetatable, assert
 local error, pairs, ipairs = error, pairs, ipairs
 local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
 
@@ -20,151 +19,436 @@ local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
 -- reloaded.
 module "luci.model.uci"
 
-cursor = uci.cursor
+local ERRSTR = {
+       "Invalid command",
+       "Invalid argument",
+       "Method not found",
+       "Entry not found",
+       "No data",
+       "Permission denied",
+       "Timeout",
+       "Not supported",
+       "Unknown error",
+       "Connection failed"
+}
+
+local session_id = nil
+
+local function call(cmd, args)
+       if type(args) == "table" and session_id then
+               args.ubus_rpc_session = session_id
+       end
+       return util.ubus("uci", cmd, args)
+end
 
-APIVERSION = uci.APIVERSION
+
+function cursor()
+       return _M
+end
 
 function cursor_state()
-       return cursor(nil, "/var/state")
+       return _M
 end
 
+function substate(self)
+       return self
+end
 
-inst = cursor()
-inst_state = cursor_state()
 
-local Cursor = getmetatable(inst)
+function get_confdir(self)
+       return "/etc/config"
+end
 
-function Cursor.apply(self, configlist, command)
-       configlist = self:_affected(configlist)
-       if command then
-               return { "/sbin/luci-reload", unpack(configlist) }
-       else
-               return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
-                       % table.concat(configlist, " "))
-       end
+function get_savedir(self)
+       return "/tmp/.uci"
 end
 
+function get_session_id(self)
+       return session_id
+end
 
--- returns a boolean whether to delete the current section (optional)
-function Cursor.delete_all(self, config, stype, comparator)
-       local del = {}
+function set_confdir(self, directory)
+       return false
+end
 
-       if type(comparator) == "table" then
-               local tbl = comparator
-               comparator = function(section)
-                       for k, v in pairs(tbl) do
-                               if section[k] ~= v then
-                                       return false
+function set_savedir(self, directory)
+       return false
+end
+
+function set_session_id(self, id)
+       session_id = id
+       return true
+end
+
+
+function load(self, config)
+       return true
+end
+
+function save(self, config)
+       return true
+end
+
+function unload(self, config)
+       return true
+end
+
+
+function changes(self, config)
+       local rv = call("changes", { config = config })
+       local res = {}
+
+       if type(rv) == "table" and type(rv.changes) == "table" then
+               local package, changes
+               for package, changes in pairs(rv.changes) do
+                       res[package] = {}
+
+                       local _, change
+                       for _, change in ipairs(changes) do
+                               local operation, section, option, value = unpack(change)
+                               if option and value and operation ~= "add" then
+                                       res[package][section] = res[package][section] or { }
+
+                                       if operation == "list-add" then
+                                               local v = res[package][section][option]
+                                               if type(v) == "table" then
+                                                       v[#v+1] = value or ""
+                                               elseif v ~= nil then
+                                                       res[package][section][option] = { v, value }
+                                               else
+                                                       res[package][section][option] = { value }
+                                               end
+                                       else
+                                               res[package][section][option] = value or ""
+                                       end
+                               else
+                                       res[package][section] = res[package][section] or {}
+                                       res[package][section][".type"] = option or ""
                                end
                        end
-                       return true
                end
        end
 
-       local function helper (section)
+       return res
+end
+
+
+function revert(self, config)
+       local _, err = call("revert", { config = config })
+       return (err == nil), ERRSTR[err]
+end
+
+function commit(self, config)
+       local _, err = call("commit", { config = config })
+       return (err == nil), ERRSTR[err]
+end
+
+--[[
+function apply(self, configs, command)
+       local _, config
+
+       assert(not command, "Apply command not supported anymore")
 
-               if not comparator or comparator(section) then
-                       del[#del+1] = section[".name"]
+       if type(configs) == "table" then
+               for _, config in ipairs(configs) do
+                       call("service", "event", {
+                               type = "config.change",
+                               data = { package = config }
+                       })
                end
        end
+end
+]]
+
+
+function foreach(self, config, stype, callback)
+       if type(callback) == "function" then
+               local rv, err = call("get", {
+                       config = config,
+                       type   = stype
+               })
+
+               if type(rv) == "table" and type(rv.values) == "table" then
+                       local sections = { }
+                       local res = false
+                       local index = 1
+
+                       local _, section
+                       for _, section in pairs(rv.values) do
+                               section[".index"] = section[".index"] or index
+                               sections[index] = section
+                               index = index + 1
+                       end
 
-       self:foreach(config, stype, helper)
+                       table.sort(sections, function(a, b)
+                               return a[".index"] < b[".index"]
+                       end)
 
-       for i, j in ipairs(del) do
-               self:delete(config, j)
+                       for _, section in ipairs(sections) do
+                               local continue = callback(section)
+                               res = true
+                               if continue == false then
+                                       break
+                               end
+                       end
+                       return res
+               else
+                       return false, ERRSTR[err] or "No data"
+               end
+       else
+               return false, "Invalid argument"
        end
 end
 
-function Cursor.section(self, config, type, name, values)
-       local stat = true
-       if name then
-               stat = self:set(config, name, type)
+local function _get(self, operation, config, section, option)
+       if section == nil then
+               return nil
+       elseif type(option) == "string" and option:byte(1) ~= 46 then
+               local rv, err = call(operation, {
+                       config  = config,
+                       section = section,
+                       option  = option
+               })
+
+               if type(rv) == "table" then
+                       return rv.value or nil
+               elseif err then
+                       return false, ERRSTR[err]
+               else
+                       return nil
+               end
+       elseif option == nil then
+               local values = self:get_all(config, section)
+               if values then
+                       return values[".type"], values[".name"]
+               else
+                       return nil
+               end
        else
-               name = self:add(config, type)
-               stat = name and true
+               return false, "Invalid argument"
        end
+end
 
-       if stat and values then
-               stat = self:tset(config, name, values)
-       end
+function get(self, ...)
+       return _get(self, "get", ...)
+end
 
-       return stat and name
+function get_state(self, ...)
+       return _get(self, "state", ...)
 end
 
-function Cursor.tset(self, config, section, values)
-       local stat = true
-       for k, v in pairs(values) do
-               if k:sub(1, 1) ~= "." then
-                       stat = stat and self:set(config, section, k, v)
-               end
+function get_all(self, config, section)
+       local rv, err = call("get", {
+               config  = config,
+               section = section
+       })
+
+       if type(rv) == "table" and type(rv.values) == "table" then
+               return rv.values
+       elseif err then
+               return false, ERRSTR[err]
+       else
+               return nil
        end
-       return stat
 end
 
-function Cursor.get_bool(self, ...)
+function get_bool(self, ...)
        local val = self:get(...)
-       return ( val == "1" or val == "true" or val == "yes" or val == "on" )
+       return (val == "1" or val == "true" or val == "yes" or val == "on")
+end
+
+function get_first(self, config, stype, option, default)
+       local rv = default
+
+       self:foreach(config, stype, function(s)
+               local val = not option and s[".name"] or s[option]
+
+               if type(default) == "number" then
+                       val = tonumber(val)
+               elseif type(default) == "boolean" then
+                       val = (val == "1" or val == "true" or
+                              val == "yes" or val == "on")
+               end
+
+               if val ~= nil then
+                       rv = val
+                       return false
+               end
+       end)
+
+       return rv
 end
 
-function Cursor.get_list(self, config, section, option)
+function get_list(self, config, section, option)
        if config and section and option then
                local val = self:get(config, section, option)
-               return ( type(val) == "table" and val or { val } )
+               return (type(val) == "table" and val or { val })
        end
-       return {}
+       return { }
 end
 
-function Cursor.get_first(self, conf, stype, opt, def)
-       local rv = def
 
-       self:foreach(conf, stype,
-               function(s)
-                       local val = not opt and s['.name'] or s[opt]
+function section(self, config, stype, name, values)
+       local rv, err = call("add", {
+               config = config,
+               type   = stype,
+               name   = name,
+               values = values
+       })
+
+       if type(rv) == "table" then
+               return rv.section
+       elseif err then
+               return false, ERRSTR[err]
+       else
+               return nil
+       end
+end
 
-                       if type(def) == "number" then
-                               val = tonumber(val)
-                       elseif type(def) == "boolean" then
-                               val = (val == "1" or val == "true" or
-                                      val == "yes" or val == "on")
+
+function add(self, config, stype)
+       return self:section(config, stype)
+end
+
+function set(self, config, section, option, value)
+       if value == nil then
+               local sname, err = self:section(config, option, section)
+               return (not not sname), err
+       else
+               local _, err = call("set", {
+                       config  = config,
+                       section = section,
+                       values  = { [option] = value }
+               })
+               return (err == nil), ERRSTR[err]
+       end
+end
+
+function set_list(self, config, section, option, value)
+       if section == nil or option == nil then
+               return false
+       elseif value == nil or (type(value) == "table" and #value == 0) then
+               return self:delete(config, section, option)
+       elseif type(value) == "table" then
+               return self:set(config, section, option, value)
+       else
+               return self:set(config, section, option, { value })
+       end
+end
+
+function tset(self, config, section, values)
+       local _, err = call("set", {
+               config  = config,
+               section = section,
+               values  = values
+       })
+       return (err == nil), ERRSTR[err]
+end
+
+function reorder(self, config, section, index)
+       local sections
+
+       if type(section) == "string" and type(index) == "number" then
+               local pos = 0
+
+               sections = { }
+
+               self:foreach(config, nil, function(s)
+                       if pos == index then
+                               pos = pos + 1
                        end
 
-                       if val ~= nil then
-                               rv = val
-                               return false
+                       if s[".name"] ~= section then
+                               pos = pos + 1
+                               sections[pos] = s[".name"]
+                       else
+                               sections[index + 1] = section
                        end
                end)
+       elseif type(section) == "table" then
+               sections = section
+       else
+               return false, "Invalid argument"
+       end
 
-       return rv
+       local _, err = call("order", {
+               config   = config,
+               sections = sections
+       })
+
+       return (err == nil), ERRSTR[err]
 end
 
-function Cursor.set_list(self, config, section, option, value)
-       if config and section and option then
-               if not value or #value == 0 then
-                       return self:delete(config, section, option)
+
+function delete(self, config, section, option)
+       local _, err = call("delete", {
+               config  = config,
+               section = section,
+               option  = option
+       })
+       return (err == nil), ERRSTR[err]
+end
+
+function delete_all(self, config, stype, comparator)
+       local _, err
+       if type(comparator) == "table" then
+               _, err = call("delete", {
+                       config = config,
+                       type   = stype,
+                       match  = comparator
+               })
+       elseif type(comparator) == "function" then
+               local rv = call("get", {
+                       config = config,
+                       type   = stype
+               })
+
+               if type(rv) == "table" and type(rv.values) == "table" then
+                       local sname, section
+                       for sname, section in pairs(rv.values) do
+                               if comparator(section) then
+                                       _, err = call("delete", {
+                                               config  = config,
+                                               section = sname
+                                       })
+                               end
+                       end
                end
-               return self:set(
-                       config, section, option,
-                       ( type(value) == "table" and value or { value } )
-               )
+       elseif comparator == nil then
+               _, err = call("delete", {
+                       config  = config,
+                       type    = stype
+               })
+       else
+               return false, "Invalid argument"
        end
-       return false
+
+       return (err == nil), ERRSTR[err]
 end
 
--- Return a list of initscripts affected by configuration changes.
-function Cursor._affected(self, configlist)
-       configlist = type(configlist) == "table" and configlist or {configlist}
 
-       local c = cursor()
-       c:load("ucitrack")
+function apply(self, configlist, command)
+       configlist = self:_affected(configlist)
+       if command then
+               return { "/sbin/luci-reload", unpack(configlist) }
+       else
+               return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
+                       % util.shellquote(table.concat(configlist, " ")))
+       end
+end
+
+-- Return a list of initscripts affected by configuration changes.
+function _affected(self, configlist)
+       configlist = type(configlist) == "table" and configlist or { configlist }
 
        -- Resolve dependencies
-       local reloadlist = {}
+       local reloadlist = { }
 
        local function _resolve_deps(name)
-               local reload = {name}
-               local deps = {}
+               local reload = { name }
+               local deps = { }
 
-               c:foreach("ucitrack", name,
+               self:foreach("ucitrack", name,
                        function(section)
                                if section.affects then
                                        for i, aff in ipairs(section.affects) do
@@ -173,7 +457,9 @@ function Cursor._affected(self, configlist)
                                end
                        end)
 
+               local i, dep
                for i, dep in ipairs(deps) do
+                       local j, add
                        for j, add in ipairs(_resolve_deps(dep)) do
                                reload[#reload+1] = add
                        end
@@ -183,7 +469,9 @@ function Cursor._affected(self, configlist)
        end
 
        -- Collect initscripts
+       local j, config
        for j, config in ipairs(configlist) do
+               local i, e
                for i, e in ipairs(_resolve_deps(config)) do
                        if not util.contains(reloadlist, e) then
                                reloadlist[#reloadlist+1] = e
@@ -193,44 +481,3 @@ function Cursor._affected(self, configlist)
 
        return reloadlist
 end
-
--- curser, means it the parent unloads or loads configs, the sub state will
--- do so as well.
-function Cursor.substate(self)
-       Cursor._substates = Cursor._substates or { }
-       Cursor._substates[self] = Cursor._substates[self] or cursor_state()
-       return Cursor._substates[self]
-end
-
-local _load = Cursor.load
-function Cursor.load(self, ...)
-       if Cursor._substates and Cursor._substates[self] then
-               _load(Cursor._substates[self], ...)
-       end
-       return _load(self, ...)
-end
-
-local _unload = Cursor.unload
-function Cursor.unload(self, ...)
-       if Cursor._substates and Cursor._substates[self] then
-               _unload(Cursor._substates[self], ...)
-       end
-       return _unload(self, ...)
-end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
index 49093c7..ef89d09 100644 (file)
@@ -14,224 +14,226 @@ module "luci.model.uci"
 ---[[
 Create a new UCI-Cursor.
 
-@class function
-@name cursor
-@return        UCI-Cursor
+@class                         function
+@name                          cursor
+@return                                UCI-Cursor
 ]]
 
 ---[[
 Create a new Cursor initialized to the state directory.
 
-@class function
-@name cursor_state
-@return UCI cursor
+@class                         function
+@name                          cursor_state
+@return                                UCI cursor
 ]]
 
 ---[[
 Applies UCI configuration changes
 
-@class function
-@name Cursor.apply
-@param configlist              List of UCI configurations
-@param command                 Don't apply only return the command
+@class                         function
+@name                          Cursor.apply
+@param configlist      List of UCI configurations
+@param command         Don't apply only return the command
 ]]
 
 ---[[
 Delete all sections of a given type that match certain criteria.
 
-@class function
-@name Cursor.delete_all
+@class                         function
+@name                          Cursor.delete_all
 @param config          UCI config
 @param type                    UCI section type
-@param comparator      Function that will be called for each section and
-returns a boolean whether to delete the current section (optional)
+@param comparator      Function that will be called for each section and returns
+                                       a boolean whether to delete the current section (optional)
 ]]
 
 ---[[
 Create a new section and initialize it with data.
 
-@class function
-@name Cursor.section
-@param config  UCI config
-@param type            UCI section type
-@param name            UCI section name (optional)
-@param values  Table of key - value pairs to initialize the section with
-@return                        Name of created section
+@class                         function
+@name                          Cursor.section
+@param config          UCI config
+@param type                    UCI section type
+@param name                    UCI section name (optional)
+@param values          Table of key - value pairs to initialize the section with
+@return                                Name of created section
 ]]
 
 ---[[
 Updated the data of a section using data from a table.
 
-@class function
-@name Cursor.tset
-@param config  UCI config
-@param section UCI section name (optional)
-@param values  Table of key - value pairs to update the section with
+@class                         function
+@name                          Cursor.tset
+@param config          UCI config
+@param section         UCI section name (optional)
+@param values          Table of key - value pairs to update the section with
 ]]
 
 ---[[
 Get a boolean option and return it's value as true or false.
 
-@class function
-@name Cursor.get_bool
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option
-@return                        Boolean
+@class                         function
+@name                          Cursor.get_bool
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option
+@return                                Boolean
 ]]
 
 ---[[
 Get an option or list and return values as table.
 
-@class function
-@name Cursor.get_list
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option
-@return                table.  If the option was not found, you will simply get
---             an empty table.
+@class                         function
+@name                          Cursor.get_list
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option
+@return table.         If the option was not found, you will simply get an empty
+                                       table.
 ]]
 
 ---[[
 Get the given option from the first section with the given type.
 
-@class function
-@name Cursor.get_first
-@param config  UCI config
-@param type            UCI section type
-@param option  UCI option (optional)
-@param default Default value (optional)
-@return                        UCI value
+@class                         function
+@name                          Cursor.get_first
+@param config          UCI config
+@param type                    UCI section type
+@param option          UCI option (optional)
+@param default         Default value (optional)
+@return                                UCI value
 ]]
 
 ---[[
 Set given values as list. Setting a list option to an empty list
 has the same effect as deleting the option.
 
-@class function
-@name Cursor.set_list
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option
-@param value   value or table. Raw values will become a single item table.
-@return                        Boolean whether operation succeeded
+@class                         function
+@name                          Cursor.set_list
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option
+@param value           Value or table. Non-table values will be set as single
+                                       item UCI list.
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
-Create a sub-state of this cursor. The sub-state is tied to the parent
+Create a sub-state of this cursor.
 
-curser, means it the parent unloads or loads configs, the sub state will
-do so as well.
-@class function
-@name Cursor.substate
-@return                        UCI state cursor tied to the parent cursor
+The sub-state is tied to the parent curser, means it the parent unloads or
+loads configs, the sub state will do so as well.
+
+@class                         function
+@name                          Cursor.substate
+@return                                UCI state cursor tied to the parent cursor
 ]]
 
 ---[[
 Add an anonymous section.
 
-@class function
-@name Cursor.add
-@param config  UCI config
-@param type            UCI section type
-@return                        Name of created section
+@class                         function
+@name                          Cursor.add
+@param config          UCI config
+@param type                    UCI section type
+@return                                Name of created section
 ]]
 
 ---[[
 Get a table of saved but uncommitted changes.
 
-@class function
-@name Cursor.changes
-@param config  UCI config
-@return                        Table of changes
-@see Cursor.save
+@class                         function
+@name                          Cursor.changes
+@param config          UCI config
+@return                                Table of changes
+@see                           Cursor.save
 ]]
 
 ---[[
 Commit saved changes.
 
-@class function
-@name Cursor.commit
-@param config  UCI config
-@return                        Boolean whether operation succeeded
-@see Cursor.revert
-@see Cursor.save
+@class                         function
+@name                          Cursor.commit
+@param config          UCI config
+@return                                Boolean whether operation succeeded
+@see                           Cursor.revert
+@see                           Cursor.save
 ]]
 
 ---[[
 Deletes a section or an option.
 
-@class function
-@name Cursor.delete
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option (optional)
-@return                        Boolean whether operation succeeded
+@class                         function
+@name                          Cursor.delete
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option (optional)
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
 Call a function for every section of a certain type.
 
-@class function
-@name Cursor.foreach
-@param config  UCI config
-@param type            UCI section type
-@param callback        Function to be called
-@return                        Boolean whether operation succeeded
+@class                         function
+@name                          Cursor.foreach
+@param config          UCI config
+@param type                    UCI section type
+@param callback                Function to be called
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
 Get a section type or an option
 
-@class function
-@name Cursor.get
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option (optional)
-@return                        UCI value
+@class                         function
+@name                          Cursor.get
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option (optional)
+@return                                UCI value
 ]]
 
 ---[[
 Get all sections of a config or all values of a section.
 
-@class function
-@name Cursor.get_all
-@param config  UCI config
-@param section UCI section name (optional)
-@return                        Table of UCI sections or table of UCI values
+@class                         function
+@name                          Cursor.get_all
+@param config          UCI config
+@param section         UCI section name (optional)
+@return                                Table of UCI sections or table of UCI values
 ]]
 
 ---[[
 Manually load a config.
 
-@class function
-@name Cursor.load
-@param config  UCI config
-@return                        Boolean whether operation succeeded
-@see Cursor.save
-@see Cursor.unload
+@class                         function
+@name                          Cursor.load
+@param config          UCI config
+@return                                Boolean whether operation succeeded
+@see                           Cursor.save
+@see                           Cursor.unload
 ]]
 
 ---[[
 Revert saved but uncommitted changes.
 
-@class function
-@name Cursor.revert
-@param config  UCI config
-@return                        Boolean whether operation succeeded
-@see Cursor.commit
-@see Cursor.save
+@class                         function
+@name                          Cursor.revert
+@param config          UCI config
+@return                                Boolean whether operation succeeded
+@see                           Cursor.commit
+@see                           Cursor.save
 ]]
 
 ---[[
 Saves changes made to a config to make them committable.
 
-@class function
-@name Cursor.save
-@param config  UCI config
-@return                        Boolean whether operation succeeded
-@see Cursor.load
-@see Cursor.unload
+@class                         function
+@name                          Cursor.save
+@param config          UCI config
+@return                                Boolean whether operation succeeded
+@see                           Cursor.load
+@see                           Cursor.unload
 ]]
 
 ---[[
@@ -243,57 +245,74 @@ then a named section of the given type is created.
 When invoked with four arguments `config`, `sectionname`, `optionname` and
 `optionvalue` then the value of the specified option is set to the given value.
 
-@class function
-@name Cursor.set
-@param config  UCI config
-@param section UCI section name
-@param option  UCI option or UCI section type
+@class                         function
+@name                          Cursor.set
+@param config          UCI config
+@param section         UCI section name
+@param option          UCI option or UCI section type
 @param value           UCI value or nothing if you want to create a section
-@return                        Boolean whether operation succeeded
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
 Get the configuration directory.
 
-@class function
-@name Cursor.get_confdir
-@return                        Configuration directory
+@class                         function
+@name                          Cursor.get_confdir
+@return                                Configuration directory
 ]]
 
 ---[[
 Get the directory for uncomitted changes.
 
-@class function
-@name Cursor.get_savedir
-@return                        Save directory
+@class                         function
+@name                          Cursor.get_savedir
+@return                                Save directory
+]]
+
+---[[
+Get the effective session ID.
+
+@class                         function
+@name                          Cursor.get_session_id
+@return                                String containing the session ID
 ]]
 
 ---[[
 Set the configuration directory.
 
-@class function
-@name Cursor.set_confdir
+@class                         function
+@name                          Cursor.set_confdir
 @param directory       UCI configuration directory
-@return                        Boolean whether operation succeeded
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
 Set the directory for uncommited changes.
 
-@class function
-@name Cursor.set_savedir
+@class                         function
+@name                          Cursor.set_savedir
 @param directory       UCI changes directory
-@return                        Boolean whether operation succeeded
+@return                                Boolean whether operation succeeded
+]]
+
+---[[
+Set the effective session ID.
+
+@class                         function
+@name                          Cursor.set_session_id
+@param id                      String containing the session ID to set
+@return                                Boolean whether operation succeeded
 ]]
 
 ---[[
 Discard changes made to a config.
 
-@class function
-@name Cursor.unload
-@param config  UCI config
-@return                        Boolean whether operation succeeded
-@see Cursor.load
-@see Cursor.save
+@class                         function
+@name                          Cursor.unload
+@param config          UCI config
+@return                                Boolean whether operation succeeded
+@see                           Cursor.load
+@see                           Cursor.save
 ]]
 
index 12b20e4..823e207 100644 (file)
@@ -87,10 +87,10 @@ end
 function httpget(url, stream, target)
        if not target then
                local source = stream and io.popen or luci.util.exec
-               return source("wget -qO- '"..url:gsub("'", "").."'")
+               return source("wget -qO- %s" % luci.util.shellquote(url))
        else
-               return os.execute("wget -qO '%s' '%s'" %
-                       {target:gsub("'", ""), url:gsub("'", "")})
+               return os.execute("wget -qO %s %s" %
+                       {luci.util.shellquote(target), luci.util.shellquote(url)})
        end
 end
 
@@ -443,18 +443,11 @@ function user.checkpasswd(username, pass)
 end
 
 function user.setpasswd(username, password)
-       if password then
-               password = password:gsub("'", [['"'"']])
-       end
-
-       if username then
-               username = username:gsub("'", [['"'"']])
-       end
-
-       return os.execute(
-               "(echo '" .. password .. "'; sleep 1; echo '" .. password .. "') | " ..
-               "passwd '" .. username .. "' >/dev/null 2>&1"
-       )
+       return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{
+               luci.util.shellquote(password),
+               luci.util.shellquote(password),
+               luci.util.shellquote(username)
+       })
 end
 
 
index 6668dad..47cb901 100644 (file)
@@ -202,7 +202,7 @@ TZ = {
        { 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' },
        { 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' },
        { 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' },
-       { 'Antarctica/Casey', '<+11>-11' },
+       { 'Antarctica/Casey', '<+08>-8' },
        { 'Antarctica/Davis', '<+07>-7' },
        { 'Antarctica/DumontDUrville', '<+10>-10' },
        { 'Antarctica/Macquarie', '<+11>-11' },
@@ -239,8 +239,8 @@ TZ = {
        { 'Asia/Dubai', '<+04>-4' },
        { 'Asia/Dushanbe', '<+05>-5' },
        { 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
-       { 'Asia/Gaza', 'EET-2EEST,M3.5.6/1,M10.5.6/1' },
-       { 'Asia/Hebron', 'EET-2EEST,M3.5.6/1,M10.5.6/1' },
+       { 'Asia/Gaza', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
+       { 'Asia/Hebron', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
        { 'Asia/Ho Chi Minh', '<+07>-7' },
        { 'Asia/Hong Kong', 'HKT-8' },
        { 'Asia/Hovd', '<+07>-7' },
index 5012111..06a9ad4 100644 (file)
@@ -187,7 +187,9 @@ function switch_status(devs)
        local switches = { }
        for dev in devs:gmatch("[^%s,]+") do
                local ports = { }
-               local swc = io.popen("swconfig dev %q show" % dev, "r")
+               local swc = io.popen("swconfig dev %s show"
+                       % luci.util.shellquote(dev), "r")
+
                if swc then
                        local l
                        repeat
index 0e7334b..ce42af2 100644 (file)
@@ -10,6 +10,7 @@ local string = require "string"
 local coroutine = require "coroutine"
 local tparser = require "luci.template.parser"
 local json = require "luci.jsonc"
+local lhttp = require "lucihttp"
 
 local _ubus = require "ubus"
 local _ubus_connection = nil
@@ -160,10 +161,33 @@ function pcdata(value)
        return value and tparser.pcdata(tostring(value))
 end
 
+function urlencode(value)
+       if value ~= nil then
+               local str = tostring(value)
+               return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL)
+                       or str
+       end
+       return nil
+end
+
+function urldecode(value, decode_plus)
+       if value ~= nil then
+               local flag = decode_plus and lhttp.DECODE_PLUS or 0
+               local str = tostring(value)
+               return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag)
+                       or str
+       end
+       return nil
+end
+
 function striptags(value)
        return value and tparser.striptags(tostring(value))
 end
 
+function shellquote(value)
+       return string.format("'%s'", string.gsub(value or "", "'", "'\\''"))
+end
+
 -- for bash, ash and similar shells single-quoted strings are taken
 -- literally except for single quotes (which terminate the string)
 -- (and the exception noted below for dash (-) at the start of a
@@ -383,16 +407,6 @@ function clone(object, deep)
 end
 
 
-function dtable()
-        return setmetatable({}, { __index =
-                function(tbl, key)
-                        return rawget(tbl, key)
-                         or rawget(rawset(tbl, key, dtable()), key)
-                end
-        })
-end
-
-
 -- Serialize the contents of a table value.
 function _serialize_table(t, seen)
        assert(not seen[t], "Recursion detected.")
@@ -617,6 +631,20 @@ function execl(command)
        return data
 end
 
+
+local ubus_codes = {
+       "INVALID_COMMAND",
+       "INVALID_ARGUMENT",
+       "METHOD_NOT_FOUND",
+       "NOT_FOUND",
+       "NO_DATA",
+       "PERMISSION_DENIED",
+       "TIMEOUT",
+       "NOT_SUPPORTED",
+       "UNKNOWN_ERROR",
+       "CONNECTION_FAILED"
+}
+
 function ubus(object, method, data)
        if not _ubus_connection then
                _ubus_connection = _ubus.connect()
@@ -627,7 +655,8 @@ function ubus(object, method, data)
                if type(data) ~= "table" then
                        data = { }
                end
-               return _ubus_connection:call(object, method, data)
+               local rv, err = _ubus_connection:call(object, method, data)
+               return rv, err, ubus_codes[err]
        elseif object then
                return _ubus_connection:signatures(object)
        else
@@ -652,10 +681,11 @@ end
 function checklib(fullpathexe, wantedlib)
        local fs = require "nixio.fs"
        local haveldd = fs.access('/usr/bin/ldd')
-       if not haveldd then
+       local haveexe = fs.access(fullpathexe)
+       if not haveldd or not haveexe then
                return false
        end
-       local libs = exec("/usr/bin/ldd " .. fullpathexe)
+       local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe)))
        if not libs then
                return false
        end
index 949aeb2..c4f28d0 100644 (file)
@@ -15,126 +15,164 @@ Class can be instantiated by calling them. All parameters will be passed
 to the __init__ function of this class - if such a function exists.
 The __init__ function must be used to set any object parameters that are not shared
 with other objects of this class. Any return values will be ignored.
-@class function
-@name class
-@param base    The base class to inherit from (optional)
-@return                A class object
-@see                   instanceof
-@see                   clone
+
+@class                         function
+@name                          class
+@param base                    The base class to inherit from (optional)
+@return                                A class object
+@see                           instanceof
+@see                           clone
 ]]
 
 ---[[
 Test whether the given object is an instance of the given class.
 
-@class function
-@name instanceof
-@param object  Object instance
+@class                         function
+@name                          instanceof
+@param object          Object instance
 @param class           Class object to test against
-@return                        Boolean indicating whether the object is an instance
+@return                                Boolean indicating whether the object is an instance
 @see                           class
 @see                           clone
 ]]
 
 ---[[
 Create a new or get an already existing thread local store associated with
+the current active coroutine.
 
-the current active coroutine. A thread local store is private a table object
+A thread local store is private a table object
 whose values can't be accessed from outside of the running coroutine.
-@class function
-@name threadlocal
-@return        Table value representing the corresponding thread local store
+
+@class                         function
+@name                          threadlocal
+@return                                Table value representing the corresponding thread local store
 ]]
 
 ---[[
 Write given object to stderr.
 
-@class function
-@name perror
-@param obj     Value to write to stderr
-@return                Boolean indicating whether the write operation was successful
+@class                         function
+@name                          perror
+@param obj                     Value to write to stderr
+@return                                Boolean indicating whether the write operation was successful
 ]]
 
 ---[[
 Recursively dumps a table to stdout, useful for testing and debugging.
 
-@class function
-@name dumptable
-@param t       Table value to dump
-@param maxdepth        Maximum depth
-@return        Always nil
+@class                         function
+@name                          dumptable
+@param t                       Table value to dump
+@param maxdepth                Maximum depth
+@return                                Always nil
 ]]
 
 ---[[
 Create valid XML PCDATA from given string.
 
-@class function
-@name pcdata
-@param value   String value containing the data to escape
-@return                String value containing the escaped data
+@class                         function
+@name                          pcdata
+@param value           String value containing the data to escape
+@return                                String value containing the escaped data
+]]
+
+---[[
+Decode an URL-encoded string - optionally decoding the "+" sign to space.
+
+@class                         function
+@name                          urldecode
+@param str                     Input string in x-www-urlencoded format
+@param decode_plus     Decode "+" signs to spaces if true (optional)
+@return                                The decoded string
+@see                           urlencode
+]]
+
+---[[
+URL-encode given string.
+
+@class                         function
+@name                          urlencode
+@param str                     String to encode
+@return                                String containing the encoded data
+@see                           urldecode
 ]]
 
 ---[[
 Strip HTML tags from given string.
 
-@class function
-@name striptags
-@param value   String containing the HTML text
-@return        String with HTML tags stripped of
+@class                         function
+@name                          striptags
+@param value           String containing the HTML text
+@return                                String with HTML tags stripped of
 ]]
 
 ---[[
-Splits given string on a defined separator sequence and return a table
+Safely quote value for use in shell commands.
+
+@class                         function
+@name                          shellquote
+@param value           String containing the value to quote
+@return                        Single-quote enclosed string with embedded quotes escaped
+]]
 
-containing the resulting substrings. The optional max parameter specifies
-the number of bytes to process, regardless of the actual length of the given
-string. The optional last parameter, regex, specifies whether the separator
-sequence is interpreted as regular expression.
-@class function
-@name split
-@param str             String value containing the data to split up
-@param pat             String with separator pattern (optional, defaults to "\n")
-@param max             Maximum times to split (optional)
-@param regex   Boolean indicating whether to interpret the separator
+---[[
+Splits given string on a defined separator sequence and return a table
+containing the resulting substrings.
+
+The optional max parameter specifies the number of bytes to process,
+regardless of the actual length of the given string. The optional last
+parameter, regex, specifies whether the separator sequence is
+nterpreted as regular expression.
+
+@class                         function
+@name                          split
+@param str                     String value containing the data to split up
+@param pat                     String with separator pattern (optional, defaults to "\n")
+@param max                     Maximum times to split (optional)
+@param regex           Boolean indicating whether to interpret the separator
 --                                     pattern as regular expression (optional, default is false)
-@return                        Table containing the resulting substrings
+@return                                Table containing the resulting substrings
 ]]
 
 ---[[
 Remove leading and trailing whitespace from given string value.
 
-@class function
-@name trim
-@param str     String value containing whitespace padded data
-@return                String value with leading and trailing space removed
+@class                         function
+@name                          trim
+@param str                     String value containing whitespace padded data
+@return                                String value with leading and trailing space removed
 ]]
 
 ---[[
 Count the occurrences of given substring in given string.
 
-@class function
-@name cmatch
-@param str             String to search in
-@param pattern String containing pattern to find
-@return                        Number of found occurrences
+@class                         function
+@name                          cmatch
+@param str                     String to search in
+@param pattern         String containing pattern to find
+@return                                Number of found occurrences
 ]]
 
 ---[[
-Return a matching iterator for the given value. The iterator will return
+Return a matching iterator for the given value.
+
+The iterator will return one token per invocation, the tokens are separated by
+whitespace. If the input value is a table, it is transformed into a string first.
+A nil value will result in a valid interator which aborts with the first invocation.
 
-one token per invocation, the tokens are separated by whitespace. If the
-input value is a table, it is transformed into a string first. A nil value
-will result in a valid interator which aborts with the first invocation.
-@class function
-@name imatch
-@param val             The value to scan (table, string or nil)
-@return                        Iterator which returns one token per call
+@class                         function
+@name                          imatch
+@param val                     The value to scan (table, string or nil)
+@return                                Iterator which returns one token per call
 ]]
 
 ---[[
 Parse certain units from the given string and return the canonical integer
+value or 0 if the unit is unknown.
 
-value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
+Upper- or lower case is irrelevant.
 Recognized units are:
+
 --     o "y"   - one year   (60*60*24*366)
  o "m" - one month  (60*60*24*31)
  o "w" - one week   (60*60*24*7)
@@ -147,232 +185,229 @@ Recognized units are:
  o "kib" - one si kilobyte (1000)
  o "mib"       - one si megabyte (1000*1000)
  o "gib"       - one si gigabyte (1000*1000*1000)
-@class function
-@name parse_units
-@param ustr    String containing a numerical value with trailing unit
-@return                Number containing the canonical value
+
+@class                         function
+@name                          parse_units
+@param ustr                    String containing a numerical value with trailing unit
+@return                                Number containing the canonical value
 ]]
 
 ---[[
 Appends numerically indexed tables or single objects to a given table.
 
-@class function
-@name append
-@param src     Target table
-@param ...     Objects to insert
-@return                Target table
+@class                         function
+@name                          append
+@param src                     Target table
+@param ...                     Objects to insert
+@return                                Target table
 ]]
 
 ---[[
 Combines two or more numerically indexed tables and single objects into one table.
 
-@class function
-@name combine
-@param tbl1    Table value to combine
-@param tbl2    Table value to combine
-@param ...     More tables to combine
-@return                Table value containing all values of given tables
+@class                         function
+@name                          combine
+@param tbl1                    Table value to combine
+@param tbl2                    Table value to combine
+@param ...                     More tables to combine
+@return                                Table value containing all values of given tables
 ]]
 
 ---[[
 Checks whether the given table contains the given value.
 
-@class function
-@name contains
-@param table   Table value
-@param value   Value to search within the given table
-@return                number indicating the first index at which the given value occurs
---                     within table or false.
+@class                         function
+@name                          contains
+@param table           Table value
+@param value           Value to search within the given table
+@return                                Number indicating the first index at which the given value occurs
+--                                     within table or false.
 ]]
 
 ---[[
 Update values in given table with the values from the second given table.
 
 Both table are - in fact - merged together.
-@class function
-@name update
+
+@class                         function
+@name                          update
 @param t                       Table which should be updated
-@param updates Table containing the values to update
-@return                        Always nil
+@param updates         Table containing the values to update
+@return                                Always nil
 ]]
 
 ---[[
 Retrieve all keys of given associative table.
 
-@class function
-@name keys
-@param t       Table to extract keys from
-@return        Sorted table containing the keys
+@class                         function
+@name                          keys
+@param t                       Table to extract keys from
+@return                                Sorted table containing the keys
 ]]
 
 ---[[
 Clones the given object and return it's copy.
 
-@class function
-@name clone
-@param object  Table value to clone
-@param deep            Boolean indicating whether to do recursive cloning
-@return                        Cloned table value
-]]
-
----[[
-Create a dynamic table which automatically creates subtables.
-
-@class function
-@name dtable
-@return        Dynamic Table
+@class                         function
+@name                          clone
+@param object          Table value to clone
+@param deep                    Boolean indicating whether to do recursive cloning
+@return                                Cloned table value
 ]]
 
 ---[[
 Recursively serialize given data to lua code, suitable for restoring
-
 with loadstring().
-@class function
-@name serialize_data
-@param val     Value containing the data to serialize
-@return                String value containing the serialized code
-@see                   restore_data
-@see                   get_bytecode
+
+@class                         function
+@name                          serialize_data
+@param val                     Value containing the data to serialize
+@return                                String value containing the serialized code
+@see                           restore_data
+@see                           get_bytecode
 ]]
 
 ---[[
 Restore data previously serialized with serialize_data().
 
-@class function
-@name restore_data
-@param str     String containing the data to restore
-@return                Value containing the restored data structure
-@see                   serialize_data
-@see                   get_bytecode
+@class                         function
+@name                          restore_data
+@param str                     String containing the data to restore
+@return                                Value containing the restored data structure
+@see                           serialize_data
+@see                           get_bytecode
 ]]
 
 ---[[
 Return the current runtime bytecode of the given data. The byte code
-
 will be stripped before it is returned.
-@class function
-@name get_bytecode
-@param val     Value to return as bytecode
-@return                String value containing the bytecode of the given data
+
+@class                         function
+@name                          get_bytecode
+@param val                     Value to return as bytecode
+@return                                String value containing the bytecode of the given data
 ]]
 
 ---[[
-Strips unnescessary lua bytecode from given string. Information like line
+Strips unnescessary lua bytecode from given string.
+
+Information like line numbers and debugging numbers will be discarded.
+Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
 
-numbers and debugging numbers will be discarded. Original version by
-Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
-@class function
-@name strip_bytecode
-@param code    String value containing the original lua byte code
-@return                String value containing the stripped lua byte code
+@class                         function
+@name                          strip_bytecode
+@param code                    String value containing the original lua byte code
+@return                                String value containing the stripped lua byte code
 ]]
 
 ---[[
 Return a key, value iterator which returns the values sorted according to
-
 the provided callback function.
-@class function
-@name spairs
-@param t       The table to iterate
-@param f A callback function to decide the order of elements
-@return        Function value containing the corresponding iterator
+
+@class                         function
+@name                          spairs
+@param t                       The table to iterate
+@param f                       A callback function to decide the order of elements
+@return                                Function value containing the corresponding iterator
 ]]
 
 ---[[
 Return a key, value iterator for the given table.
 
 The table pairs are sorted by key.
-@class function
-@name kspairs
-@param t       The table to iterate
-@return        Function value containing the corresponding iterator
+
+@class                         function
+@name                          kspairs
+@param t                       The table to iterate
+@return                                Function value containing the corresponding iterator
 ]]
 
 ---[[
 Return a key, value iterator for the given table.
 
 The table pairs are sorted by value.
-@class function
-@name vspairs
-@param t       The table to iterate
-@return        Function value containing the corresponding iterator
+
+@class                         function
+@name                          vspairs
+@param t                       The table to iterate
+@return                                Function value containing the corresponding iterator
 ]]
 
 ---[[
 Test whether the current system is operating in big endian mode.
 
-@class function
-@name bigendian
-@return        Boolean value indicating whether system is big endian
+@class                         function
+@name                          bigendian
+@return                                Boolean value indicating whether system is big endian
 ]]
 
 ---[[
 Execute given commandline and gather stdout.
 
-@class function
-@name exec
-@param command String containing command to execute
-@return                        String containing the command's stdout
+@class                         function
+@name                          exec
+@param command         String containing command to execute
+@return                                String containing the command's stdout
 ]]
 
 ---[[
 Return a line-buffered iterator over the output of given command.
 
-@class function
-@name execi
-@param command String containing the command to execute
-@return                        Iterator
+@class                         function
+@name                          execi
+@param command         String containing the command to execute
+@return                                Iterator
 ]]
 
 ---[[
 Issue an ubus call.
 
-@class function
-@name ubus
+@class                         function
+@name                          ubus
 @param object          String containing the ubus object to call
 @param method          String containing the ubus method to call
 @param values          Table containing the values to pass
-@return                        Table containin the ubus result
+@return                                Table containin the ubus result
 ]]
 
 ---[[
 Convert data structure to JSON
 
-@class function
-@name serialize_json
-@param data            The data to serialize
-@param writer  A function to write a chunk of JSON data (optional)
-@return                        String containing the JSON if called without write callback
+@class                         function
+@name                          serialize_json
+@param data                    The data to serialize
+@param writer          A function to write a chunk of JSON data (optional)
+@return                                String containing the JSON if called without write callback
 ]]
 
 ---[[
 Returns the absolute path to LuCI base directory.
 
-@class function
-@name libpath
-@return                String containing the directory path
+@class                         function
+@name                          libpath
+@return                                String containing the directory path
 ]]
 
 ---[[
 This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
 
-@class function
-@name coxpcall
-@param f               Lua function to be called protected
-@param err     Custom error handler
-@param ...     Parameters passed to the function
-@return                A boolean whether the function call succeeded and the return
---                             values of either the function or the error handler
+@class                         function
+@name                          coxpcall
+@param f                       Lua function to be called protected
+@param err                     Custom error handler
+@param ...                     Parameters passed to the function
+@return                                A boolean whether the function call succeeded and the return
+--                                     values of either the function or the error handler
 ]]
 
 ---[[
 This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
 
-@class function
-@name copcall
-@param f               Lua function to be called protected
-@param ...     Parameters passed to the function
-@return                A boolean whether the function call succeeded and the returns
---                             values of the function or the error object
+@class                         function
+@name                          copcall
+@param f                       Lua function to be called protected
+@param ...                     Parameters passed to the function
+@return                                A boolean whether the function call succeeded and the returns
+--                                     values of the function or the error object
 ]]
 
index a79beeb..806b1b5 100644 (file)
@@ -22,9 +22,9 @@
        <script type="text/javascript">
                function callback(path) {
                        if( window.opener ) {
-                               var input = window.opener.document.getElementById('<%=luci.http.formvalue('field')%>');
+                               var input = window.opener.document.getElementById(decodeURIComponent('<%=luci.http.urlencode(luci.http.formvalue('field'))%>'));
                                if( input ) {
-                                       input.value = path;
+                                       input.value = decodeURIComponent(path);
                                        window.close();
                                }
                        }
                        end
                end
 
-               local filepath = table.concat( path, '/' )
-               local filestat = nixio.fs.stat( filepath )
-               local baseurl  = luci.dispatcher.build_url('admin', 'filebrowser')
+               local filestat = nixio.fs.stat(table.concat(path, '/'))
+               local baseurl  = { 'admin', 'filebrowser' }
 
                if filestat and filestat.type == "reg" then
-                       table.remove( path, #path )
-                       filepath = table.concat( path, '/' ) .. '/'
-               elseif not ( filestat and filestat.type == "dir" ) then
-                       path     = { '' }
-                       filepath = '/'
+                       path[#path] = ''
+               elseif not (filestat and filestat.type == "dir") then
+                       path = { '', '' }
                else
-                       filepath = filepath .. '/'
+                       path[#path+1] = ''
                end
 
-               local entries = nixio.util.consume((nixio.fs.dir(filepath)))
+               filepath = table.concat(path, '/')
+
+               local entries = {}
+               local _, e
+               for _, e in luci.util.vspairs(nixio.util.consume((nixio.fs.dir(filepath)))) do
+                       local p = filepath .. e
+                       local s = nixio.fs.stat(p)
+                       if s then
+                               entries[#entries+1] = {
+                                       name = e,
+                                       path = p,
+                                       type = s.type
+                               }
+                       end
+               end
        -%>
-    <div id="path">
+       <div id="path">
                Location:
                <% for i, dir in ipairs(path) do %>
                        <% if i == 1 then %>
-                               <a href="<%=baseurl%>?field=<%=field%>">(root)</a>
+                               <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>">(root)</a>
                        <% elseif next(path, i) then %>
-                               <% baseurl = baseurl .. '/' .. dir %>
-                               / <a href="<%=baseurl%>?field=<%=field%>"><%=dir%></a>
+                               <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
+                               / <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(dir)%></a>
                        <% else %>
-                               <% baseurl = baseurl .. '/' .. dir %>
-                               / <%=dir%>
+                               <% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
+                               / <%=pcdata(dir)%>
                        <% end %>
                <% end %>
        </div>
 
        <div id="listing">
                <ul>
-                       <% for _, e in luci.util.vspairs(entries) do
-                           local stat = nixio.fs.stat(filepath..e)
-                               if stat and stat.type == 'dir' then
-                       -%>
+                       <% for _, e in ipairs(entries) do if e.type == 'dir' then -%>
                                <li class="dir">
                                        <img src="<%=resource%>/cbi/folder.gif" alt="<%:Directory%>" />
-                                       <a href="<%=baseurl%>/<%=e%>?field=<%=field%>"><%=e%>/</a>
+                                       <a href="<%=url(unpack(baseurl))%>/<%=luci.http.urlencode(e.name)%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(e.name)%>/</a>
                                </li>
                        <% end end -%>
 
-                       <% for _, e in luci.util.vspairs(entries) do
-                           local stat = nixio.fs.stat(filepath..e)
-                               if stat and stat.type ~= 'dir' then
-                       -%>
+                       <% for _, e in ipairs(entries) do if e.type ~= 'dir' then -%>
                                <li class="file">
                                        <img src="<%=resource%>/cbi/file.gif" alt="<%:File%>" />
-                                       <a href="#" onclick="callback('<%=filepath..e%>')"><%=e%></a>
+                                       <a href="#" onclick="callback('<%=luci.http.urlencode(e.path)%>')"><%=pcdata(e.name)%></a>
                                </li>
                        <% end end -%>
                </ul>
index 78f5c5a..3b758d7 100644 (file)
@@ -52,7 +52,8 @@
                <%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%>
        " />
 <% end %>
-               <script type="text/javascript">cbi_d_update();</script>
        </div>
 </form>
 <% end %>
+
+<script type="text/javascript">cbi_init();</script>
index 26d13f9..3cb8756 100644 (file)
@@ -35,7 +35,7 @@ end
                                <%- else -%>
                                        <th>&#160;</th>
                                <%- end -%>
-                       <%- end -%>
+                       <%- count = count +1; end -%>
                        <%- for i, k in pairs(self.children) do if not k.optional then -%>
                                <th class="cbi-section-table-cell"<%=width(k)%>>
                                <%- if k.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%- end -%>
@@ -44,7 +44,7 @@ end
                                </th>
                        <%- count = count + 1; end; end; if self.sortable then -%>
                                <th class="cbi-section-table-cell"><%:Sort%></th>
-                       <%- end; if self.extedit or self.addremove then -%>
+                       <%- count = count + 1; end; if self.extedit or self.addremove then -%>
                                <th class="cbi-section-table-cell">&#160;</th>
                        <%- count = count + 1; end -%>
                        </tr>
index bc74226..a762f60 100644 (file)
@@ -7,5 +7,5 @@
 <%+header%>
 <h2 name="content">404 <%:Not Found%></h2>
 <p><%:Sorry, the object you requested was not found.%></p>
-<tt><%:Unable to dispatch%>: <%=luci.http.request.env.PATH_INFO%></tt>
+<tt><%:Unable to dispatch%>: <%=url(unpack(luci.dispatcher.context.request))%></tt>
 <%+footer%>
index f6b0f57..b3ec9b7 100644 (file)
@@ -6,7 +6,7 @@
 
 <%+header%>
 
-<form method="post" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
+<form method="post" action="<%=pcdata(FULL_REQUEST_URI)%>">
        <%- if fuser then %>
        <div class="errorbox"><%:Invalid username and/or password! Please try again.%></div>
        <% end -%>
index a6a8843..c413b71 100644 (file)
@@ -744,6 +744,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2154,6 +2159,9 @@ msgstr "Avís"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "D'acord"
 
@@ -2913,6 +2921,9 @@ msgstr "Mida"
 msgid "Size (.ipk)"
 msgstr "Mida (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Salta"
 
@@ -3305,7 +3316,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index c69654f..89714cc 100644 (file)
@@ -738,6 +738,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2162,6 +2167,9 @@ msgstr "Oznámení"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2939,6 +2947,9 @@ msgstr "Velikost"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Přeskočit"
 
@@ -3347,7 +3358,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index 47472a3..fd495b9 100644 (file)
@@ -764,6 +764,11 @@ msgid "Custom feeds"
 msgstr "Eigene Repositories"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr "Passt das Verhalten der Geräte-LEDs an - wenn dies möglich ist."
@@ -2228,6 +2233,9 @@ msgstr "Notiz"
 msgid "Nslookup"
 msgstr "DNS-Auflösung"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -3039,6 +3047,9 @@ msgstr "Größe"
 msgid "Size (.ipk)"
 msgstr "Größe (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Überspringen"
 
@@ -3480,10 +3491,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Dies ist die lokale, vom Broker zugewiesene IPv6-Adresse, sie endet "
-"üblicherweise mit <code>:2</code>"
+"üblicherweise mit <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index d0b9e24..ad5ed07 100644 (file)
@@ -747,6 +747,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2170,6 +2175,9 @@ msgstr "Επισήμανση"
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "Εντάξει"
 
@@ -2931,6 +2939,9 @@ msgstr "Μέγεθος"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Παράκαμψη"
 
@@ -3307,7 +3318,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index fbaa03b..f629135 100644 (file)
@@ -734,6 +734,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2137,6 +2142,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2895,6 +2903,9 @@ msgstr "Size"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Skip"
 
@@ -3267,7 +3278,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index a92bb43..776f7fb 100644 (file)
@@ -743,6 +743,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2176,6 +2181,9 @@ msgstr "Aviso"
 msgid "Nslookup"
 msgstr "NSLookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "Aceptar"
 
@@ -2952,6 +2960,9 @@ msgstr "Tamaño"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Saltar"
 
@@ -3372,10 +3383,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Esta es la dirección de punto final asignada por el broker del túnel, suele "
-"terminar con <code>:2</code>"
+"terminar con <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index cba7cac..9de1687 100644 (file)
@@ -750,6 +750,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2190,6 +2195,9 @@ msgstr "Note"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2966,6 +2974,9 @@ msgstr "Taille"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Passer au suivant"
 
@@ -3387,10 +3398,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Il s'agit de l'adresse de l'extrémité locale attribuée par le fournisseur de "
-"tunnels, elle se termine habituellement avec <code>:2</code>"
+"tunnels, elle se termine habituellement avec <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index 6d98134..8d5daf3 100644 (file)
@@ -727,6 +727,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2110,6 +2115,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr ""
 
@@ -2862,6 +2870,9 @@ msgstr ""
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3228,7 +3239,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index e7b3a79..5e2ea2b 100644 (file)
@@ -745,6 +745,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2179,6 +2184,9 @@ msgstr "Megjegyzés"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2957,6 +2965,9 @@ msgstr "Méret"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Ugrás"
 
@@ -3375,10 +3386,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Ez az alagút közvetítő (tunnel broker) által megadott helyi végpont címe, "
-"általában így végződik: <code>:2</code>"
+"általában így végződik: <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index 414fddf..6b55e23 100644 (file)
@@ -750,6 +750,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2179,6 +2184,9 @@ msgstr "Notifica"
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2941,6 +2949,9 @@ msgstr "Dimensione"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Salta"
 
@@ -3335,7 +3346,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index c069940..b643e8c 100644 (file)
@@ -3,18 +3,18 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2009-06-10 03:40+0200\n"
-"PO-Revision-Date: 2017-10-20 13:54+0900\n"
+"PO-Revision-Date: 2018-04-26 00:23+0900\n"
 "Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
 "Language: ja\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 2.0.4\n"
+"X-Generator: Poedit 2.0.7\n"
 "Language-Team: \n"
 
 msgid "%.1f dB"
-msgstr ""
+msgstr "%.1f dB"
 
 msgid "%s is untagged in multiple VLANs!"
 msgstr "%s は複数のVLANにUntaggedしています!"
@@ -137,7 +137,7 @@ msgid "<abbr title=\"Media Access Control\">MAC</abbr>-Address"
 msgstr "<abbr title=\"Media Access Control\">MAC</abbr>-アドレス"
 
 msgid "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"
-msgstr ""
+msgstr "<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"
 
 msgid ""
 "<abbr title=\"maximal\">Max.</abbr> <abbr title=\"Dynamic Host Configuration "
@@ -251,6 +251,8 @@ msgstr "追加"
 
 msgid "Add local domain suffix to names served from hosts files"
 msgstr ""
+"hosts ファイルにより解決される名前にローカルドメイン サフィックスを付加しま"
+"す。"
 
 msgid "Add new interface..."
 msgstr "インターフェースの新規作成..."
@@ -751,6 +753,13 @@ msgid "Custom feeds"
 msgstr "カスタム フィード"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+"カスタム ファイル(証明書, スクリプト)がシステムに残るかもしれません。これを"
+"防ぐには、まず最初に factory-reset を行います。"
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -1254,7 +1263,7 @@ msgid "Force use of NAT-T"
 msgstr "NAT-Tの強制使用"
 
 msgid "Form token mismatch"
-msgstr ""
+msgstr "フォーム トークンの不一致"
 
 msgid "Forward DHCP traffic"
 msgstr "DHCPトラフィックを転送する"
@@ -1661,7 +1670,7 @@ msgstr ""
 "ユーザー名かパスワード、もしくは両方が不正です!もう一度入力してください。"
 
 msgid "Isolate Clients"
-msgstr ""
+msgstr "クライアント間の分離"
 
 msgid ""
 "It appears that you are trying to flash an image that does not fit into the "
@@ -1756,6 +1765,8 @@ msgstr "割り当て数"
 
 msgid "Limit DNS service to subnets interfaces on which we are serving DNS."
 msgstr ""
+"DNS サービスを、現在 DNS を提供しているサブネットのインターフェースに限定しま"
+"す。"
 
 msgid "Limit listening to these interfaces, and loopback."
 msgstr "待ち受けをこれらのインターフェースとループバックに制限します。"
@@ -1840,7 +1851,7 @@ msgid "Local IPv6 address"
 msgstr "ローカル IPv6 アドレス"
 
 msgid "Local Service Only"
-msgstr ""
+msgstr "ローカルサービスのみ"
 
 msgid "Local Startup"
 msgstr "ローカル スタートアップ"
@@ -1855,6 +1866,8 @@ msgid ""
 "Local domain specification. Names matching this domain are never forwarded "
 "and are resolved from DHCP or hosts files only"
 msgstr ""
+"ローカル ドメインの定義です。このドメインに一致する名前は転送が行われず、 "
+"DHCP または hosts ファイルのみにより解決されます。"
 
 msgid "Local domain suffix appended to DHCP names and hosts file entries"
 msgstr ""
@@ -2178,6 +2191,9 @@ msgstr "注意"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2962,6 +2978,9 @@ msgstr "サイズ"
 msgid "Size (.ipk)"
 msgstr "サイズ (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "スキップ"
 
@@ -3085,10 +3104,10 @@ msgid "Submit"
 msgstr "送信"
 
 msgid "Suppress logging"
-msgstr ""
+msgstr "ログの抑制"
 
 msgid "Suppress logging of the routine operation of these protocols"
-msgstr ""
+msgstr "これらのプロトコルのルーチン的操作についてのログを抑制します。"
 
 msgid "Swap"
 msgstr "スワップ"
@@ -3110,7 +3129,7 @@ msgid ""
 msgstr ""
 
 msgid "Switch Port Mask"
-msgstr ""
+msgstr "スイッチポート マスク"
 
 msgid "Switch VLAN"
 msgstr ""
@@ -3338,13 +3357,16 @@ msgstr ""
 "サービスを有効にするために、管理者パスワードを設定してください。"
 
 msgid "This IPv4 address of the relay"
-msgstr ""
+msgstr "リレーの IPv4 アドレス"
 
 msgid ""
 "This file may contain lines like 'server=/domain/1.2.3.4' or "
 "'server=1.2.3.4' fordomain-specific or full upstream <abbr title=\"Domain "
 "Name System\">DNS</abbr> servers."
 msgstr ""
+"このファイルは、特定ドメイン用、または上位 <abbr title=\"Domain Name System"
+"\">DNS</abbr> サーバーのための 'server=/domain/1.2.3.4' や 'server=1.2.3.4' "
+"というような行を含めることができます。"
 
 msgid ""
 "This is a list of shell glob patterns for matching files and directories to "
@@ -3369,17 +3391,17 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "プロバイダからアサインされた、ローカルのエンドポイント アドレスです。通常、"
-"<code>:2</code>が終端に設定されます。"
+"<code>...:2/64</code>が終端に設定されます。"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
 "abbr> in the local network"
 msgstr ""
-"ローカル ネットワーク内のみの <abbr title=\"Dynamic Host Configuration "
-"Protocol\">DHCP</abbr>として使用する"
+"ã\81\93ã\82\8cã\81¯ã\83­ã\83¼ã\82«ã\83« ã\83\8dã\83\83ã\83\88ã\83¯ã\83¼ã\82¯å\86\85ã\81®ã\81¿ã\81® <abbr title=\"Dynamic Host Configuration "
+"Protocol\">DHCP</abbr> です。"
 
 msgid "This is the plain username for logging into the account"
 msgstr ""
@@ -3946,24 +3968,3 @@ msgstr "はい"
 
 msgid "« Back"
 msgstr "« 戻る"
-
-#~ msgid "Action"
-#~ msgstr "動作"
-
-#~ msgid "Buttons"
-#~ msgstr "ボタン"
-
-#~ msgid "Handler"
-#~ msgstr "ハンドラ"
-
-#~ msgid "Maximum hold time"
-#~ msgstr "最大保持時間"
-
-#~ msgid "Minimum hold time"
-#~ msgstr "最短保持時間"
-
-#~ msgid "Path to executable which handles the button event"
-#~ msgstr "ボタンイベントをハンドルする実行ファイルのパス"
-
-#~ msgid "This page allows the configuration of custom button actions"
-#~ msgstr "このページでは、ボタンの動作を変更することができます。"
index c56c05e..04d3c6a 100644 (file)
@@ -732,6 +732,11 @@ msgid "Custom feeds"
 msgstr "Custom feed 들"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2128,6 +2133,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr ""
 
@@ -2890,6 +2898,9 @@ msgstr "Size"
 msgid "Size (.ipk)"
 msgstr "크기 (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3270,7 +3281,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index ff33243..b478bd6 100644 (file)
@@ -712,6 +712,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr "Mengkustomisasi perilaku peranti LED jika mungkin."
@@ -2108,6 +2113,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "Baik"
 
@@ -2864,6 +2872,9 @@ msgstr "Saiz"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Skip"
 
@@ -3238,7 +3249,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index f8b40c1..502c3b3 100644 (file)
@@ -734,6 +734,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2153,6 +2158,9 @@ msgstr "Merk"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2930,6 +2938,9 @@ msgstr "Størrelse"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Gå videre"
 
@@ -3343,10 +3354,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Dette er den lokale endepunkt adressen som ble tildelt av tunnel 'broker', "
-"adressen ender vanligvis med <code>:2</code>"
+"adressen ender vanligvis med <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index 9bc33a4..956e566 100644 (file)
@@ -752,6 +752,11 @@ msgstr ""
 msgid "Custom feeds"
 msgstr ""
 
+msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
 # Spacji zabrało i napisy się skleiły
 msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
@@ -2198,6 +2203,9 @@ msgstr "Spostrzeżenie"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2978,6 +2986,9 @@ msgstr "Rozmiar"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Pomiń"
 
@@ -3400,10 +3411,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "To jest lokalny adres końcowy przypisany przez tunnel broker'a, zwykle "
-"kończący się z <code>:2</code>"
+"kończący się z <code>...:2/64</code>"
 
 # w tłumaczeniu pojawiła się spacja po DHCP</abbr> co powoduje niepoprawne wyświetlanie się strony z lang PL
 msgid ""
index bf0de75..9c4901f 100644 (file)
@@ -787,6 +787,11 @@ msgid "Custom feeds"
 msgstr "Fontes de pacotes customizadas"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2279,6 +2284,9 @@ msgstr "Aviso"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -3084,6 +3092,9 @@ msgstr "Tamanho"
 msgid "Size (.ipk)"
 msgstr "Tamanho (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Pular"
 
@@ -3519,10 +3530,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Este é o endereço da ponta local designado pelo agente de túnel. normalmente "
-"ele termina com <code>:2</code>"
+"ele termina com <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index 3109903..8f2622c 100644 (file)
@@ -747,6 +747,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2177,6 +2182,9 @@ msgstr "Reparo"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2948,6 +2956,9 @@ msgstr "Tamanho"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Saltar"
 
@@ -3347,7 +3358,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index 955cff6..86eaa64 100644 (file)
@@ -722,6 +722,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2107,6 +2112,9 @@ msgstr "Notificare"
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2858,6 +2866,9 @@ msgstr "Marime"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3220,7 +3231,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index c0b53eb..4ffb723 100644 (file)
@@ -778,6 +778,11 @@ msgid "Custom feeds"
 msgstr "Список custom-ных feed-ов"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2235,6 +2240,9 @@ msgstr "Заметка"
 msgid "Nslookup"
 msgstr "DNS-запрос"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -3043,6 +3051,9 @@ msgstr "Размер"
 msgid "Size (.ipk)"
 msgstr "Размер (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Пропустить"
 
@@ -3471,10 +3482,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Это локальный адрес, назначенный туннельным брокером, обычно заканчивается "
-"на <code>:2</code>."
+"на <code>...:2/64</code>."
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index ec72661..a17ac98 100644 (file)
@@ -705,6 +705,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2082,6 +2087,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr ""
 
@@ -2830,6 +2838,9 @@ msgstr ""
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3190,7 +3201,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index a7f906e..089546a 100644 (file)
@@ -719,6 +719,11 @@ msgid "Custom feeds"
 msgstr "Anpassade flöden"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2103,6 +2108,9 @@ msgstr "Avisering"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2853,6 +2861,9 @@ msgstr "Storlek"
 msgid "Size (.ipk)"
 msgstr "Storlek (.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Hoppa över"
 
@@ -3215,7 +3226,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index a840921..de8b7fb 100644 (file)
@@ -698,6 +698,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2075,6 +2080,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr ""
 
@@ -2823,6 +2831,9 @@ msgstr ""
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3183,7 +3194,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index 496d96f..45f4a7c 100644 (file)
@@ -718,6 +718,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2095,6 +2100,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr ""
 
@@ -2843,6 +2851,9 @@ msgstr ""
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3203,7 +3214,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index 520bff4..b1feed3 100644 (file)
@@ -756,6 +756,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2191,6 +2196,9 @@ msgstr "Попередження"
 msgid "Nslookup"
 msgstr "DNS-запит"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK"
 
@@ -2973,6 +2981,9 @@ msgstr "Розмір"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "Пропустити"
 
@@ -3391,10 +3402,10 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 "Це локальна адреса кінцевої точки, присвоєна тунельним брокером, зазвичай "
-"закінчується на <code>:2</code>"
+"закінчується на <code>...:2/64</code>"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index 2287dfb..ecb369e 100644 (file)
@@ -712,6 +712,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2112,6 +2117,9 @@ msgstr ""
 msgid "Nslookup"
 msgstr ""
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "OK "
 
@@ -2870,6 +2878,9 @@ msgstr "Dung lượng "
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr ""
 
@@ -3240,7 +3251,7 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
+"ends with <code>...:2/64</code>"
 msgstr ""
 
 msgid ""
index c0a5351..c76511b 100644 (file)
@@ -721,6 +721,12 @@ msgid "Custom feeds"
 msgstr "自定义软件源"
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+"自定义文件(证书、脚本)会保留在系统上。若无需保留,请先执行恢复出厂设置。"
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr "自定义此设备的 <abbr title=\"Light Emitting Diode\">LED</abbr> 行为。"
@@ -2127,6 +2133,9 @@ msgstr "注意"
 msgid "Nslookup"
 msgstr "Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr "缓存的 DNS 条目数量(最大 10000,0 表示不缓存)"
+
 msgid "OK"
 msgstr "确认"
 
@@ -2900,6 +2909,9 @@ msgstr "大小"
 msgid "Size (.ipk)"
 msgstr "大小(.ipk)"
 
+msgid "Size of DNS query cache"
+msgstr "DNS 查询缓存的大小"
+
 msgid "Skip"
 msgstr "跳过"
 
@@ -3283,8 +3295,8 @@ msgstr "启动脚本插入到 'exit 0' 之前即可随系统启动运行。"
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
-msgstr "隧道代理分配的本地终端地址,通常以 <code>:2</code> 结尾"
+"ends with <code>...:2/64</code>"
+msgstr "隧道代理分配的本地终端地址,通常以 <code>...:2/64</code> 结尾"
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
index d78223f..28a806e 100644 (file)
@@ -723,6 +723,11 @@ msgid "Custom feeds"
 msgstr ""
 
 msgid ""
+"Custom files (certificates, scripts) may remain on the system. To prevent "
+"this, perform a factory-reset first."
+msgstr ""
+
+msgid ""
 "Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
 "\">LED</abbr>s if possible."
 msgstr ""
@@ -2119,6 +2124,9 @@ msgstr "通知"
 msgid "Nslookup"
 msgstr "DNS偵錯Nslookup"
 
+msgid "Number of cached DNS entries (max is 10000, 0 is no caching)"
+msgstr ""
+
 msgid "OK"
 msgstr "行"
 
@@ -2883,6 +2891,9 @@ msgstr "大小"
 msgid "Size (.ipk)"
 msgstr ""
 
+msgid "Size of DNS query cache"
+msgstr ""
+
 msgid "Skip"
 msgstr "跳過"
 
@@ -3275,8 +3286,8 @@ msgstr ""
 
 msgid ""
 "This is the local endpoint address assigned by the tunnel broker, it usually "
-"ends with <code>:2</code>"
-msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>:2</code>結尾."
+"ends with <code>...:2/64</code>"
+msgstr "這是由通道代理人指定的本地終端位址, 通常用 <code>...:2/64</code>結尾."
 
 msgid ""
 "This is the only <abbr title=\"Dynamic Host Configuration Protocol\">DHCP</"
diff --git a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json
new file mode 100644 (file)
index 0000000..ed7ad8a
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       "uci-access": {
+               "description": "Grant uci write access to all configurations",
+               "read": {
+                       "uci": [ "*" ]
+               },
+               "write": {
+                       "uci": [ "*" ]
+               }
+       }
+}
index 33f6a67..ab6db4f 100644 (file)
@@ -82,7 +82,7 @@ function index()
                end
 
 
-               page = entry({"admin", "network", "iface_add"}, cbi("admin_network/iface_add"), nil)
+               page = entry({"admin", "network", "iface_add"}, form("admin_network/iface_add"), nil)
                page.leaf = true
 
                page = entry({"admin", "network", "iface_delete"}, post("iface_delete"), nil)
@@ -289,7 +289,8 @@ function iface_reconnect(iface)
        local netmd = require "luci.model.network".init()
        local net = netmd:get_network(iface)
        if net then
-               luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface)
+               luci.sys.call("env -i /sbin/ifup %s >/dev/null 2>/dev/null"
+                       % luci.util.shellquote(iface))
                luci.http.status(200, "Reconnected")
                return
        end
@@ -301,7 +302,8 @@ function iface_shutdown(iface)
        local netmd = require "luci.model.network".init()
        local net = netmd:get_network(iface)
        if net then
-               luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
+               luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
+                       % luci.util.shellquote(iface))
                luci.http.status(200, "Shutdown")
                return
        end
@@ -313,7 +315,8 @@ function iface_delete(iface)
        local netmd = require "luci.model.network".init()
        local net = netmd:del_network(iface)
        if net then
-               luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface)
+               luci.sys.call("env -i /sbin/ifdown %s >/dev/null 2>/dev/null"
+                       % luci.util.shellquote(iface))
                luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
                netmd:commit("network")
                netmd:commit("wireless")
@@ -389,7 +392,7 @@ function diag_command(cmd, addr)
        if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then
                luci.http.prepare_content("text/plain")
 
-               local util = io.popen(cmd % addr)
+               local util = io.popen(cmd % luci.util.shellquote(addr))
                if util then
                        while true do
                                local ln = util:read("*l")
@@ -408,21 +411,21 @@ function diag_command(cmd, addr)
 end
 
 function diag_ping(addr)
-       diag_command("ping -c 5 -W 1 %q 2>&1", addr)
+       diag_command("ping -c 5 -W 1 %s 2>&1", addr)
 end
 
 function diag_traceroute(addr)
-       diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr)
+       diag_command("traceroute -q 1 -w 1 -n %s 2>&1", addr)
 end
 
 function diag_nslookup(addr)
-       diag_command("nslookup %q 2>&1", addr)
+       diag_command("nslookup %s 2>&1", addr)
 end
 
 function diag_ping6(addr)
-       diag_command("ping6 -c 5 %q 2>&1", addr)
+       diag_command("ping6 -c 5 %s 2>&1", addr)
 end
 
 function diag_traceroute6(addr)
-       diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr)
+       diag_command("traceroute6 -q 1 -w 2 -n %s 2>&1", addr)
 end
index 22e1b7e..4471fd5 100644 (file)
@@ -14,7 +14,7 @@ function index()
        entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3)
        entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4)
        entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5)
-       entry({"admin", "status", "processes"}, cbi("admin_status/processes"), _("Processes"), 6)
+       entry({"admin", "status", "processes"}, form("admin_status/processes"), _("Processes"), 6)
 
        entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7)
 
@@ -62,7 +62,9 @@ end
 function action_bandwidth(iface)
        luci.http.prepare_content("application/json")
 
-       local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface)
+       local bwc = io.popen("luci-bwc -i %s 2>/dev/null"
+               % luci.util.shellquote(iface))
+
        if bwc then
                luci.http.write("[")
 
@@ -80,7 +82,9 @@ end
 function action_wireless(iface)
        luci.http.prepare_content("application/json")
 
-       local bwc = io.popen("luci-bwc -r %q 2>/dev/null" % iface)
+       local bwc = io.popen("luci-bwc -r %s 2>/dev/null"
+               % luci.util.shellquote(iface))
+
        if bwc then
                luci.http.write("[")
 
index 9c33d9c..ba317f9 100644 (file)
@@ -5,8 +5,8 @@
 module("luci.controller.admin.uci", package.seeall)
 
 function index()
-       local redir = luci.http.formvalue("redir", true) or
-         luci.dispatcher.build_url(unpack(luci.dispatcher.context.request))
+       local redir = luci.http.formvalue("redir", true)
+               or table.concat(luci.dispatcher.context.request, "/")
 
        entry({"admin", "uci"}, nil, _("Configuration"))
        entry({"admin", "uci", "changes"}, call("action_changes"), _("Changes"), 40).query = {redir=redir}
index 66d9942..fbde431 100644 (file)
@@ -115,7 +115,7 @@ s:taboption("advanced", Flag, "nonegcache",
 s:taboption("advanced", Value, "serversfile",
        translate("Additional servers file"),
        translate("This file may contain lines like 'server=/domain/1.2.3.4' or 'server=1.2.3.4' for"..
-               "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers."))
+               "domain-specific or full upstream <abbr title=\"Domain Name System\">DNS</abbr> servers."))
 
 s:taboption("advanced", Flag, "strictorder",
        translate("Strict order"),
@@ -212,6 +212,12 @@ cq.optional = true
 cq.datatype = "uinteger"
 cq.placeholder = 150
 
+cs = s:taboption("advanced", Value, "cachesize",
+       translate("Size of DNS query cache"),
+       translate("Number of cached DNS entries (max is 10000, 0 is no caching)"))
+cs.optional = true
+cs.datatype = "range(0,10000)"
+cs.placeholder = 150
 
 s:taboption("tftp", Flag, "enable_tftp",
        translate("Enable TFTP server")).optional = true
@@ -274,7 +280,7 @@ s.anonymous = true
 s.template = "cbi/tblsection"
 
 name = s:option(Value, "name", translate("Hostname"))
-name.datatype = "hostname"
+name.datatype = "hostname('strict')"
 name.rmempty  = true
 
 function name.write(self, section, value)
@@ -295,7 +301,7 @@ ip = s:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\
 ip.datatype = "or(ip4addr,'ignore')"
 
 time = s:option(Value, "leasetime", translate("Lease time"))
-time.rmempty  = true
+time.rmempty = true
 
 duid = s:option(Value, "duid", translate("<abbr title=\"The DHCP Unique Identifier\">DUID</abbr>"))
 duid.datatype = "and(rangelength(20,36),hexstring)"
index 89a73a5..b52dff1 100644 (file)
@@ -5,6 +5,7 @@
 m = Map("network", translate("Switch"), translate("The network ports on this device can be combined to several <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s in which computers can communicate directly with each other. <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network."))
 
 local fs = require "nixio.fs"
+local ut = require "luci.util"
 local nw = require "luci.model.network"
 local switches = { }
 
@@ -74,7 +75,7 @@ m.uci:foreach("network", "switch",
                end
 
                -- Parse some common switch properties from swconfig help output.
-               local swc = io.popen("swconfig dev %q help 2>/dev/null" % switch_name)
+               local swc = io.popen("swconfig dev %s help 2>/dev/null" % ut.shellquote(switch_name))
                if swc then
 
                        local is_port_attr = false
index c0bb380..a574d35 100644 (file)
@@ -63,7 +63,7 @@ function m.parse(map)
        Map.parse(map)
 
        if m:get(wdev:name(), "type") == "mac80211" and new_cc and new_cc ~= old_cc then
-               luci.sys.call("iw reg set %q" % new_cc)
+               luci.sys.call("iw reg set %s" % ut.shellquote(new_cc))
                luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless", arg[1]))
                return
        end
index d5d7828..88e0fff 100644 (file)
@@ -69,7 +69,7 @@ end
                                <% if querypat then %>
                                <div class="cbi-value">
                                        <%:Displaying only packages containing%> <strong>"<%=pcdata(query)%>"</strong>
-                                       <input type="button" onclick="location.href='?display=<%=pcdata(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" />
+                                       <input type="button" onclick="location.href='?display=<%=luci.http.urlencode(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" />
                                        <br style="clear:both" />
                                </div>
                                <% end %>
index c337360..6e725c8 100644 (file)
@@ -16,9 +16,9 @@
 <% end %>
 
 <div class="cbi-page-actions">
-       <% local r = luci.http.formvalue("redir"); if r and #r > 0 then %>
+       <% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %>
        <div style="float:left">
-               <form class="inline" method="get" action="<%=luci.util.pcdata(r)%>">
+               <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>">
                        <input class="cbi-button cbi-button-link" style="float:left; margin:0" type="submit" value="<%:Back%>" />
                </form>
        </div>
index 5da7281..20327ad 100644 (file)
        <p><strong><%:There are no pending changes to revert!%></strong></p>
 <% end %>
 
-<div class="cbi-page-actions">
-       <form class="inline" method="get" action="<%=luci.util.pcdata(luci.http.formvalue("redir"))%>">
-               <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" />
-       </form>
-</div>
+<% local node, url = luci.dispatcher.lookup(luci.http.formvalue("redir")); if url then %>
+       <div class="cbi-page-actions">
+               <form class="inline" method="get" action="<%=luci.util.pcdata(url)%>">
+                       <input class="cbi-button cbi-button-link" style="margin:0" type="submit" value="<%:Back%>" />
+               </form>
+       </div>
+<% end %>
 
 <%+footer%>
index 18be30b..9f017c9 100644 (file)
@@ -6,7 +6,7 @@
        <script type="text/javascript" src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js"></script>
        <script type="text/javascript" src="osm.js"></script>
 </head>
-<body onload="init();drawmap();" style="padding:0px; margin:0px">                              
+<body onload="init();drawmap();" style="padding:0px; margin:0px">
                <div id="map"></div>
                <div style="position:absolute; bottom:0%; width:100%; background:url('cbi/black_60.png'); font-size:10px; color:#fff;z-index:1000">
                        Map by <a href="http://www.openstreetmap.org" title="www.openstreetmap.org" style="color:#fff;" >openstreetmap.org</a>, License CC-BY-SA 
@@ -16,5 +16,4 @@
                                Longitude: <input id="osmlon" name="osmlon" type="text" size="20" style="font-size:10px;">
                        </span>
                </div>
-
 </body>
index e2291e5..adad750 100644 (file)
@@ -77,7 +77,7 @@ function index()
        page.order  = 10
 
        page        = node("admin", "freifunk", "basics", "profile_expert")
-       page.target = cbi("freifunk/profile_expert")
+       page.target = form("freifunk/profile_expert")
        page.title  = _("Profile (Expert)")
        page.order  = 20
 
index 759bb74..3326d57 100644 (file)
@@ -7,23 +7,45 @@ local pairs = pairs
 local print = print
 local pcall = pcall
 local table = table
+local type = type
+local tonumber = tonumber
 
 module "luci.controller.rpc"
 
-function index()
-       local function authenticator(validator, accs)
-               local auth = luci.http.formvalue("auth", true)
-               if auth then -- if authentication token was given
-                       local sdat = (luci.util.ubus("session", "get", { ubus_rpc_session = auth }) or { }).values
-                       if sdat then -- if given token is valid
-                               if sdat.user and luci.util.contains(accs, sdat.user) then
-                                       return sdat.user, auth
-                               end
-                       end
+
+local function session_retrieve(sid, allowed_users)
+       local util = require "luci.util"
+       local sdat = util.ubus("session", "get", {
+               ubus_rpc_session = sid
+       })
+
+       if type(sdat) == "table" and
+          type(sdat.values) == "table" and
+          type(sdat.values.token) == "string" and
+          type(sdat.values.secret) == "string" and
+          type(sdat.values.username) == "string" and
+          util.contains(allowed_users, sdat.values.username)
+       then
+               return sid, sdat.values
+       end
+
+       return nil
+end
+
+local function authenticator(validator, accs)
+       local auth = luci.http.formvalue("auth", true)
+               or luci.http.getcookie("sysauth")
+
+       if auth then -- if authentication token was given
+               local sid, sdat = session_retrieve(auth, accs)
+               if sdat then -- if given token is valid
+                       return sdat.username, sid
                end
                luci.http.status(403, "Forbidden")
        end
+end
 
+function index()
        local rpc = node("rpc")
        rpc.sysauth = "root"
        rpc.sysauth_authenticator = authenticator
@@ -43,39 +65,48 @@ function rpc_auth()
        local ltn12   = require "luci.ltn12"
        local util    = require "luci.util"
 
-       local loginstat
-
        local server = {}
        server.challenge = function(user, pass)
-               local sid, token, secret
-
                local config = require "luci.config"
-
-               if sys.user.checkpasswd(user, pass) then
-                       local sdat = util.ubus("session", "create", { timeout = config.sauth.sessiontime })
+               local login = util.ubus("session", "login", {
+                       username = user,
+                       password = pass,
+                       timeout  = tonumber(config.sauth.sessiontime)
+               })
+
+               if type(login) == "table" and
+                  type(login.ubus_rpc_session) == "string"
+               then
+                       util.ubus("session", "set", {
+                               ubus_rpc_session = login.ubus_rpc_session,
+                               values = {
+                                       token = sys.uniqueid(16),
+                                       secret = sys.uniqueid(16)
+                               }
+                       })
+
+                       local sid, sdat = session_retrieve(login.ubus_rpc_session, { user })
                        if sdat then
-                               sid = sdat.ubus_rpc_session
-                               token = sys.uniqueid(16)
-                               secret = sys.uniqueid(16)
-
-                               http.header("Set-Cookie", "sysauth="..sid.."; path=/")
-                               util.ubus("session", "set", {
-                                       ubus_rpc_session = sid,
-                                       values = {
-                                               user = user,
-                                               token = token,
-                                               secret = secret
-                                       }
-                               })
+                               return {
+                                       sid = sid,
+                                       token = sdat.token,
+                                       secret = sdat.secret
+                               }
                        end
                end
 
-               return sid and {sid=sid, token=token, secret=secret}
+               return nil
        end
 
        server.login = function(...)
                local challenge = server.challenge(...)
-               return challenge and challenge.sid
+               if challenge then
+                       http.header("Set-Cookie", 'sysauth=%s; path=%s' %{
+                               challenge.sid,
+                               http.getenv("SCRIPT_NAME")
+                       })
+                       return challenge.sid
+               end
        end
 
        http.prepare_content("application/json")
index 88dfe09..16245b8 100644 (file)
@@ -24,7 +24,7 @@ peeraddr.datatype = "ip4addr"
 
 ip6addr = s:taboption("general", Value, "ip6addr",
        translate("Local IPv6 address"),
-       translate("This is the local endpoint address assigned by the tunnel broker, it usually ends with <code>:2</code>"))
+       translate("This is the local endpoint address assigned by the tunnel broker, it usually ends with <code>...:2/64</code>"))
 
 ip6addr.datatype = "ip6addr"
 
index 78b98e0..4881535 100644 (file)
                        end
 
                        if ucichanges > 0 then
-                               write('<a class="label notice" href="%s?redir=%s">%s: %d</a>' %{
+                               write('<a class="uci_change_indicator label notice" href="%s?redir=%s">%s: %d</a>' %{
                                        url(category, 'uci/changes'),
-                                       http.urlencode(http.formvalue('redir') or REQUEST_URI),
+                                       http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")),
                                        translate('Unsaved Changes'),
                                        ucichanges
                                })
index 342a9d4..16ffc99 100644 (file)
@@ -205,7 +205,7 @@ if tree.nodes[category] and tree.nodes[category].ucidata then
 -%>
        <div id="savemenu">
                <% if ucic > 0 then %>
-                       <a class="warning" href="<%=controller%>/<%=category%>/uci/changes/?redir=<%=http.urlencode(http.formvalue("redir") or REQUEST_URI)%>"><%:Unsaved Changes%>: <%=ucic%></a>
+                       <a class="uci_change_indicator warning" href="<%=controller%>/<%=category%>/uci/changes/?redir=<%=http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/"))%>"><%:Unsaved Changes%>: <%=ucic%></a>
                <% end -%>
        </div>
 <% end %>
index 545c5fb..57bbaf6 100755 (executable)
@@ -253,9 +253,19 @@ header > .container > .brand {
     vertical-align: text-bottom;
 }
 
+.danger {
+    background-color: #FA8072 !important;
+    color: black;
+}
+
 .warning {
-    background-color: #FF7D60 !important;
-    color: #FFF;
+    background-color:  #F0E68C !important;
+    color: black;
+}
+
+.success {
+    background-color: #90EE90 !important;
+    color: black;
 }
 
 .errorbox,
@@ -1546,4 +1556,4 @@ body.lang_pl.node-main-login .cbi-value-title {
     .cbi-value-field .cbi-input-select {
         min-width: 25rem;
     }
-}
\ No newline at end of file
+}
index d84fd27..0aca882 100644 (file)
                        end
 
                        if ucichanges > 0 then
-                               write('<a class="label notice" href="%s?redir=%s">%s: %d</a>' %{
+                               write('<a class="uci_change_indicator label notice" href="%s?redir=%s">%s: %d</a>' %{
                                        url(category, 'uci/changes'),
-                                       http.urlencode(http.formvalue('redir') or REQUEST_URI),
+                                       http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")),
                                        translate('Unsaved Changes'),
                                        ucichanges
                                })
index ae348f3..a560014 100644 (file)
                                end
                        end
 
-                       write('<div id="savemenu">')
-
                        if ucic > 0 then
-                               write('<a class="warning" href="%s?redir=%s">%s: %d</a>' %{
+                               write('<div id="savemenu" class="uci_change_indicator"><a class="warning" href="%s?redir=%s">%s: %d</a></div>' %{
                                        url(category, 'uci/changes'),
-                                       http.urlencode(http.formvalue('redir') or REQUEST_URI),
+                                       http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")),
                                        translate('Unsaved Changes'),
                                        ucic
                                })
-                       else
-                               write('<a href="#">%s: 0</a>' %{
-                                       translate('Unsaved Changes')
-                               })
                        end
-
-                       write('</div>')
                end
        end
 -%>