Merge pull request #304 from nmav/ocserv-crypt
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 10 Mar 2015 17:55:46 +0000 (18:55 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Tue, 10 Mar 2015 17:55:46 +0000 (18:55 +0100)
luci-app-ocserv: uclibc's crypt() doesn't support sha2crypt

157 files changed:
applications/luci-app-asterisk/Makefile
applications/luci-app-coovachilli/luasrc/model/cbi/coovachilli_network.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-ddns/luasrc/model/cbi/ddns/global.lua [new file with mode: 0644]
applications/luci-app-ddns/luasrc/model/cbi/ddns/hints.lua
applications/luci-app-ddns/luasrc/model/cbi/ddns/overview.lua
applications/luci-app-ddns/luasrc/tools/ddns.lua
applications/luci-app-ddns/luasrc/view/ddns/detail_lvalue.htm
applications/luci-app-ddns/luasrc/view/ddns/detail_value.htm
applications/luci-app-ddns/luasrc/view/ddns/global_value.htm [new file with mode: 0644]
applications/luci-app-ddns/luasrc/view/ddns/overview_startstop.htm
applications/luci-app-ddns/luasrc/view/ddns/overview_status.htm
applications/luci-app-ddns/luasrc/view/ddns/system_status.htm
applications/luci-app-ddns/po/de/ddns.po
applications/luci-app-ddns/po/templates/ddns.pot
applications/luci-app-firewall/luasrc/view/firewall/cbi_addforward.htm
applications/luci-app-ocserv/luasrc/controller/ocserv.lua
applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua
applications/luci-app-ocserv/luasrc/model/cbi/ocserv/users.lua
applications/luci-app-olsr-services/luasrc/view/freifunk-services/services.htm
applications/luci-app-olsr/luasrc/controller/olsr.lua
applications/luci-app-privoxy/Makefile [new file with mode: 0644]
applications/luci-app-privoxy/luasrc/controller/privoxy.lua [new file with mode: 0755]
applications/luci-app-privoxy/luasrc/model/cbi/privoxy.lua [new file with mode: 0755]
applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm [new file with mode: 0755]
applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm [new file with mode: 0644]
applications/luci-app-privoxy/po/de/privoxy.po [new file with mode: 0644]
applications/luci-app-privoxy/po/templates/privoxy.pot [new file with mode: 0644]
applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy [new file with mode: 0755]
applications/luci-app-siitwizard/luasrc/model/cbi/siitwizard.lua
applications/luci-app-splash/luasrc/controller/splash/splash.lua
applications/luci-app-splash/luasrc/view/admin_status/splash.htm
applications/luci-app-splash/root/usr/sbin/luci-splash
applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua
applications/luci-app-upnp/luasrc/controller/upnp.lua
build/luadoc/doc.lua [new file with mode: 0755]
build/luadoc/luadoc/config.lua [new file with mode: 0644]
build/luadoc/luadoc/doclet/debug.lua [new file with mode: 0644]
build/luadoc/luadoc/doclet/formatter.lua [new file with mode: 0644]
build/luadoc/luadoc/doclet/html.lua [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/constant.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/file.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/function.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/index.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/luadoc.css [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/menu.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/module.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/html/table.lp [new file with mode: 0644]
build/luadoc/luadoc/doclet/raw.lua [new file with mode: 0644]
build/luadoc/luadoc/init.lua [new file with mode: 0644]
build/luadoc/luadoc/lp.lua [new file with mode: 0644]
build/luadoc/luadoc/taglet/standard.lua [new file with mode: 0644]
build/luadoc/luadoc/taglet/standard/tags.lua [new file with mode: 0644]
build/luadoc/luadoc/util.lua [new file with mode: 0644]
build/makedocs.sh
build/zoneinfo2lua.pl
contrib/luadoc/Makefile [deleted file]
contrib/luadoc/hostfiles/bin/luadoc [deleted file]
contrib/luadoc/lua/luadoc/config.lua [deleted file]
contrib/luadoc/lua/luadoc/doclet/debug.lua [deleted file]
contrib/luadoc/lua/luadoc/doclet/formatter.lua [deleted file]
contrib/luadoc/lua/luadoc/doclet/html.lua [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/constant.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/file.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/function.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/index.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/luadoc.css [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/menu.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/module.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/html/table.lp [deleted file]
contrib/luadoc/lua/luadoc/doclet/raw.lua [deleted file]
contrib/luadoc/lua/luadoc/init.lua [deleted file]
contrib/luadoc/lua/luadoc/lp.lua [deleted file]
contrib/luadoc/lua/luadoc/taglet/standard.lua [deleted file]
contrib/luadoc/lua/luadoc/taglet/standard/tags.lua [deleted file]
contrib/luadoc/lua/luadoc/util.lua [deleted file]
contrib/package/community-profiles/files/etc/config/profile_aachen [deleted file]
contrib/package/community-profiles/files/etc/config/profile_augsburg
contrib/package/community-profiles/files/etc/config/profile_demo
contrib/package/community-profiles/files/etc/config/profile_neuss [deleted file]
contrib/package/community-profiles/files/etc/config/profile_potsdam
contrib/package/freifunk-common/files/etc/config/freifunk
contrib/package/meshwizard/Makefile
contrib/package/meshwizard/files/usr/bin/meshwizard/helpers/setup_wifi.sh
libs/luci-lib-httpclient/luasrc/httpclient.lua
libs/luci-lib-ip/Makefile [new file with mode: 0644]
libs/luci-lib-ip/src/Makefile [new file with mode: 0644]
libs/luci-lib-ip/src/ip.c [new file with mode: 0644]
libs/luci-lib-ip/src/ip.luadoc [new file with mode: 0644]
libs/luci-lib-json/luasrc/json.lua
libs/luci-lib-json/luasrc/json.luadoc [new file with mode: 0644]
libs/luci-lib-jsonc/Makefile [new file with mode: 0644]
libs/luci-lib-jsonc/src/Makefile [new file with mode: 0644]
libs/luci-lib-jsonc/src/jsonc.c [new file with mode: 0644]
libs/luci-lib-jsonc/src/jsonc.luadoc [new file with mode: 0644]
libs/luci-lib-nixio/docsrc/CHANGELOG.lua
libs/luci-lib-nixio/docsrc/README.lua
libs/luci-lib-nixio/src/Makefile
libs/luci-lib-rpcc/luasrc/rpcc.lua
libs/luci-lib-rpcc/luasrc/rpcc.luadoc [new file with mode: 0644]
libs/luci-lib-rpcc/luasrc/rpcc/ruci.lua
libs/luci-lib-rpcc/luasrc/rpcc/ruci.luadoc [new file with mode: 0644]
luci.mk
modules/luci-base/Makefile
modules/luci-base/luasrc/dispatcher.lua
modules/luci-base/luasrc/dispatcher.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/http.lua
modules/luci-base/luasrc/http.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/http/protocol.lua
modules/luci-base/luasrc/http/protocol.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/http/protocol/conditionals.lua
modules/luci-base/luasrc/http/protocol/conditionals.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/http/protocol/date.lua
modules/luci-base/luasrc/http/protocol/date.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/http/protocol/mime.lua
modules/luci-base/luasrc/http/protocol/mime.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/i18n.lua
modules/luci-base/luasrc/i18n.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/ip.lua [deleted file]
modules/luci-base/luasrc/ltn12.lua
modules/luci-base/luasrc/model/ipkg.lua
modules/luci-base/luasrc/model/ipkg.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/model/uci.lua
modules/luci-base/luasrc/model/uci.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/sys.lua
modules/luci-base/luasrc/sys.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/sys/iptparser.lua
modules/luci-base/luasrc/sys/iptparser.luadoc [new file with mode: 0644]
modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua
modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua
modules/luci-base/luasrc/tools/webadmin.lua
modules/luci-base/luasrc/util.lua
modules/luci-base/luasrc/util.luadoc [new file with mode: 0644]
modules/luci-mod-admin-full/luasrc/controller/admin/index.lua
modules/luci-mod-admin-full/luasrc/controller/admin/system.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/routes.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview.htm
modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm
modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua
modules/luci-mod-freifunk/luasrc/view/freifunk/public_status.htm
protocols/luci-proto-ipv6/Makefile
protocols/luci-proto-ipv6/luasrc/model/cbi/admin_network/proto_aiccu.lua [new file with mode: 0644]
protocols/luci-proto-ipv6/luasrc/model/network/proto_aiccu.lua [new file with mode: 0644]
protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/mobile.css
themes/luci-theme-bootstrap/root/etc/uci-defaults/luci-theme-bootstrap
themes/luci-theme-freifunk-bno/root/etc/uci-defaults/luci-theme-freifunk-bno
themes/luci-theme-freifunk-generic/luasrc/view/themes/freifunk-generic/header.htm
themes/luci-theme-freifunk-generic/root/etc/uci-defaults/luci-theme-freifunk-generic
themes/luci-theme-openwrt/root/etc/uci-defaults/luci-theme-openwrt

index bb4d415..f2f3cd1 100644 (file)
@@ -6,7 +6,7 @@
 
 include $(TOPDIR)/rules.mk
 
-LUCI_TITLE:=LuCI Support for AHCPd
+LUCI_TITLE:=LuCI Support for Asterisk
 LUCI_DEPENDS:=+ahcpd
 
 include ../../luci.mk
index e1a084a..025bc17 100644 (file)
@@ -2,8 +2,8 @@
 -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
 -- Licensed to the public under the Apache License 2.0.
 
-require("luci.sys")
-require("luci.ip")
+local sys = require"luci.sys"
+local ip  = require "luci.ip"
 
 m = Map("coovachilli")
 
@@ -16,8 +16,8 @@ s1:option( Value, "tundev" ).optional = true
 s1:option( Value, "txqlen" ).optional = true
 
 net = s1:option( Value, "net" )
-for _, route in ipairs(luci.sys.net.routes()) do
-       if route.device ~= "lo" and route.dest:prefix() < 32 then
+for _, route in ipairs(ip.routes({ family = 4, type = 1 })) do
+       if route.dest:prefix() > 0 and route.dest:prefix() < 32 then
                net:value( route.dest:string() )
        end
 end
@@ -41,7 +41,7 @@ s2 = m:section(TypedSection, "dhcp")
 s2.anonymous = true
 
 dif = s2:option( Value, "dhcpif" )
-for _, nif in ipairs(luci.sys.net.devices()) do
+for _, nif in ipairs(sys.net.devices()) do
        if nif ~= "lo" then dif:value(nif) end
 end
 
index d116f06..f20b49e 100644 (file)
@@ -6,17 +6,33 @@
 
 include $(TOPDIR)/rules.mk
 
-LUCI_TITLE:=LuCI Support for Dynamic DNS (ddns-scripts)
-LUCI_DEPENDS:=+ddns-scripts +luci-mod-admin-full
-
 PKG_NAME:=luci-app-ddns
-PKG_VERSION:=2.1.0
-PKG_RELEASE:=4
-PKG_LICENSE:=Apache-2.0
-PKGARCH:=all
 
+# Version == major.minor.patch
+# increase on new functionality (minor) or patches (patch)
+PKG_VERSION:=2.2.1
+
+# Release == build
+# increase on changes of translation files
+PKG_RELEASE:=1
+
+PKG_LICENSE:=Apache-2.0
 PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
 
-include ../../luci.mk
+# LuCI specific settings
+LUCI_TITLE:=LuCI Support for Dynamic DNS Client (ddns-scripts)
+LUCI_DEPENDS:=+luci-mod-admin-full +ddns-scripts
+LUCI_PKGARCH:=all
+
+define Package/$(PKG_NAME)/config
+# shown in make menuconfig <Help>
+help
+       $(LUCI_TITLE)
+       .
+       Version: $(PKG_VERSION)-$(PKG_RELEASE)
+       $(PKG_MAINTAINER)
+endef
+
+include $(TOPDIR)/feeds/luci/luci.mk
 
 # call BuildPackage - OpenWrt buildroot signature
index 3cd52e5..0b82021 100644 (file)
@@ -15,25 +15,28 @@ local SYS  = require "luci.sys"
 local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
 local UTIL = require "luci.util"
 
-local luci_ddns_version = "2.1.0-4"    -- luci-app-ddns / openwrt Makefile compatible version
-local ddns_scripts_min  = "2.1.0-3"    -- minimum version of ddns-scripts required
+DDNS_MIN = "2.2.0-1"   -- minimum version of service required
 
 function index()
-       -- no services_ipv6 file or no dynamic_dns_lucihelper.sh
-       -- do NOT start
-       if not nixio.fs.access("/usr/lib/ddns/services_ipv6") 
-       or not nixio.fs.access("/usr/lib/ddns/dynamic_dns_lucihelper.sh") then
+       local nxfs      = require "nixio.fs"            -- global definitions not available
+       local sys       = require "luci.sys"            -- in function index()
+       local ddns      = require "luci.tools.ddns"     -- ddns multiused functions
+       local verinst   = ddns.ipkg_ver_installed("ddns-scripts")
+       local verok     = ddns.ipkg_ver_compare(verinst, ">=", "2.0.0-0")
+       -- do NOT start it not ddns-scripts version 2.x
+       if not verok then
                return
        end
        -- no config create an empty one
-       if not nixio.fs.access("/etc/config/ddns") then
-               nixio.fs.writefile("/etc/config/ddns", "")
+       if not nxfs.access("/etc/config/ddns") then
+               nxfs.writefile("/etc/config/ddns", "")
        end
 
        entry( {"admin", "services", "ddns"}, cbi("ddns/overview"), _("Dynamic DNS"), 59)
        entry( {"admin", "services", "ddns", "detail"}, cbi("ddns/detail"), nil ).leaf = true
        entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints",
                {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true
+       entry( {"admin", "services", "ddns", "global"}, cbi("ddns/global"), nil ).leaf = true
        entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true
        entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true
        entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
@@ -44,17 +47,11 @@ local function _get_status()
        local uci        = UCI.cursor()
        local service    = SYS.init.enabled("ddns") and 1 or 0
        local url_start  = DISP.build_url("admin", "system", "startup")
-       local luci_build = DDNS.ipkg_version("luci-app-ddns").version
-       local ddns_act   = DDNS.ipkg_version("ddns-scripts").version
        local data       = {}   -- Array to transfer data to javascript
 
        data[#data+1]   = {
                enabled    = service,           -- service enabled
                url_up     = url_start,         -- link to enable DDS (System-Startup)
-               luci_ver   = luci_ddns_version, -- luci-app-ddns / openwrt Makefile compatible version
-               luci_build = luci_build,        -- installed luci build
-               script_min = ddns_scripts_min,  -- minimum version of ddns-scripts needed
-               script_ver = ddns_act           -- installed ddns-scripts
        }
 
        uci:foreach("ddns", "service", function (s)
@@ -63,8 +60,8 @@ local function _get_status()
                -- and enabled state
                local section   = s[".name"]
                local enabled   = tonumber(s["enabled"]) or 0
-               local datelast  = "_empty_"     -- formated date of last update
-               local datenext  = "_empty_"     -- formated date of next update
+               local datelast  = "_empty_"     -- formatted date of last update
+               local datenext  = "_empty_"     -- formatted date of next update
 
                -- get force seconds
                local force_seconds = DDNS.calc_seconds(
@@ -94,7 +91,7 @@ local function _get_status()
                end
 
                -- process running but update needs to happen
-               -- problems it force_seconds > uptime
+               -- problems if force_seconds > uptime
                force_seconds = (force_seconds > uptime) and uptime or force_seconds
                if pid > 0 and ( lasttime + force_seconds - uptime ) <= 0 then
                        datenext = "_verify_"
@@ -107,7 +104,7 @@ local function _get_status()
                elseif pid == 0 and enabled == 0 then
                        datenext  = "_disabled_"
 
-               -- no process running and NOT
+               -- no process running and enabled
                elseif pid == 0 and enabled ~= 0 then
                        datenext = "_stopped_"
                end
@@ -153,11 +150,11 @@ end
 -- called by XHR.get from detail_logview.htm
 function logread(section)
        -- read application settings
-       local uci         = UCI.cursor()
-       local log_dir     = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
-       local lfile=log_dir .. "/" .. section .. ".log"
+       local uci       = UCI.cursor()
+       local log_dir   = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
+       local lfile     = log_dir .. "/" .. section .. ".log"
+       local ldata     = NXFS.readfile(lfile)
 
-       local ldata=NXFS.readfile(lfile)
        if not ldata or #ldata == 0 then
                ldata="_nodata_"
        end
@@ -168,10 +165,10 @@ end
 -- called by XHR.get from overview_status.htm
 function startstop(section, enabled)
        local uci  = UCI.cursor()
+       local pid  = DDNS.get_pid(section)
        local data = {}         -- Array to transfer data to javascript
 
        -- if process running we want to stop and return
-       local pid = DDNS.get_pid(section)
        if pid > 0 then
                local tmp = NX.kill(pid, 15)    -- terminate
                NX.nanosleep(2) -- 2 second "show time"
@@ -182,7 +179,7 @@ function startstop(section, enabled)
                return
        end
 
-       -- read uncommited changes
+       -- read uncommitted changes
        -- we don't save and commit data from other section or other options
        -- only enabled will be done
        local exec        = true
@@ -210,9 +207,9 @@ function startstop(section, enabled)
        end
 
        -- we can not execute because other
-       -- uncommited changes pending, so exit here
+       -- uncommitted changes pending, so exit here
        if not exec then
-               HTTP.write("_uncommited_")
+               HTTP.write("_uncommitted_")
                return
        end
 
@@ -238,14 +235,3 @@ function status()
        HTTP.prepare_content("application/json")
        HTTP.write_json(data)
 end
-
--- check if installed ddns-scripts version < required version
-function update_needed()
-       local sver = DDNS.ipkg_version("ddns-scripts")
-       local rver = UTIL.split(ddns_scripts_min, "[%.%-]", nil, true)
-       return (sver.major < (tonumber(rver[1]) or 0))
-           or (sver.minor < (tonumber(rver[2]) or 0))
-           or (sver.patch < (tonumber(rver[3]) or 0))
-           or (sver.build < (tonumber(rver[4]) or 0))
-end
-
index 057b8c8..40a66ef 100644 (file)
@@ -1,11 +1,11 @@
 -- Copyright 2008 Steven Barth <steven@midlink.org>
 -- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
 -- Copyright 2013 Manuel Munz <freifunk at somakoma dot de>
--- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Copyright 2014-2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
 -- Licensed to the public under the Apache License 2.0.
 
 local NX   = require "nixio"
-local FS   = require "nixio.fs"
+local NXFS = require "nixio.fs"
 local SYS  = require "luci.sys"
 local UTIL = require "luci.util"
 local DISP = require "luci.dispatcher"
@@ -14,21 +14,21 @@ local DTYP = require "luci.cbi.datatypes"
 local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
 
 -- takeover arguments -- #######################################################
-section = arg[1]
+local section  = arg[1]
 
 -- check supported options -- ##################################################
 -- saved to local vars here because doing multiple os calls slow down the system
-has_ipv6   = DDNS.check_ipv6() -- IPv6 support
-has_ssl    = DDNS.check_ssl()  -- HTTPS support
-has_proxy  = DDNS.check_proxy()        -- Proxy support
-has_dnstcp = DDNS.check_bind_host()    -- DNS TCP support
-has_force  = has_ssl and has_dnstcp            -- Force IP Protocoll
+local has_ipv6   = DDNS.check_ipv6()   -- IPv6 support
+local has_ssl    = DDNS.check_ssl()    -- HTTPS support
+local has_proxy  = DDNS.check_proxy()  -- Proxy support
+local has_dnstcp = DDNS.check_bind_host()      -- DNS TCP support
+local has_force  = has_ssl and has_dnstcp      -- Force IP Protocoll
 
 -- html constants -- ###########################################################
-font_red = "<font color='red'>"
-font_off = "</font>"
-bold_on  = "<strong>"
-bold_off = "</strong>"
+local font_red = "<font color='red'>"
+local font_off = "</font>"
+local bold_on  = "<strong>"
+local bold_off = "</strong>"
 
 -- error text constants -- #####################################################
 err_ipv6_plain = translate("IPv6 not supported") .. " - " ..
@@ -136,7 +136,10 @@ log_dir = m.uci:get(m.config, "global", "log_dir") or "/var/log/ddns"
 -- cbi-section definition -- ###################################################
 ns = m:section( NamedSection, section, "service",
        translate("Details for") .. ([[: <strong>%s</strong>]] % section),
-       translate("Configure here the details for selected Dynamic DNS service") )
+       translate("Configure here the details for selected Dynamic DNS service.")
+       .. [[<br /><a href="http://wiki.openwrt.org/doc/uci/ddns#version_1x" target="_blank">]]
+       .. translate("For detailed information about parameter settings look here.")
+       .. [[</a>]] )
 ns.instance = section  -- arg [1]
 ns:tab("basic", translate("Basic Settings"), nil )
 ns:tab("advanced", translate("Advanced Settings"), nil )
@@ -344,7 +347,7 @@ function ush.validate(self, value)
                end
        elseif (#url > 0) then
                return nil, err_tab_basic(self) .. translate("either url or script could be set")
-       elseif not FS.access(value) then
+       elseif not NXFS.access(value) then
                return nil, err_tab_basic(self) .. translate("File not found")
        end
        return value
@@ -765,7 +768,7 @@ function ips.validate(self, value)
        if (usev6:formvalue(section) == "0" and src4:formvalue(section) ~= "script")
        or (usev6:formvalue(section) == "1" and src6:formvalue(section) ~= "script") then
                return ""
-       elseif not value or not (#value > 0) or not FS.access(split[1], "x") then
+       elseif not value or not (#value > 0) or not NXFS.access(split[1], "x") then
                return nil, err_tab_adv(self) ..
                        translate("not found or not executable - Sample: '/path/to/script.sh'")
        else
@@ -855,6 +858,34 @@ function eif6.write(self, section, value)
        end
 end
 
+-- IPv4/IPv6 - bind_network -- #################################################
+if has_ssl or ( ( m:get(section, "bind_network") or "" ) ~= "" ) then
+       bnet = ns:taboption("advanced", ListValue, "bind_network",
+               translate("Bind Network") )
+       bnet:depends("ipv4_source", "web")
+       bnet:depends("ipv6_source", "web")
+       bnet.rmempty = true
+       bnet.default = ""
+       bnet:value("", translate("-- default --"))
+       WADM.cbi_add_networks(bnet)
+       function bnet.cfgvalue(self, section)
+               local value = AbstractValue.cfgvalue(self, section)
+               if not has_ssl and value ~= "" then
+                       self.description = bold_on .. font_red ..
+                               translate("Binding to a specific network not supported") .. font_off .. "<br />" ..
+                               translate("please set to 'default'") .. " !" .. bold_off
+               else
+                       self.description = translate("OPTIONAL: Network to use for communication") ..
+                               "<br />" .. translate("Casual users should not change this setting")
+               end
+               return value
+       end
+       function bnet.validate(self, value)
+               if (value ~= "" and has_ssl ) or value == "" then return value end
+               return nil, err_tab_adv(self) .. translate("Binding to a specific network not supported") .. " !"
+       end
+end
+
 -- IPv4 + IPv6 - force_ipversion (NEW) -- ######################################
 -- optional to force wget/curl and host to use only selected IP version
 -- command parameter "-4" or "-6"
@@ -1198,7 +1229,7 @@ lv.inputtitle = translate("Read / Reread log file")
 lv.rows = 50
 function lv.cfgvalue(self, section)
        local lfile=log_dir .. "/" .. section .. ".log"
-       if FS.access(lfile) then
+       if NXFS.access(lfile) then
                return lfile .. "\n" .. translate("Please press [Read] button")
        end
        return lfile .. "\n" .. translate("File not found or empty")
diff --git a/applications/luci-app-ddns/luasrc/model/cbi/ddns/global.lua b/applications/luci-app-ddns/luasrc/model/cbi/ddns/global.lua
new file mode 100644 (file)
index 0000000..e171873
--- /dev/null
@@ -0,0 +1,156 @@
+-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed to the public under the Apache License 2.0.
+
+local NX   = require "nixio"
+local NXFS = require "nixio.fs"
+local DISP = require "luci.dispatcher"
+local SYS  = require "luci.sys"
+local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
+
+-- cbi-map definition -- #######################################################
+local m = Map("ddns")
+
+-- first need to close <a> from cbi map template our <a> closed by template
+m.title = [[</a><a href="]] .. DISP.build_url("admin", "services", "ddns") .. [[">]] 
+       .. translate("Dynamic DNS")
+
+m.description = translate("Dynamic DNS allows that your router can be reached with " ..
+                       "a fixed hostname while having a dynamically changing IP address.")
+
+m.redirect = DISP.build_url("admin", "services", "ddns")
+
+function m.commit_handler(self)
+       if self.changed then    -- changes ?
+               os.execute("/etc/init.d/ddns reload &") -- reload configuration
+       end
+end
+
+-- cbi-section definition -- ###################################################
+local ns = m:section( NamedSection, "global", "ddns",
+       translate("Global Settings"),
+       translate("Configure here the details for all Dynamic DNS services including this LuCI application.") 
+       .. [[<br /><strong>]]
+       .. translate("It is NOT recommended for casual users to change settings on this page.")
+       .. [[</strong><br />]]
+       .. [[<a href="http://wiki.openwrt.org/doc/uci/ddns#version_2x1" target="_blank">]]
+       .. translate("For detailed information about parameter settings look here.")
+       .. [[</a>]]
+
+-- section might not exist
+function ns.cfgvalue(self, section)
+       if not self.map:get(section) then
+               self.map:set(section, nil, self.sectiontype)
+       end
+       return self.map:get(section)
+end
+
+-- allow_local_ip  -- ##########################################################
+local ali      = ns:option(Flag, "allow_local_ip")
+ali.title      = translate("Allow non-public IP's")
+ali.description = translate("Non-public and by default blocked IP's") .. ":"
+               .. [[<br /><strong>IPv4: </strong>]]
+               .. "0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16"
+               .. [[<br /><strong>IPv6: </strong>]]
+               .. "::/32, f000::/4"
+ali.reempty    = true
+ali.default    = "0"
+function ali.parse(self, section)
+       DDNS.flag_parse(self, section)
+end
+function ali.validate(self, value)
+       if value == self.default then
+               return "" -- default = empty
+       end
+       return value
+end
+
+-- date_format  -- #############################################################
+local df       = ns:option(Value, "date_format")
+df.title       = translate("Date format")
+df.description = [[<a href="http://www.cplusplus.com/reference/ctime/strftime/" target="_blank">]]
+               .. translate("For supported codes look here") 
+               .. [[</a>]]
+df.template    = "ddns/global_value"
+df.rmempty     = true
+df.default     = "%F %R"
+df.date_string = ""
+function df.cfgvalue(self, section)
+       local value = AbstractValue.cfgvalue(self, section) or self.default
+       local epoch = os.time()
+       self.date_string = DDNS.epoch2date(epoch, value)
+       return value
+end
+function df.validate(self, value)
+       if value == self.default then
+               return "" -- default = empty
+       end
+       return value
+end
+
+-- run_dir  -- #################################################################
+local rd       = ns:option(Value, "run_dir")
+rd.title       = translate("Status directory")
+rd.description = translate("Directory contains PID and other status information for each running section")
+rd.rmempty     = true
+rd.default     = "/var/run/ddns"
+function rd.validate(self, value)
+       if value == self.default then
+               return "" -- default = empty
+       end
+       return value
+end
+
+-- log_dir  -- #################################################################
+local ld       = ns:option(Value, "log_dir")
+ld.title       = translate("Log directory")
+ld.description = translate("Directory contains Log files for each running section")
+ld.rmempty     = true
+ld.default     = "/var/log/ddns"
+function ld.validate(self, value)
+       if value == self.default then
+               return "" -- default = empty
+       end
+       return value
+end
+
+-- log_lines  -- ###############################################################
+local ll       = ns:option(Value, "log_lines")
+ll.title       = translate("Log length")
+ll.description = translate("Number of last lines stored in log files")
+ll.rmempty     = true
+ll.default     = "250"
+ll.datatype    = "and(uinteger,min(1))"
+function ll.validate(self, value)
+       local n = tonumber(value)
+       if not n or math.floor(n) ~= n or n < 1 then
+               return nil, self.title .. ": " .. translate("minimum value '1'")
+       end
+       if value == self.default then
+               return "" -- default = empty
+       end
+       return value
+end
+
+-- use_curl  -- ################################################################
+if (SYS.call([[ grep -i "\+ssl" /usr/bin/wget >/dev/null 2>&1 ]]) == 0) 
+and NXFS.access("/usr/bin/curl") then
+       local pc        = ns:option(Flag, "use_curl")
+       pc.title        = translate("Use cURL")
+       pc.description  = translate("If both cURL and GNU Wget are installed, Wget is used by default.")
+               .. [[<br />]]
+               .. translate("To use cURL activate this option.")
+       pc.orientation  = "horizontal"
+       pc.rmempty      = true
+       pc.default      = "0"
+       function pc.parse(self, section)
+               DDNS.flag_parse(self, section)
+       end
+       function pc.validate(self, value)
+               if value == self.default then
+                       return "" -- default = empty
+               end
+               return value
+       end
+end
+
+return m
index 15da028..ff7aa7a 100644 (file)
@@ -8,10 +8,11 @@ local DDNS = require "luci.tools.ddns"                -- ddns multiused functions
 
 -- check supported options -- ##################################################
 -- saved to local vars here because doing multiple os calls slow down the system
-has_ssl     = DDNS.check_ssl()         -- HTTPS support
+has_ssl     = DDNS.check_ssl()         -- HTTPS support and --bind-network / --interface
 has_proxy   = DDNS.check_proxy()       -- Proxy support
 has_dnstcp  = DDNS.check_bind_host()   -- DNS TCP support
-need_update = CTRL.update_needed()     -- correct ddns-scripts version
+-- correct ddns-scripts version
+need_update = DDNS.ipkg_ver_compare(DDNS.ipkg_ver_installed("ddns-scripts"), "<<", CTRL.DDNS_MIN)
 
 -- html constants
 font_red = [[<font color="red">]]
@@ -87,6 +88,22 @@ if not has_ssl then
                        translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")
 end
 
+-- No bind_network
+if not has_ssl then
+       local dv = s:option(DummyValue, "_no_bind_network")
+       dv.titleref = DISP.build_url("admin", "system", "packages")
+       dv.rawhtml  = true
+       dv.title = bold_on ..
+               translate("Binding to a specific network not supported") .. bold_off
+       dv.value = translate("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") ..
+                       "<br />- " ..
+                       translate("You should install GNU Wget with SSL or cURL package.") ..
+                       "<br />- " ..
+                       translate("GNU Wget will use the IP of given network, cURL will use the physical interface.") ..
+                       "<br />- " ..
+                       translate("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")
+end
+
 -- cURL without proxy support
 if has_ssl and not has_proxy then
        local dv = s:option(DummyValue, "_no_proxy")
index 2944ec5..9e8df2d 100644 (file)
@@ -14,7 +14,8 @@ show_hints = not (DDNS.check_ipv6()           -- IPv6 support
                and DDNS.check_proxy()          -- Proxy support
                and DDNS.check_bind_host()      -- DNS TCP support
                )
-need_update = CTRL.update_needed()             -- correct ddns-scripts version
+-- correct ddns-scripts version
+need_update = DDNS.ipkg_ver_compare(DDNS.ipkg_ver_installed("ddns-scripts"), "<<", CTRL.DDNS_MIN)
 
 -- html constants
 font_red = [[<font color="red">]]
@@ -26,10 +27,17 @@ bold_off = [[</strong>]]
 m = Map("ddns")
 
 -- first need to close <a> from cbi map template our <a> closed by template
---m.title = [[</a><a href="javascript:alert(']] .. CTRL.show_versions() ..[[')">]] ..
---             translate("Dynamic DNS")
-m.title = [[</a><a href="#" onclick="onclick_maptitle();">]] ..
-               translate("Dynamic DNS")
+m.title        = [[</a><a href="javascript:alert(']]
+               .. translate("Version Information")
+               .. [[\n\nluci-app-ddns]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. DDNS.ipkg_ver_installed("luci-app-ddns")
+               .. [[\n\nddns-scripts ]] .. translate("required") .. [[:]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.DDNS_MIN .. [[ ]] .. translate("or higher")
+               .. [[\n\nddns-scripts ]] .. translate("installed") .. [[:]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. DDNS.ipkg_ver_installed("ddns-scripts")
+               .. [[\n\n]]
+       .. [[')">]]
+       .. translate("Dynamic DNS")
 
 m.description = translate("Dynamic DNS allows that your router can be reached with " ..
                        "a fixed hostname while having a dynamically changing " ..
@@ -99,9 +107,13 @@ end
 -- TableSection definition -- ##################################################
 ts = m:section( TypedSection, "service",
        translate("Overview"),
-       translate("Below is a list of configured DDNS configurations and their current state." .. "<br />" ..
-               "If you want to send updates for IPv4 and IPv6 you need to define two separate Configurations " ..
-               "i.e. 'myddns_ipv4' and 'myddns_ipv6'") )
+       translate("Below is a list of configured DDNS configurations and their current state.") 
+       .. "<br />" 
+       .. translate("If you want to send updates for IPv4 and IPv6 you need to define two separate Configurations " 
+               .. "i.e. 'myddns_ipv4' and 'myddns_ipv6'") 
+       .. "<br />" 
+       .. [[<a href="]] .. DISP.build_url("admin", "services", "ddns", "global") .. [[">]]
+       .. translate("To change global settings click here") .. [[</a>]] )
 ts.sectionhead = translate("Configuration")
 ts.template = "cbi/tblsection"
 ts.addremove = true
index 5c8ced5..6d53931 100644 (file)
@@ -35,7 +35,7 @@ end
 
 -- check if Wget with SSL support or cURL installed
 function check_ssl()
-       if (SYS.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
+       if (SYS.call([[ grep -i "\+ssl" /usr/bin/wget >/dev/null 2>&1 ]]) == 0) then
                return true
        else
                return NXFS.access("/usr/bin/curl")
@@ -45,12 +45,12 @@ end
 -- check if Wget with SSL or cURL with proxy support installed
 function check_proxy()
        -- we prefere GNU Wget for communication
-       if (SYS.call([[ grep -iq "\+ssl" /usr/bin/wget 2>/dev/null ]]) == 0) then
+       if (SYS.call([[ grep -i "\+ssl" /usr/bin/wget >/dev/null 2>&1 ]]) == 0) then
                return true
 
        -- if not installed cURL must support proxy
        elseif NXFS.access("/usr/bin/curl") then
-               return (SYS.call([[ grep -iq all_proxy /usr/lib/libcurl.so* 2>/dev/null ]]) == 0)
+               return (SYS.call([[ grep -i all_proxy /usr/lib/libcurl.so* >/dev/null 2>&1 ]]) == 0)
 
        -- only BusyBox Wget is installed
        else
@@ -96,33 +96,71 @@ function get_pid(section)
        return pid
 end
 
--- read version information for given package if installed
-function ipkg_version(package)
-       if not package then
-               return nil
-       end
-       local info = OPKG.info(package)
-       local data = {}
-       local version = ""
-       local i = 0
-       for k, v in pairs(info) do
-               if v.Package == package and v.Status.installed then
-                       version = v.Version
-                       i = i + 1
+-- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>"
+function ipkg_ver_compare(ver1, comp, ver2)
+       if not ver1 or not (#ver1 > 0)
+       or not ver2 or not (#ver2 > 0)
+       or not comp or not (#comp > 0) then return nil end
+       -- correct compare string
+       if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
+       elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
+       elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
+       elseif comp == "="  or comp == "==" then comp = "=="
+       elseif comp == "<<" then comp = "<"
+       elseif comp == ">>" then comp = ">"
+       else return nil end
+
+       local av1 = UTIL.split(ver1, "[%.%-]", nil, true)
+       local av2 = UTIL.split(ver2, "[%.%-]", nil, true)
+
+       for i = 1, math.max(table.getn(av1),table.getn(av2)), 1  do
+               local s1 = av1[i] or ""
+               local s2 = av2[i] or ""
+               local n1 = tonumber(s1)
+               local n2 = tonumber(s2)
+
+               -- one numeric and other empty string then set other to 0
+               if n1 and not n2 and (not s2 or #s2 == 0) then n2 = 0 end
+               if n2 and not n1 and (not s1 or #s1 == 0) then n1 = 0 end
+
+               local nc = (n1 and n2)  -- numeric compare
+
+               if nc then
+                       -- first "not equal" found return true
+                       if comp == "~=" and (n1 ~= n2) then return true end
+                       -- first "lower" found return true
+                       if (comp == "<" or comp == "<=") and (n1 < n2) then return true end
+                       -- first "greater" found return true
+                       if (comp == ">" or comp == ">=") and (n1 > n2) then return true end
+                       -- not equal then return false
+                       if (n1 ~= n2) then return false end
+               else
+                       if comp == "~=" and (s1 ~= s2) then return true end
+                       if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
+                       if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
+                       if (s1 ~= s2) then return false end
                end
        end
-       if i > 1 then   -- more then one valid record
-               return data
+       -- all equal then true
+       return true
+end
+
+-- read version information for given package if installed
+function ipkg_ver_installed(pkg)
+       local version = nil
+       local control = io.open("/usr/lib/opkg/info/%s.control" % pkg, "r")
+       if control then
+               local ln
+               repeat
+                       ln = control:read("*l")
+                       if ln and ln:match("^Version: ") then
+                               version = ln:gsub("^Version: ", "")
+                               break
+                       end
+               until not ln
+               control:close()
        end
-       local sver = UTIL.split(version, "[%.%-]", nil, true)
-       data = {
-               version = version,
-               major   = tonumber(sver[1]) or 0,
-               minor   = tonumber(sver[2]) or 0,
-               patch   = tonumber(sver[3]) or 0,
-               build   = tonumber(sver[4]) or 0
-       }
-       return data
+       return version
 end
 
 -- replacement of build-in read of UCI option
index d516837..0bcfd44 100644 (file)
@@ -1,6 +1,6 @@
 
 <!-- ++ BEGIN ++ Dynamic DNS ++ detail_lvalue.htm ++ -->
-<!-- no value header to supress next line -->
+<!-- no value header to suppress next line -->
 &#160;
 <% if self.widget == "select" then %>
        <select class="cbi-input-select" onchange="cbi_d_update(this.id)"<%= attr("id", cbid) .. attr("name", cbid) .. ifattr(self.size, "size") %>>
index 7cb28e2..cbe76ab 100644 (file)
@@ -5,5 +5,5 @@
                attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
                ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder")
        %> />
-<!-- no value footer to supress next line -->
+<!-- no value footer to suppress next line -->
 <!-- ++ END ++ Dynamic DNS ++ detail_value.htm ++ -->
diff --git a/applications/luci-app-ddns/luasrc/view/ddns/global_value.htm b/applications/luci-app-ddns/luasrc/view/ddns/global_value.htm
new file mode 100644 (file)
index 0000000..159cb60
--- /dev/null
@@ -0,0 +1,34 @@
+
+<!-- ++ BEGIN ++ Dynamic DNS ++ global_value.htm ++ -->
+<%+cbi/valueheader%>
+<script type="text/javascript">//<![CDATA[
+       // event handler on changed date
+       function onkeyup_date(value) {
+               var obj = document.getElementById("cbid.ddns.global.date_format.help");
+               if ( !obj ) { return; } // security check
+
+               if ( value == "" || value.length == 0 ) { value = "%F %R"; }
+               var now = new Date();
+               var txt = now.toLocaleFormat(value);
+               // handle newline(%n) and tab(%t) needs to be converted to HTML
+               txt = txt.replace(new RegExp('\r?\n','g'), '<br />');
+               txt = txt.replace(new RegExp('\t','g'), '&nbsp;&nbsp;&nbsp;&nbsp;');
+               obj.innerHTML = "<%:Current setting%>: <strong>" + txt + "<\/strong>";
+       }
+//]]></script>
+
+<input type="text" class="cbi-input-text" onchange="cbi_d_update(this.id)" onkeyup="onkeyup_date(this.value)"
+       <%=
+       attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
+       ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder")
+       %>
+/>
+<br />
+<div class="cbi-value-description">
+       <span class="cbi-value-helpicon"><img src="<%=resource%>/cbi/help.gif" alt="<%:help%>" /><%=self.description%></span>
+       <br />
+       <span id="<%=cbid%>.help" class="cbi-value-helpicon"><%:Current setting%>: <strong><%=self.date_string%></strong></span>
+</div> <!-- div class="cbi-value-description" -->
+</div> <!-- div class="cbi-value-field" -->
+</div> <!-- div class="cbi-value cbi-value-last" -->
+<!-- ++ END ++ Dynamic DNS ++ global_value.htm ++ -->
index 8255aa6..327028c 100644 (file)
@@ -6,7 +6,7 @@
 -- We need to garantie that function cfgvalue run first to set missing parameters
 %>
        <!-- style="font-size: 100%;" needed for openwrt theme to fix font size -->
-       <!-- type="button" onclick="..." enable standard onclick functionalty   -->
+       <!-- type="button" onclick="..." enable standard onclick functionality   -->
        <input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" style="font-size: 100%;" type="button" onclick="onclick_startstop(this.id)"
        <%=
        attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle) .. ifattr(self.disabled, "disabled")
index 37c54be..ea8e4a1 100644 (file)
@@ -2,12 +2,6 @@
 <!-- ++ BEGIN ++ Dynamic DNS ++ overview_status.htm ++ -->
 <script type="text/javascript">//<![CDATA[
 
-       // variables to store version information
-       var luci_version
-       var luci_build
-       var ddns_version
-       var ddns_required
-
        // helper to extract section from objects id
        // cbi.ddns.SECTION._xyz
        function _id2section(id) {
        // screen objects
        // called by XHR.poll and onclick_startstop
        function _data2elements(data) {
-               // DDNS Service
-               // fill Version informations
-               luci_version  = data[0].luci_ver
-               luci_build    = data[0].luci_build
-               ddns_version  = data[0].script_ver
-               ddns_required = data[0].script_min
-
                // Service sections
                for( i = 1; i < data.length; i++ )
                {
                }
        }
 
-       // event handler for map.title link
-       function onclick_maptitle() {
-               var str = "<%:Version Information%>";
-               str += "\n\nluci-app-ddns:";
-               str += "\n\t<%:Version%>:\t" + luci_version;
-               str += "\n\t<%:Build%>:\t" + luci_build;
-               str += "\n\nddns-scripts <%:required%>:";
-               str += "\n\t<%:Version%>:\t" + ddns_required + " <%:or greater%>";
-               str += "\n\nddns-scripts <%:installed%>:";
-               str += "\n\t<%:Version%>:\t" + ddns_version;
-               str += "\n\n"
-               alert(str);
-       }
-
        // event handler for start/stop button
        function onclick_startstop(id) {
                // extract section
                var section = _id2section(id);
                // get elements
                var cbx = document.getElementById("cbid.ddns." + section + ".enabled");         // Enabled
-               var obj = document.getElementById("cbi-ddns-overview-status-legend");           // objext defined below to make in-/visible
+               var obj = document.getElementById("cbi-ddns-overview-status-legend");           // object defined below to make in-/visible
                if ( !(obj && cbx) ) { return; }        // security check
 
                // make me visible
                var btnXHR = new XHR();
                btnXHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "startstop")%>/' + section + '/' + cbx.checked, null,
                        function(x, data) {
-                               if (x.responseText == "_uncommited_") {
+                               if (x.responseText == "_uncommitted_") {
                                        // we need a trick to display Ampersand "&" in stead of "&#38;" or "&amp;"
                                        // after translation
                                        txt="<%:Please [Save & Apply] your changes first%>";
                                } else {
                                        // should have data because status changed
                                        // so update screen
-                                       if (data)
-                                               _data2elements(data);
+                                       if (data) { _data2elements(data); }
                                }
                                // make me invisible
                                obj.parentNode.style.display = "none";
        // force to immediate show status on page load (not waiting for XHR.poll)
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(data);
+                       if (data) { _data2elements(data); }
                }
        );
 
        // we need update every 15 seconds only
        XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(data);
+                       if (data) { _data2elements(data); }
                }
        );
 
index db9d1d1..4ca0abb 100644 (file)
                        tbl.deleteRow(1);
 
                // variable for Modulo-Division use to set cbi-rowstyle-? (0 or 1)
-               var x = -1;
-               var i = 1;
-
-               // no data => no ddns-scripts Version 2 installed
-               if ( !data ) {
-                       var txt = '<br /><strong><font color="red"><%:Old version of ddns-scripts installed%></font>' ;
-                       var url = '<a href="' ;
-                       url += '<%=luci.dispatcher.build_url("admin", "system", "packages")%>' ;
-                       url += '"><%:install update here%></a></strong>' ;
-                       var tr = tbl.insertRow(-1);
-                       tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1);
-                       var td = tr.insertCell(-1);
-                       td.colSpan = 2 ;
-                       td.innerHTML = txt + " - " + url
-                       tr.insertCell(-1).colSpan = 3 ;
-                       return;
-               }
+               var i = -1;
+               var j = 1;
 
                // DDNS Service disabled
                if (data[0].enabled == 0) {
                        var txt = '<strong><font color="red"><%:DDNS Autostart disabled%></font>' ;
                        var url = '<a href="' + data[0].url_up + '"><%:enable here%></a></strong>' ;
                        var tr = tbl.insertRow(-1);
-                       tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1);
+                       tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((j + i) % 2) + 1);
                        var td = tr.insertCell(-1);
                        td.colSpan = 2 ;
                        td.innerHTML = txt + " - " + url
                        tr.insertCell(-1).colSpan = 3 ;
-                       x++ ;
+                       i++ ;
                }
 
-               for( i = 1; i < data.length; i++ )
+               for( j = 1; j < data.length; j++ )
                {
                        var tr = tbl.insertRow(-1);
-                       tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((i + x) % 2) + 1) ;
+                       tr.className = 'cbi-section-table-row cbi-rowstyle-' + (((j + i) % 2) + 1) ;
 
                        // configuration
-                       tr.insertCell(-1).innerHTML = '<strong>' + data[i].section + '</strong>' ;
+                       tr.insertCell(-1).innerHTML = '<strong>' + data[j].section + '</strong>' ;
 
                        // pid
-                       // data[i].pid ignored here
+                       // data[j].pid ignored here
 
                        // last update
-                       // data[i].datelast ignored here
+                       // data[j].datelast ignored here
 
                        // next update
-                       switch (data[i].datenext) {
+                       switch (data[j].datenext) {
                                case "_empty_":
                                        tr.insertCell(-1).innerHTML = '<em><%:Unknown error%></em>' ;
                                        break;
                                        tr.insertCell(-1).innerHTML = '<em><%:Verify%></em>';
                                        break;
                                default:
-                                       tr.insertCell(-1).innerHTML = data[i].datenext ;
+                                       tr.insertCell(-1).innerHTML = data[j].datenext ;
                                        break;
                        }
 
                        // domain
-                       if (data[i].domain == "_nodomain_")
+                       if (data[j].domain == "_nodomain_")
                                tr.insertCell(-1).innerHTML = '<em><%:config error%></em>';
                        else
-                               tr.insertCell(-1).innerHTML = data[i].domain;
+                               tr.insertCell(-1).innerHTML = data[j].domain;
 
                        // registered IP
-                       switch (data[i].reg_ip) {
+                       switch (data[j].reg_ip) {
                                case "_nodomain_":
                                        tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
                                        break;
                                        tr.insertCell(-1).innerHTML = '<em><%:IPv6 not supported%></em>';
                                        break;
                                default:
-                                       tr.insertCell(-1).innerHTML = data[i].reg_ip;
+                                       tr.insertCell(-1).innerHTML = data[j].reg_ip;
                                        break;
                        }
 
-                       // monitored interfacce
-                       if (data[i].iface == "_nonet_")
+                       // monitored interface
+                       if (data[j].iface == "_nonet_")
                                tr.insertCell(-1).innerHTML = '<em><%:Config error%></em>';
                        else
-                               tr.insertCell(-1).innerHTML = data[i].iface;
+                               tr.insertCell(-1).innerHTML = data[j].iface;
                }
 
                if (tbl.rows.length == 1 || (data[0].enabled == 0 && tbl.rows.length == 2) ) {
        // force to immediate show status (not waiting for XHR.poll)
        XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(x, data);
+                       if (data) { _data2elements(x, data); }
                }
        );
 
-       XHR.poll(10, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+       XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(x, data);
+                       if (data) { _data2elements(x, data); }
                }
        );
+
 //]]></script>
 
 <fieldset class="cbi-section" id="ddns_status_section">
index 9706dbd..f6e0d5e 100644 (file)
@@ -1,10 +1,10 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: luci-app-ddns\n"
-"POT-Creation-Date: 2014-11-09 13:41+0100\n"
-"PO-Revision-Date: 2014-11-09 14:29+0100\n"
+"POT-Creation-Date: 2015-02-08 18:30+0100\n"
+"PO-Revision-Date: 2015-02-08 18:36+0100\n"
 "Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language-Team: \n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -17,6 +17,21 @@ msgstr ""
 msgid "&"
 msgstr "&"
 
+msgid "-- custom --"
+msgstr "-- benutzerdefiniert --"
+
+msgid "-- default --"
+msgstr "-- Standard --"
+
+msgid "Advanced Settings"
+msgstr "Erweiterte Einstellungen"
+
+msgid "Allow non-public IP's"
+msgstr "Erlaube Nicht-öffentliche IPs"
+
+msgid "Applying changes"
+msgstr "Änderungen anwenden"
+
 msgid "Basic Settings"
 msgstr "Grundlegende Einstellungen"
 
@@ -29,15 +44,14 @@ msgstr ""
 
 msgid ""
 "Below is a list of configured DDNS configurations and their current state."
-"<br />If you want to send updates for IPv4 and IPv6 you need to define two "
-"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
 msgstr ""
-"Liste der definierten DDNS Konfigurationen und ihr aktueller Status.<br /"
-">Wenn Sie Aktualisierungen für IPv4 und IPv6 senden möchten benötigen Sie "
-"zwei Konfigurationen z.B. 'myddns_ipv4' und 'myddns_ipv6'"
+"Liste der konfigurierten DDNS Konfigurationen und ihr momentaner Status."
+
+msgid "Bind Network"
+msgstr "Bind-Netzwerk"
 
-msgid "Build"
-msgstr "Build"
+msgid "Binding to a specific network not supported"
+msgstr "'Bind' an ein bestimmtes Netzwerk wird nicht unterstützt"
 
 msgid ""
 "BusyBox's nslookup and Wget do not support to specify the IP version to use "
@@ -53,20 +67,33 @@ msgstr ""
 "BusyBox's nslookup unterstützt es nicht das TCP-Protokoll für DNS Anfragen "
 "anstelle des standardmäßigen UDP-Protokolls."
 
+msgid "Casual users should not change this setting"
+msgstr "Standard Benutzer sollten diese Einstellung nicht Ã¤ndern."
+
 msgid "Check Interval"
 msgstr "Prüfinterval"
 
-msgid "Check for changed IP every"
-msgstr "Teste auf neue IP alle"
-
-msgid "Check-time unit"
-msgstr "Zeiteinheit"
+msgid "Collecting data..."
+msgstr "Sammle Daten..."
 
 msgid "Config error"
 msgstr "Konfigurationsfehler"
 
-msgid "Configure here the details for selected Dynamic DNS service"
-msgstr "Konfiguriere hier die Details für den gewählten Dynamik DNS Dienst"
+msgid "Configuration"
+msgstr "Einstellungen"
+
+msgid ""
+"Configure here the details for all Dynamic DNS services including this LuCI "
+"application."
+msgstr ""
+"Konfiguriere hier die Details für alle Dynamik DNS Dienste einschließlich "
+"dieser LuCI Anwendung."
+
+msgid "Configure here the details for selected Dynamic DNS service."
+msgstr "Konfiguriere hier die Details für den gewählten Dynamik DNS Dienst."
+
+msgid "Current setting"
+msgstr "Aktuelle Einstellung"
 
 msgid ""
 "Currently DDNS updates are not started at boot or on interface events.<br /"
@@ -107,6 +134,9 @@ msgstr "DNS Anfragen Ã¼ber TCP nicht unterstützt"
 msgid "DNS-Server"
 msgstr "DNS-Server"
 
+msgid "Date format"
+msgstr "Datumsformat "
+
 msgid "Defines the Web page to read systems IPv4-Address from"
 msgstr ""
 "Definiert die Web-Seite von der die aktuelle IPv4-Adresse des System gelesen "
@@ -153,6 +183,19 @@ msgstr ""
 msgid "Details for"
 msgstr "Details für"
 
+msgid "Directory contains Log files for each running section"
+msgstr ""
+"Das Verzeichnis enthält die Protokolldateien aller laufenden Konfigurationen."
+
+msgid ""
+"Directory contains PID and other status information for each running section"
+msgstr ""
+"Das Verzeichnis enthält die PID und andere Statusinformationen aller "
+"laufenden Konfigurationen."
+
+msgid "Disabled"
+msgstr "Deaktiviert"
+
 msgid "Dynamic DNS"
 msgstr "Dynamisches DNS"
 
@@ -166,6 +209,12 @@ msgstr ""
 msgid "Enable secure communication with DDNS provider"
 msgstr "Aktiviert sichere Kommunikation mit dem DDNS Anbieter"
 
+msgid "Enabled"
+msgstr "Aktiviert"
+
+msgid "Error"
+msgstr "Fehler"
+
 msgid "Error Retry Counter"
 msgstr "Wiederholungszähler bei Fehler"
 
@@ -175,8 +224,8 @@ msgstr "Wiederholungsintervall bei Fehler"
 msgid "Event Network"
 msgstr "Ereignis Netzwerk"
 
-msgid "Event interface"
-msgstr "Ereignis Netzwerk"
+msgid "File"
+msgstr "Datei"
 
 msgid "File not found"
 msgstr "Datei nicht gefunden"
@@ -191,6 +240,13 @@ msgstr ""
 "Folgen Sie dem Link<br />Hier finden Sie weitere Hinweise um Ihr System für "
 "die Nutzung aller Optionen der DDNS Skripte zu optimieren."
 
+msgid "For detailed information about parameter settings look here."
+msgstr ""
+"Detaillierte Informationen zu den Parametereinstellungen finden Sie hier."
+
+msgid "For supported codes look here"
+msgstr "Unterstützte Kodierungen finden Sie hier."
+
 msgid "Force IP Version"
 msgstr "Erzwinge IP-Version"
 
@@ -203,12 +259,6 @@ msgstr "Erzwungene Aktualisierung"
 msgid "Force TCP on DNS"
 msgstr "Erzwinge TCP bei DNS-Anfragen"
 
-msgid "Force update every"
-msgstr "Erzwinge Aktualisierung alle"
-
-msgid "Force-time unit"
-msgstr "Zeiteinheit"
-
 msgid "Forced IP Version don't matched"
 msgstr "Erzwungene IP Version stimmt nicht Ã¼berein"
 
@@ -218,6 +268,16 @@ msgstr "Format"
 msgid "Format: IP or FQDN"
 msgstr "Format: IP-Adresse oder FQDN"
 
+msgid ""
+"GNU Wget will use the IP of given network, cURL will use the physical "
+"interface."
+msgstr ""
+"GNU Wget verwendet die IP des gewählten Netzwerkes; cURL verwendet die "
+"physikalische Schnittstelle."
+
+msgid "Global Settings"
+msgstr "Globale Einstellungen"
+
 msgid "HTTPS not supported"
 msgstr "HTTPS nicht unterstützt"
 
@@ -233,6 +293,9 @@ msgstr "IP-Adressquelle"
 msgid "IP address version"
 msgstr "IP-Adressversion"
 
+msgid "IPv4-Address"
+msgstr "IPv4-Adresse"
+
 msgid "IPv6 address must be given in square brackets"
 msgstr "Eine IPv6 Adresse muss in eckigen Klammern angegeben werden"
 
@@ -248,6 +311,12 @@ msgstr ""
 msgid "IPv6 not supported"
 msgstr "IPv6 nicht unterstützt"
 
+msgid "IPv6-Address"
+msgstr "IPv6-Adresse"
+
+msgid "If both cURL and GNU Wget are installed, Wget is used by default."
+msgstr "Wenn cURL und GNU Wget installiert sind, wird Wget verwendet."
+
 msgid ""
 "If this service section is disabled it could not be started.<br />Neither "
 "from LuCI interface nor from console"
@@ -256,11 +325,24 @@ msgstr ""
 "über das LuCI Web Interface noch von der Geräte-Konsole"
 
 msgid ""
+"If you want to send updates for IPv4 and IPv6 you need to define two "
+"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
+msgstr ""
+"Wenn Sie Aktualisierungen für IPv4 und IPv6 senden möchten benötigen Sie "
+"zwei Konfigurationen z.B. 'myddns_ipv4' und 'myddns_ipv6'"
+
+msgid ""
 "In some versions cURL/libcurl in OpenWrt is compiled without proxy support."
 msgstr ""
 "In einigen Versionen von OpenWrt wurde cURL/libcurl ohne Proxy Unterstützung "
 "compiliert."
 
+msgid "Info"
+msgstr "Informationen"
+
+msgid "Interface"
+msgstr "Schnittstelle"
+
 msgid ""
 "Interval to check for changed IP<br />Values below 5 minutes == 300 seconds "
 "are not supported"
@@ -277,12 +359,26 @@ msgstr ""
 "werden.<br />Ein Wert von '0' führt das Skript nur einmalig aus. <br />Der "
 "Wert muss größer als das Prüfintervall sein oder '0'."
 
+msgid "It is NOT recommended for casual users to change settings on this page."
+msgstr ""
+"Es wird nicht empfohlen, dass Standard Benutzer die Einstellungen auf dieser "
+"Seite Ã¤ndern."
+
 msgid "Last Update"
 msgstr "Letztes Aktualisierung"
 
+msgid "Loading"
+msgstr "Lade"
+
 msgid "Log File Viewer"
 msgstr "Protokolldatei"
 
+msgid "Log directory"
+msgstr "Protokoll-Verzeichnis"
+
+msgid "Log length"
+msgstr "Protokolllänge"
+
 msgid "Log to file"
 msgstr "Protokoll in Datei schreiben"
 
@@ -290,12 +386,22 @@ msgid "Log to syslog"
 msgstr "Systemprotokoll verwenden"
 
 msgid ""
+"Neither GNU Wget with SSL nor cURL installed to select a network to use for "
+"communication."
+msgstr ""
+"Weder GNU Wget mit SSL noch cURL sind installiert um ein Netzwerk zur "
+"Kommunikation festzulegen."
+
+msgid ""
 "Neither GNU Wget with SSL nor cURL installed to support updates via HTTPS "
 "protocol."
 msgstr ""
 "Weder GNU Wget mit SSL noch cURL sind installiert um Aktualisierungen Ã¼ber "
 "HTTPS Protokoll zu unterstützen."
 
+msgid "Network"
+msgstr "Netzwerk"
+
 msgid "Network on which the ddns-updater scripts will be started"
 msgstr "Netzwerk auf dem Ereignisse die ddns-updater Skripte starten"
 
@@ -311,6 +417,16 @@ msgstr "Keine Daten"
 msgid "No logging"
 msgstr "Keine Protokollierung"
 
+msgid "Non-public and by default blocked IP's"
+msgstr "Nicht-öffentliche und standardmäßig blockierte IPs."
+
+msgid "Notice"
+msgstr "Notiz"
+
+msgid "Number of last lines stored in log files"
+msgstr ""
+"Anzahl der letzten Zeilen die in der Protokolldatei gespeichert werden."
+
 msgid "OPTIONAL: Force the usage of pure IPv4/IPv6 only communication."
 msgstr ""
 "OPTIONAL: Erzwingt die Verwendung einer reinen IPv4/IPv6 Kommunikation."
@@ -319,6 +435,9 @@ msgid "OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."
 msgstr ""
 "OPTIONAL: Erzwingt die Verwendung von TCP anstelle von UDP bei DNS Anfragen."
 
+msgid "OPTIONAL: Network to use for communication"
+msgstr "OPTIONAL: Netzwerk das zur Kommunikation verwendet werden soll."
+
 msgid "OPTIONAL: Proxy-Server for detection and updates."
 msgstr "OPTIONAL: Proxy-Server für Adresserkennung und Aktualisierungen"
 
@@ -327,9 +446,6 @@ msgstr ""
 "OPTIONAL: Ersetzt den voreingestellten DNS-Server um die 'Registrierte IP' "
 "zu ermitteln."
 
-msgid "Old version of ddns-scripts installed"
-msgstr "Alte Version von ddns-scripts installiert"
-
 msgid "On Error the script will retry the failed action after given time"
 msgstr ""
 "Bei Fehlern wird das Skript die fehlerhafte Aktion nach der gegebenen Zeit "
@@ -338,12 +454,21 @@ msgstr ""
 msgid "On Error the script will stop execution after given number of retrys"
 msgstr "Das Skript wird nach der gegebener Anzahlt von Fehlversuchen beendet"
 
+msgid "Overview"
+msgstr "Übersicht"
+
 msgid "PROXY-Server"
 msgstr "Proxy-Server"
 
 msgid "PROXY-Server not supported"
 msgstr "Proxy-Server nicht unterstützt"
 
+msgid "Password"
+msgstr "Passwort"
+
+msgid "Path to CA-Certificate"
+msgstr "Pfad zum CA-Zertifikat"
+
 msgid "Please [Save & Apply] your changes first"
 msgstr "Bitte [Speichern & Anwenden] Sie Ã„nderungen zunächst"
 
@@ -377,21 +502,21 @@ msgstr "Einmalig ausführen"
 msgid "Script"
 msgstr "Skript"
 
-msgid "Service"
-msgstr "Dienst"
-
 msgid "Show more"
 msgstr "Zeige mehr"
 
 msgid "Software update required"
 msgstr "Softwareaktualisierung nötig"
 
-msgid "Source of IP address"
-msgstr "Quelle der IP-Adresse"
+msgid "Start"
+msgstr "Start"
 
 msgid "Start / Stop"
 msgstr "Start / Stopp"
 
+msgid "Status directory"
+msgstr "Status-Verzeichnis"
+
 msgid "Stopped"
 msgstr "Angehalten"
 
@@ -408,6 +533,12 @@ msgstr "Kein Dienst konfiguriert"
 msgid "Timer Settings"
 msgstr "Zeitgeber Einstellungen"
 
+msgid "To change global settings click here"
+msgstr "Globale Einstellungen können sie hier Ã¤ndern."
+
+msgid "To use cURL activate this option."
+msgstr "Um cURL zu verwenden aktivieren sie diese Einstellung."
+
 msgid "URL"
 msgstr "URL"
 
@@ -430,14 +561,32 @@ msgstr "Aktualisierungsfehler"
 msgid "Use HTTP Secure"
 msgstr "Verwende sicheres HTTP"
 
+msgid "Use cURL"
+msgstr "Verwende cURL"
+
 msgid "User defined script to read systems IP-Address"
 msgstr ""
 "Definiert das Skript mit dem die  aktuelle IP-Adresse des System gelesen "
 "wird."
 
+msgid "Username"
+msgstr "Benutzername"
+
+msgid "Verify"
+msgstr "überprüfen"
+
+msgid "Version"
+msgstr "Version"
+
 msgid "Version Information"
 msgstr "Versionsinformationen"
 
+msgid "Waiting for changes to be applied..."
+msgstr "Änderungen werden angewandt..."
+
+msgid "Warning"
+msgstr "Warnung"
+
 msgid ""
 "Writes detailed messages to log file. File will be truncated automatically."
 msgstr ""
@@ -460,6 +609,9 @@ msgstr ""
 "Sie sollten das Programmpaket GNU Wget mit SSL (bevorzugt) oder cURL "
 "installieren."
 
+msgid "You should install GNU Wget with SSL or cURL package."
+msgstr "Sie sollten das Programmpaket GNU Wget mit SSL oder cURL installieren."
+
 msgid "You should install GNU Wget with SSL or replace libcurl."
 msgstr ""
 "Sie sollten das Programmpaket GNU Wget mit SSL installieren oder libcurl "
@@ -482,9 +634,6 @@ msgstr "Konnte Server nicht finden:"
 msgid "config error"
 msgstr "Konfigurationsfehler"
 
-msgid "custom"
-msgstr "benutzerdefiniert"
-
 msgid "days"
 msgstr "Tage"
 
@@ -500,27 +649,18 @@ msgstr "hier aktivieren"
 msgid "file or directory not found or not 'IGNORE'"
 msgstr "Datei oder Verzeichnis nicht gefunden oder nicht 'IGNORE'"
 
-msgid "h"
-msgstr "Stunden"
+msgid "help"
+msgstr "Hilfe"
 
 msgid "hours"
 msgstr "Stunden"
 
-msgid "install update here"
-msgstr "Aktualisierung hier installieren"
-
 msgid "installed"
 msgstr "installiert"
 
-msgid "interface"
-msgstr "Schnittstelle"
-
 msgid "invalid - Sample"
 msgstr "ungültig - Beispiel"
 
-msgid "min"
-msgstr "Minuten"
-
 msgid "minimum value '0'"
 msgstr "Minimum Wert '0'"
 
@@ -545,9 +685,6 @@ msgstr "muss mit 'http://' beginnen"
 msgid "nc (netcat) can not connect"
 msgstr "nc (netcat) kann keine Verbindung herstellen"
 
-msgid "network"
-msgstr "Netzwerk"
-
 msgid "never"
 msgstr "nie"
 
@@ -564,8 +701,8 @@ msgstr "nslookup kann den Namen nicht auflösen"
 msgid "or"
 msgstr "oder"
 
-msgid "or greater"
-msgstr "oder größer"
+msgid "or higher"
+msgstr "oder höher"
 
 msgid "please disable"
 msgstr "Bitte deaktivieren"
@@ -579,6 +716,9 @@ msgstr "Bitte 'IPv4' Adressversion auswählen"
 msgid "please select 'IPv4' address version in"
 msgstr "Bitte 'IPv4' Adressversion auswählen in den"
 
+msgid "please set to 'default'"
+msgstr "Bitte auf 'Standard' setzen"
+
 msgid "proxy port missing"
 msgstr "Proxy-Port fehlt"
 
index c3b8c93..6e4f2fe 100644 (file)
@@ -4,6 +4,21 @@ msgstr "Content-Type: text/plain; charset=UTF-8"
 msgid "&"
 msgstr ""
 
+msgid "-- custom --"
+msgstr ""
+
+msgid "-- default --"
+msgstr ""
+
+msgid "Advanced Settings"
+msgstr ""
+
+msgid "Allow non-public IP's"
+msgstr ""
+
+msgid "Applying changes"
+msgstr ""
+
 msgid "Basic Settings"
 msgstr ""
 
@@ -14,11 +29,12 @@ msgstr ""
 
 msgid ""
 "Below is a list of configured DDNS configurations and their current state."
-"<br />If you want to send updates for IPv4 and IPv6 you need to define two "
-"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
 msgstr ""
 
-msgid "Build"
+msgid "Bind Network"
+msgstr ""
+
+msgid "Binding to a specific network not supported"
 msgstr ""
 
 msgid ""
@@ -31,19 +47,30 @@ msgid ""
 "UDP when requesting DNS server"
 msgstr ""
 
-msgid "Check Interval"
+msgid "Casual users should not change this setting"
 msgstr ""
 
-msgid "Check for changed IP every"
+msgid "Check Interval"
 msgstr ""
 
-msgid "Check-time unit"
+msgid "Collecting data..."
 msgstr ""
 
 msgid "Config error"
 msgstr ""
 
-msgid "Configure here the details for selected Dynamic DNS service"
+msgid "Configuration"
+msgstr ""
+
+msgid ""
+"Configure here the details for all Dynamic DNS services including this LuCI "
+"application."
+msgstr ""
+
+msgid "Configure here the details for selected Dynamic DNS service."
+msgstr ""
+
+msgid "Current setting"
 msgstr ""
 
 msgid ""
@@ -78,6 +105,9 @@ msgstr ""
 msgid "DNS-Server"
 msgstr ""
 
+msgid "Date format"
+msgstr ""
+
 msgid "Defines the Web page to read systems IPv4-Address from"
 msgstr ""
 
@@ -109,6 +139,16 @@ msgstr ""
 msgid "Details for"
 msgstr ""
 
+msgid "Directory contains Log files for each running section"
+msgstr ""
+
+msgid ""
+"Directory contains PID and other status information for each running section"
+msgstr ""
+
+msgid "Disabled"
+msgstr ""
+
 msgid "Dynamic DNS"
 msgstr ""
 
@@ -120,6 +160,12 @@ msgstr ""
 msgid "Enable secure communication with DDNS provider"
 msgstr ""
 
+msgid "Enabled"
+msgstr ""
+
+msgid "Error"
+msgstr ""
+
 msgid "Error Retry Counter"
 msgstr ""
 
@@ -129,7 +175,7 @@ msgstr ""
 msgid "Event Network"
 msgstr ""
 
-msgid "Event interface"
+msgid "File"
 msgstr ""
 
 msgid "File not found"
@@ -143,6 +189,12 @@ msgid ""
 "run DDNS scripts with all options"
 msgstr ""
 
+msgid "For detailed information about parameter settings look here."
+msgstr ""
+
+msgid "For supported codes look here"
+msgstr ""
+
 msgid "Force IP Version"
 msgstr ""
 
@@ -155,19 +207,21 @@ msgstr ""
 msgid "Force TCP on DNS"
 msgstr ""
 
-msgid "Force update every"
+msgid "Forced IP Version don't matched"
 msgstr ""
 
-msgid "Force-time unit"
+msgid "Format"
 msgstr ""
 
-msgid "Forced IP Version don't matched"
+msgid "Format: IP or FQDN"
 msgstr ""
 
-msgid "Format"
+msgid ""
+"GNU Wget will use the IP of given network, cURL will use the physical "
+"interface."
 msgstr ""
 
-msgid "Format: IP or FQDN"
+msgid "Global Settings"
 msgstr ""
 
 msgid "HTTPS not supported"
@@ -185,6 +239,9 @@ msgstr ""
 msgid "IP address version"
 msgstr ""
 
+msgid "IPv4-Address"
+msgstr ""
+
 msgid "IPv6 address must be given in square brackets"
 msgstr ""
 
@@ -197,15 +254,32 @@ msgstr ""
 msgid "IPv6 not supported"
 msgstr ""
 
+msgid "IPv6-Address"
+msgstr ""
+
+msgid "If both cURL and GNU Wget are installed, Wget is used by default."
+msgstr ""
+
 msgid ""
 "If this service section is disabled it could not be started.<br />Neither "
 "from LuCI interface nor from console"
 msgstr ""
 
 msgid ""
+"If you want to send updates for IPv4 and IPv6 you need to define two "
+"separate Configurations i.e. 'myddns_ipv4' and 'myddns_ipv6'"
+msgstr ""
+
+msgid ""
 "In some versions cURL/libcurl in OpenWrt is compiled without proxy support."
 msgstr ""
 
+msgid "Info"
+msgstr ""
+
+msgid "Interface"
+msgstr ""
+
 msgid ""
 "Interval to check for changed IP<br />Values below 5 minutes == 300 seconds "
 "are not supported"
@@ -217,12 +291,24 @@ msgid ""
 "Interval' except '0' are not supported"
 msgstr ""
 
+msgid "It is NOT recommended for casual users to change settings on this page."
+msgstr ""
+
 msgid "Last Update"
 msgstr ""
 
+msgid "Loading"
+msgstr ""
+
 msgid "Log File Viewer"
 msgstr ""
 
+msgid "Log directory"
+msgstr ""
+
+msgid "Log length"
+msgstr ""
+
 msgid "Log to file"
 msgstr ""
 
@@ -230,10 +316,18 @@ msgid "Log to syslog"
 msgstr ""
 
 msgid ""
+"Neither GNU Wget with SSL nor cURL installed to select a network to use for "
+"communication."
+msgstr ""
+
+msgid ""
 "Neither GNU Wget with SSL nor cURL installed to support updates via HTTPS "
 "protocol."
 msgstr ""
 
+msgid "Network"
+msgstr ""
+
 msgid "Network on which the ddns-updater scripts will be started"
 msgstr ""
 
@@ -249,19 +343,28 @@ msgstr ""
 msgid "No logging"
 msgstr ""
 
+msgid "Non-public and by default blocked IP's"
+msgstr ""
+
+msgid "Notice"
+msgstr ""
+
+msgid "Number of last lines stored in log files"
+msgstr ""
+
 msgid "OPTIONAL: Force the usage of pure IPv4/IPv6 only communication."
 msgstr ""
 
 msgid "OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."
 msgstr ""
 
-msgid "OPTIONAL: Proxy-Server for detection and updates."
+msgid "OPTIONAL: Network to use for communication"
 msgstr ""
 
-msgid "OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'."
+msgid "OPTIONAL: Proxy-Server for detection and updates."
 msgstr ""
 
-msgid "Old version of ddns-scripts installed"
+msgid "OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'."
 msgstr ""
 
 msgid "On Error the script will retry the failed action after given time"
@@ -270,12 +373,21 @@ msgstr ""
 msgid "On Error the script will stop execution after given number of retrys"
 msgstr ""
 
+msgid "Overview"
+msgstr ""
+
 msgid "PROXY-Server"
 msgstr ""
 
 msgid "PROXY-Server not supported"
 msgstr ""
 
+msgid "Password"
+msgstr ""
+
+msgid "Path to CA-Certificate"
+msgstr ""
+
 msgid "Please [Save & Apply] your changes first"
 msgstr ""
 
@@ -309,21 +421,21 @@ msgstr ""
 msgid "Script"
 msgstr ""
 
-msgid "Service"
-msgstr ""
-
 msgid "Show more"
 msgstr ""
 
 msgid "Software update required"
 msgstr ""
 
-msgid "Source of IP address"
+msgid "Start"
 msgstr ""
 
 msgid "Start / Stop"
 msgstr ""
 
+msgid "Status directory"
+msgstr ""
+
 msgid "Stopped"
 msgstr ""
 
@@ -338,6 +450,12 @@ msgstr ""
 msgid "Timer Settings"
 msgstr ""
 
+msgid "To change global settings click here"
+msgstr ""
+
+msgid "To use cURL activate this option."
+msgstr ""
+
 msgid "URL"
 msgstr ""
 
@@ -358,12 +476,30 @@ msgstr ""
 msgid "Use HTTP Secure"
 msgstr ""
 
+msgid "Use cURL"
+msgstr ""
+
 msgid "User defined script to read systems IP-Address"
 msgstr ""
 
+msgid "Username"
+msgstr ""
+
+msgid "Verify"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
 msgid "Version Information"
 msgstr ""
 
+msgid "Waiting for changes to be applied..."
+msgstr ""
+
+msgid "Warning"
+msgstr ""
+
 msgid ""
 "Writes detailed messages to log file. File will be truncated automatically."
 msgstr ""
@@ -379,6 +515,9 @@ msgstr ""
 msgid "You should install GNU Wget with SSL (prefered) or cURL package."
 msgstr ""
 
+msgid "You should install GNU Wget with SSL or cURL package."
+msgstr ""
+
 msgid "You should install GNU Wget with SSL or replace libcurl."
 msgstr ""
 
@@ -397,9 +536,6 @@ msgstr ""
 msgid "config error"
 msgstr ""
 
-msgid "custom"
-msgstr ""
-
 msgid "days"
 msgstr ""
 
@@ -415,27 +551,18 @@ msgstr ""
 msgid "file or directory not found or not 'IGNORE'"
 msgstr ""
 
-msgid "h"
+msgid "help"
 msgstr ""
 
 msgid "hours"
 msgstr ""
 
-msgid "install update here"
-msgstr ""
-
 msgid "installed"
 msgstr ""
 
-msgid "interface"
-msgstr ""
-
 msgid "invalid - Sample"
 msgstr ""
 
-msgid "min"
-msgstr ""
-
 msgid "minimum value '0'"
 msgstr ""
 
@@ -460,9 +587,6 @@ msgstr ""
 msgid "nc (netcat) can not connect"
 msgstr ""
 
-msgid "network"
-msgstr ""
-
 msgid "never"
 msgstr ""
 
@@ -478,7 +602,7 @@ msgstr ""
 msgid "or"
 msgstr ""
 
-msgid "or greater"
+msgid "or higher"
 msgstr ""
 
 msgid "please disable"
@@ -493,6 +617,9 @@ msgstr ""
 msgid "please select 'IPv4' address version in"
 msgstr ""
 
+msgid "please set to 'default'"
+msgstr ""
+
 msgid "proxy port missing"
 msgstr ""
 
index 3726f64..3c46e22 100644 (file)
@@ -6,7 +6,8 @@
        for _, z in ipairs(fw:get_zones()) do
                if z:name() ~= "wan" then
                        izl[#izl+1] = z
-               elseif z:name() ~= "lan" then
+               end
+               if z:name() ~= "lan" then
                        ezl[#ezl+1] = z
                end
        end
index bb7fe3f..91bddc7 100644 (file)
@@ -44,7 +44,7 @@ function ocserv_status()
                        if not ln then break end
                
                        local id, user, group, vpn_ip, ip, device, time, cipher, status = 
-                               ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+                               ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%(%)%:%.-_%w]+)%s+([%:%.-_%w]+).*")
                        if id then
                                fwd[#fwd+1] = {
                                        id = id,
index d354cf6..d1cc155 100644 (file)
@@ -42,7 +42,7 @@ if fd then local ln
                        found_pki = true
                elseif found_pki then
                        local hash = ln:match("([a-f0-9]+)")
-                       o_pki.default = hash and hash:upper()
+                       o_pki.default = hash and "sha1:" .. hash:upper()
                        complete = complete + 1
                        found_pki = false
                end
@@ -90,6 +90,10 @@ local pip = s:taboption("general", Flag, "predictable_ips", translate("Predictab
        translate("The assigned IPs will be selected deterministically"))
 pip.default = "1"
 
+local compr = s:taboption("general", Flag, "compression", translate("Enable compression"),
+       translate("Enable compression"))
+compr.default = "1"
+
 local udp = s:taboption("general", Flag, "udp", translate("Enable UDP"),
        translate("Enable UDP channel support; this must be enabled unless you know what you are doing"))
 udp.default = "1"
index 2e530c0..c4be181 100644 (file)
@@ -47,7 +47,7 @@ if fd then local ln
                if not ln then break end
 
                local id, user, group, vpn_ip, ip, device, time, cipher, status = 
-                       ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+).*")
+                       ln:match("^%s*(%d+)%s+([-_%w]+)%s+([%.%*-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%:%.-_%w]+)%s+([%(%)%:%.-_%w]+)%s+([%:%.-_%w]+).*")
                if id then
                        table.insert(lusers, {id, user, group, vpn_ip, ip, device, time, cipher, status})
                end
index 7142c77..0e59c61 100644 (file)
@@ -93,9 +93,9 @@ if luci.http.formvalue("status") == "1" then
        local rv = {}
        for k, line in ipairs(services) do
                local field = utl.split(line, "[#|]", split, true)
-               local origin_lnk = ip.IPv6(pcdata(field[4])) or ""
+               local origin_lnk = ip.IPv6(pcdata(field[4]))
                local origin_link = ""
-               if #origin_lnk ~= 0 and origin_lnk:is6() then
+               if origin_lnk and origin_lnk:is6() then
                        origin_link = "["..origin_lnk:string().."]"
                else
                        origin_link = pcdata(field[4])
@@ -168,9 +168,9 @@ end
                        local field = {}
                        -- split line at # and |, 1=url, 2=proto, 3=description, 4=source
                        local field = utl.split(line, "[#|]", split, true)
-                       local origin_lnk = ip.IPv6(pcdata(field[4])) or ""
+                       local origin_lnk = ip.IPv6(pcdata(field[4]))
                        local origin_link
-                       if #origin_lnk ~= 0 and origin_lnk:is6() then
+                       if origin_lnk and origin_lnk:is6() then
                                origin_link = "["..origin_lnk:string().."]"
                        else
                                origin_link = pcdata(field[4])
index 3615372..74deb71 100644 (file)
@@ -1,5 +1,8 @@
 module("luci.controller.olsr", package.seeall)
 
+local neigh_table = nil
+local ifaddr_table = nil
+
 function index()
        local ipv4,ipv6
        if nixio.fs.access("/etc/config/olsrd") then
@@ -93,6 +96,46 @@ function action_json()
        http.write('{"v4":' .. jsonreq4 .. ', "v6":' .. jsonreq6 .. '}')
 end
 
+
+local function local_mac_lookup(ipaddr)
+       local _, ifa, dev
+
+       ipaddr = tostring(ipaddr)
+
+       if not ifaddr_table then
+               ifaddr_table = nixio.getifaddrs()
+       end
+
+       -- ipaddr -> ifname
+       for _, ifa in ipairs(ifaddr_table) do
+               if ifa.addr == ipaddr then
+                       dev = ifa.name
+                       break
+               end
+       end
+
+       -- ifname -> macaddr
+       for _, ifa in ipairs(ifaddr_table) do
+               if ifa.name == dev and ifa.family == "packet" then
+                       return ifa.addr
+               end
+       end
+end
+
+local function remote_mac_lookup(ipaddr)
+       local _, n
+
+       if not neigh_table then
+               neigh_table = luci.ip.neighbors()
+       end
+
+       for _, n in ipairs(neigh_table) do
+               if n.mac and n.dest and n.dest:equal(ipaddr) then
+                       return n.mac
+               end
+       end
+end
+
 function action_neigh(json)
        local data, has_v4, has_v6, error = fetch_jsoninfo('links')
 
@@ -107,17 +150,13 @@ function action_neigh(json)
        local sys = require "luci.sys"
        local assoclist = {}
        --local neightbl = require "neightbl"
+       local ntm = require "luci.model.network"
        local ipc = require "luci.ip"
+       local nxo = require "nixio"
+       local defaultgw
 
-       luci.sys.net.routes(function(r) 
-               if r.dest:prefix() == 0 then 
-                       defaultgw = r.gateway:string() 
-               end
-       end)
-
-       if not defaultgw then
-               defaultgw = luci.util.exec("ip route list exact 0.0.0.0/0 table all"):match(" via (%S+)")
-       end
+       ipc.routes({ family = 4, type = 1, dest_exact = "0.0.0.0/0" },
+               function(rt) defaultgw = rt.gw end)
 
        local function compare(a,b)
                if a.proto == b.proto then
@@ -138,14 +177,10 @@ function action_neigh(json)
        end
 
        for k, v in ipairs(data) do
-               local interface
                local snr = 0
                local signal = 0
                local noise = 0
-               local arptable = sys.net.arptable()
                local mac = ""
-               local rmac = ""
-               local lmac = ""
                local ip
                local neihgt = {}
                
@@ -155,45 +190,11 @@ function action_neigh(json)
                                v.hostname = hostname
                        end
                end
-               if v.proto == '4' then
-                       uci:foreach("network", "interface",function(vif)
-                               if vif.ipaddr and vif.ipaddr == v.localIP then
-                                       interface = vif['.name'] or vif.interface
-                                       lmac = string.lower(vif.macaddr or "") 
-                                       return
-                               end
-                       end)
-                       for _, arpt in ipairs(arptable) do
-                               ip = arpt['IP address']
-                               if ip == v.remoteIP then
-                                       rmac = string.lower(arpt['HW address'] or "")
-                               end
-                       end
-               elseif v.proto == '6' then
-                       uci:foreach("network", "interface",function(vif)
-                               local name = vif['.name']
-                               local net = ntm:get_network(name)
-                               local device = net and net:get_interface()
-                               local locip = ipc.IPv6(v.localIP)
-                               if device and device:ip6addrs() and locip then
-                                       for _, a in ipairs(device:ip6addrs()) do
-                                               if not a:is6linklocal() then
-                                                       if a:host() == locip:host() then
-                                                               interface = name
-                                                               --neihgt = neightbl.get(device.ifname) or {}
-                                                       end
-                                               end
-                                       end
-                               end
-                       end)
-                       --[[
-                       for ip,mac in pairs(neihgt) do
-                               if ip == v.remoteIP then
-                                       rmac = mac
-                               end
-                       end
-                       ]]--
-               end
+
+               local interface = ntm:get_status_by_address(v.localIP)
+               local lmac = local_mac_lookup(v.localIP)
+               local rmac = remote_mac_lookup(v.remoteIP)
+
                for _, val in ipairs(assoclist) do
                        if val.network == interface and val.list then
                                for assocmac, assot in pairs(val.list) do
diff --git a/applications/luci-app-privoxy/Makefile b/applications/luci-app-privoxy/Makefile
new file mode 100644 (file)
index 0000000..bc2c57e
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
+#
+# This is free software, licensed under the Apache License, Version 2.0 .
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=luci-app-privoxy
+
+# Version == major.minor.patch
+# increase "minor" on new functionality and "patch" on patches/optimization
+PKG_VERSION:=1.0.3
+
+# Release == build
+# increase on changes of translation files
+PKG_RELEASE:=1
+
+PKG_LICENSE:=Apache-2.0
+PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
+
+# LuCI specific settings
+LUCI_TITLE:=LuCI Support for Privoxy WEB proxy
+LUCI_DEPENDS:=+luci-mod-admin-full +privoxy
+LUCI_PKGARCH:=all
+
+define Package/$(PKG_NAME)/config
+# shown in make menuconfig <Help>
+help
+       $(LUCI_TITLE)
+       .
+       Version: $(PKG_VERSION)-$(PKG_RELEASE)
+       $(PKG_MAINTAINER)
+endef
+
+include $(TOPDIR)/feeds/luci/luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-privoxy/luasrc/controller/privoxy.lua b/applications/luci-app-privoxy/luasrc/controller/privoxy.lua
new file mode 100755 (executable)
index 0000000..9ffc404
--- /dev/null
@@ -0,0 +1,160 @@
+-- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed under the Apache License, Version 2.0
+
+module("luci.controller.privoxy", package.seeall)
+
+local NX   = require "nixio"
+local NXFS = require "nixio.fs"
+local HTTP = require "luci.http"
+local UCI  = require "luci.model.uci"
+local UTIL = require "luci.util"
+local SYS  = require "luci.sys"
+
+PRIVOXY_MIN = "3.0.22-0"       -- minimum version of service required
+
+function index()
+       entry( {"admin", "services", "privoxy"}, cbi("privoxy"), _("Privoxy WEB proxy"), 59)
+       entry( {"admin", "services", "privoxy", "logview"}, call("logread") ).leaf = true
+       entry( {"admin", "services", "privoxy", "startstop"}, call("startstop") ).leaf = true
+       entry( {"admin", "services", "privoxy", "status"}, call("get_pid") ).leaf = true
+end
+
+-- called by XHR.get from detail_logview.htm
+function logread()
+       -- read application settings
+       local uci     = UCI.cursor()
+       local logdir  = uci:get("privoxy", "privoxy", "logdir") or "/var/log"
+       local logfile = uci:get("privoxy", "privoxy", "logfile") or "privoxy.log"
+       uci:unload("privoxy")
+
+       local lfile=logdir .. "/" .. logfile
+       local ldata=NXFS.readfile(lfile)
+       if not ldata or #ldata == 0 then
+               ldata="_nodata_"
+       end
+       HTTP.write(ldata)
+end
+
+-- called by XHR.get from detail_startstop.htm
+function startstop()
+       local pid = get_pid(true)
+       if pid > 0 then
+               SYS.call("/etc/init.d/privoxy stop")
+               NX.nanosleep(1)         -- sleep a second
+               if NX.kill(pid, 0) then -- still running
+                       NX.kill(pid, 9) -- send SIGKILL
+               end
+               pid = 0
+       else
+               SYS.call("/etc/init.d/privoxy start")
+               NX.nanosleep(1)         -- sleep a second
+               pid = tonumber(NXFS.readfile("/var/run/privoxy.pid") or 0 )
+               if pid > 0 and not NX.kill(pid, 0) then
+                       pid = 0         -- process did not start
+               end
+       end
+       HTTP.write(tostring(pid))       -- HTTP needs string not number
+end
+
+-- called by XHR.poll from detail_startstop.htm
+-- and from lua (with parameter "true")
+function get_pid(from_lua)
+       local pid = tonumber(NXFS.readfile("/var/run/privoxy.pid") or 0 )
+       if pid > 0 and not NX.kill(pid, 0) then
+               pid = 0
+       end
+       if from_lua then
+               return pid
+       else
+               HTTP.write(tostring(pid))       -- HTTP needs string not number
+       end
+end
+
+-- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>"
+function ipkg_ver_compare(ver1, comp, ver2)
+       if not ver1 or not (#ver1 > 0)
+       or not ver2 or not (#ver2 > 0)
+       or not comp or not (#comp > 0) then return nil end
+       -- correct compare string
+       if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
+       elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
+       elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
+       elseif comp == "="  or comp == "==" then comp = "=="
+       elseif comp == "<<" then comp = "<"
+       elseif comp == ">>" then comp = ">"
+       else return nil end
+
+       local av1 = UTIL.split(ver1, "[%.%-]", nil, true)
+       local av2 = UTIL.split(ver2, "[%.%-]", nil, true)
+
+       for i = 1, math.max(table.getn(av1),table.getn(av2)), 1  do
+               local s1 = av1[i] or ""
+               local s2 = av2[i] or ""
+               local n1 = tonumber(s1)
+               local n2 = tonumber(s2)
+
+               -- one numeric and other empty string then set other to 0
+               if n1 and not n2 and (not s2 or #s2 == 0) then n2 = 0 end
+               if n2 and not n1 and (not s1 or #s1 == 0) then n1 = 0 end
+
+               local nc = (n1 and n2)  -- numeric compare
+
+               if nc then
+                       -- first "not equal" found return true
+                       if comp == "~=" and (n1 ~= n2) then return true end
+                       -- first "lower" found return true
+                       if (comp == "<" or comp == "<=") and (n1 < n2) then return true end
+                       -- first "greater" found return true
+                       if (comp == ">" or comp == ">=") and (n1 > n2) then return true end
+                       -- not equal then return false
+                       if (n1 ~= n2) then return false end
+               else
+                       if comp == "~=" and (s1 ~= s2) then return true end
+                       if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
+                       if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
+                       if (s1 ~= s2) then return false end
+               end
+       end
+       -- all equal then true
+       return true
+end
+
+-- read version information for given package if installed
+function ipkg_ver_installed(pkg)
+       local version = nil
+       local control = io.open("/usr/lib/opkg/info/%s.control" % pkg, "r")
+       if control then
+               local ln
+               repeat
+                       ln = control:read("*l")
+                       if ln and ln:match("^Version: ") then
+                               version = ln:gsub("^Version: ", "")
+                               break
+                       end
+               until not ln
+               control:close()
+       end
+       return version
+end
+
+-- replacement of build-in Flag.parse of cbi.lua
+-- modified to mark section as changed if value changes
+-- current parse did not do this, but it is done AbstaractValue.parse()
+function flag_parse(self, section)
+       local fexists = self.map:formvalue(
+               luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
+
+       if fexists then
+               local fvalue = self:formvalue(section) and self.enabled or self.disabled
+               local cvalue = self:cfgvalue(section)
+               if fvalue ~= self.default or (not self.optional and not self.rmempty) then
+                       self:write(section, fvalue)
+               else
+                       self:remove(section)
+               end
+               if (fvalue ~= cvalue) then self.section.changed = true end
+       else
+               self:remove(section)
+               self.section.changed = true
+       end
+end
diff --git a/applications/luci-app-privoxy/luasrc/model/cbi/privoxy.lua b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy.lua
new file mode 100755 (executable)
index 0000000..c009313
--- /dev/null
@@ -0,0 +1,977 @@
+-- Copyright 2014-2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed under the Apache License, Version 2.0
+
+local NXFS = require "nixio.fs"
+local SYS  = require "luci.sys"
+local UTIL = require "luci.util"
+local DISP = require "luci.dispatcher"
+local DTYP = require "luci.cbi.datatypes"
+local CTRL = require "luci.controller.privoxy" -- this application's controller
+
+-- Bootstrap theme needs 2 or 3 additional linefeeds for tab description for better optic
+local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
+
+local VERINST = CTRL.ipkg_ver_installed("privoxy")
+local VEROK   = CTRL.ipkg_ver_compare(VERINST,">=",CTRL.PRIVOXY_MIN)
+
+local TITLE = [[</a><a href="javascript:alert(']]
+               .. translate("Version Information")
+               .. [[\n\nluci-app-privoxy]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]]
+               .. CTRL.ipkg_ver_installed("luci-app-privoxy")
+               .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
+               .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
+               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. VERINST
+               .. [[\n\n]]
+       .. [[')">]]
+       .. translate("Privoxy WEB proxy")
+
+local DESC = translate("Privoxy is a non-caching web proxy with advanced filtering "
+               .. "capabilities for enhancing privacy, modifying web page data and HTTP headers, "
+               .. "controlling access, and removing ads and other obnoxious Internet junk.")
+               .. [[<br /><strong>]]
+               .. translate("For help use link at the relevant option")
+               .. [[</strong>]]
+
+-- Error handling if wrong privoxy version installed -- ########################
+if not nixio.fs.access("/etc/config/privoxy") or not VEROK then
+       local f = SimpleForm("_no_config")
+       f.title = TITLE
+       f.description = DESC
+       f.submit = false
+       f.reset  = false
+
+       local s = f:section(SimpleSection)
+       s.title = [[<font color="red">]] .. [[<strong>]]
+               .. translate("Software update required")
+               .. [[</strong>]] .. [[</font>]]
+
+       local v    = s:option(DummyValue, "_update_needed")
+       v.titleref = DISP.build_url("admin", "system", "packages")
+       v.rawhtml  = true
+       v.value    = [[<h3><strong><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
+                  .. translate("The currently installed 'privoxy' package is not supported by LuCI application.")
+                  .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
+                  .. translate("required") .. ": " .. CTRL.PRIVOXY_MIN .. " *** ".. translate("installed") .. ": " .. VERINST
+                  .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
+                  .. translate("Please update to the current version!")
+                  .. [[<br /><br /></strong></h3>]]
+       return f
+end
+
+-- cbi-map -- ##################################################################
+local m        = Map("privoxy")
+m.title        = TITLE
+m.description = DESC
+function m.commit_handler(self)
+       if self.changed then    -- changes ?
+               os.execute("/etc/init.d/privoxy reload &")      -- reload configuration
+       end
+end
+
+-- cbi-section -- ##############################################################
+local ns = m:section( NamedSection, "privoxy", "privoxy")
+
+ns:tab("local",
+       translate("Local Set-up"),
+       translate("If you intend to operate Privoxy for more users than just yourself, "
+               .. "it might be a good idea to let them know how to reach you, what you block "
+               .. "and why you do that, your policies, etc.") )
+local function err_tab_local(title, msg)
+       return string.format(translate("Local Set-up") .. " - %s: %s", title, msg )
+end
+
+ns:tab("filter",
+       translate("Files and Directories"),
+       translate("Privoxy can (and normally does) use a number of other files "
+               .. "for additional configuration, help and logging. This section of "
+               .. "the configuration file tells Privoxy where to find those other files.") )
+local function err_tab_filter(title, msg)
+       return string.format(translate("Files and Directories") .. " - %s: %s", title, msg )
+end
+
+ns:tab("access",
+       translate("Access Control"),
+       translate("This tab controls the security-relevant aspects of Privoxy's configuration.") )
+local function err_tab_access(title, msg)
+       return string.format(translate("Access Control") .. " - %s: %s", title, msg )
+end
+
+ns:tab("forward",
+       translate("Forwarding"),
+       translate("Configure here the routing of HTTP requests through a chain of multiple proxies. "
+               .. "Note that parent proxies can severely decrease your privacy level. "
+               .. "Also specified here are SOCKS proxies.") )
+
+ns:tab("misc",
+       translate("Miscellaneous"),
+       nil)
+local function err_tab_misc(self, msg)
+       return string.format(translate("Miscellaneous") .. " - %s: %s", self.title_base, msg )
+end
+
+ns:tab("debug",
+       translate("Logging"),
+       nil )
+
+ns:tab("logview",
+       translate("Log File Viewer"),
+       nil )
+
+-- tab: local -- ###############################################################
+
+-- start/stop button -----------------------------------------------------------
+local btn      = ns:taboption("local", Button, "_startstop")
+btn.title      = translate("Start / Stop")
+btn.description        = translate("Start/Stop Privoxy WEB Proxy")
+btn.template   = "privoxy/detail_startstop"
+function btn.cfgvalue(self, section)
+       local pid = CTRL.get_pid(true)
+       if pid > 0 then
+               btn.inputtitle  = "PID: " .. pid
+               btn.inputstyle  = "reset"
+               btn.disabled    = false
+       else
+               btn.inputtitle  = translate("Start")
+               btn.inputstyle  = "apply"
+               btn.disabled    = false
+       end
+       return true
+end
+
+-- enabled ---------------------------------------------------------------------
+local ena      = ns:taboption("local", Flag, "_enabled")
+ena.title       = translate("Enabled")
+ena.description = translate("Enable/Disable autostart of Privoxy on system startup and interface events")
+ena.orientation = "horizontal" -- put description under the checkbox
+ena.rmempty    = false
+function ena.cfgvalue(self, section)
+       return (SYS.init.enabled("privoxy")) and "1" or "0"
+end
+function ena.validate(self, value)
+       error("Validate " .. value)
+end
+function ena.write(self, section, value)
+       --error("Write " .. value)
+       if value == "1" then
+               return SYS.init.enable("privoxy")
+       else
+               return SYS.init.disable("privoxy")
+       end
+end
+
+-- hostname --------------------------------------------------------------------
+local hn       = ns:taboption("local", Value, "hostname")
+hn.title       = string.format(HELP, "HOSTNAME", "Hostname" )
+hn.description = translate("The hostname shown on the CGI pages.")
+hn.placeholder = SYS.hostname()
+hn.optional    = true
+hn.rmempty     = true
+
+-- user-manual -----------------------------------------------------------------
+local um       = ns:taboption("local", Value, "user_manual")
+um.title       = string.format(HELP, "USER-MANUAL", "User Manual" )
+um.description = translate("Location of the Privoxy User Manual.")
+um.placeholder = "http://www.privoxy.org/user-manual/"
+um.optional    = true
+um.rmempty     = true
+
+-- admin-address ---------------------------------------------------------------
+local aa       = ns:taboption("local", Value, "admin_address")
+aa.title_base  = "Admin Email"
+aa.title       = string.format(HELP, "ADMIN-ADDRESS", aa.title_base )
+aa.description = translate("An email address to reach the Privoxy administrator.")
+aa.placeholder = "privoxy.admin@example.com"
+aa.optional    = true
+aa.rmempty     = true
+function aa.validate(self, value)
+       if not value or #value == 0 then
+               return ""
+       end
+       if not (value:match("[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")) then
+               return nil, err_tab_local(self.title_base, translate("Invalid email address") )
+       end
+       return value
+end
+
+-- proxy-info-url --------------------------------------------------------------
+local piu      = ns:taboption("local", Value, "proxy_info_url")
+piu.title      = string.format(HELP, "PROXY-INFO-URL", "Proxy Info URL" )
+piu.description        = translate("A URL to documentation about the local Privoxy setup, configuration or policies.")
+piu.optional   = true
+piu.rmempty    = true
+
+-- trust-info-url --------------------------------------------------------------
+local tiu      = ns:taboption("local", Value, "trust_info_url")
+tiu.title      = string.format(HELP, "TRUST-INFO-URL", "Trust Info URLs" )
+tiu.description        = translate("A URL to be displayed in the error page that users will see if access to an untrusted page is denied.")
+               .. [[<br /><strong>]]
+               .. translate("The value of this option only matters if the experimental trust mechanism has been activated.")
+               .. [[</strong>]]
+tiu.optional   = true
+tiu.rmepty     = true
+
+-- tab: filter -- ##############################################################
+
+-- logdir ----------------------------------------------------------------------
+local ld       = ns:taboption("filter", Value, "logdir")
+ld.title_base  = "Log Directory"
+ld.title       = string.format(HELP, "LOGDIR", ld.title_base )
+ld.description = translate("The directory where all logging takes place (i.e. where the logfile is located).")
+               .. [[<br />]]
+               .. translate("No trailing '/', please.")
+ld.default     = "/var/log"
+ld.rmempty     = false
+function ld.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
+       elseif not NXFS.access(value) then
+               return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+       else
+               return value
+       end
+end
+
+-- logfile ---------------------------------------------------------------------
+local lf       = ns:taboption("filter", Value, "logfile")
+lf.title_base  = "Log File"
+lf.title       = string.format(HELP, "LOGFILE", lf.title_base )
+lf.description = translate("The log file to use. File name, relative to log directory.")
+lf.default     = "privoxy.log"
+lf.rmempty     = false
+function lf.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No File given!") )
+       else
+               return value
+       end
+end
+
+-- confdir ---------------------------------------------------------------------
+local cd       = ns:taboption("filter", Value, "confdir")
+cd.title_base  = "Configuration Directory"
+cd.title       = string.format(HELP, "CONFDIR", cd.title_base )
+cd.description = translate("The directory where the other configuration files are located.")
+               .. [[<br />]]
+               .. translate("No trailing '/', please.")
+cd.default     = "/etc/privoxy"
+cd.rmempty     = false
+function cd.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
+       elseif not NXFS.access(value) then
+               return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+       else
+               return value
+       end
+end
+
+-- templdir --------------------------------------------------------------------
+local tld      = ns:taboption("filter", Value, "templdir")
+tld.title_base = "Template Directory"
+tld.title      = string.format(HELP, "TEMPLDIR", tld.title_base )
+tld.description        = translate("An alternative directory where the templates are loaded from.")
+               .. [[<br />]]
+               .. translate("No trailing '/', please.")
+tld.placeholder        = "/etc/privoxy/templates"
+tld.rmempty    = true
+function tld.validate(self, value)
+       if not NXFS.access(value) then
+               return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
+       else
+               return value
+       end
+end
+
+-- temporary-directory ---------------------------------------------------------
+local td       = ns:taboption("filter", Value, "temporary_directory")
+td.title_base  = "Temporary Directory"
+td.title       = string.format(HELP, "TEMPORARY-DIRECTORY", td.title_base )
+td.description = translate("A directory where Privoxy can create temporary files.")
+               .. [[<br /><strong>]]
+               .. translate("Only when using 'external filters', Privoxy has to create temporary files.")
+               .. [[</strong>]]
+td.rmempty     = true
+
+-- actionsfile -----------------------------------------------------------------
+local af       = ns:taboption("filter", DynamicList, "actionsfile")
+af.title_base  = "Action Files"
+af.title       = string.format(HELP, "ACTIONSFILE", af.title_base)
+af.description = translate("The actions file(s) to use. Multiple actionsfile lines are permitted, and are in fact recommended!")
+               .. [[<br /><strong>match-all.action := </strong>]]
+               .. translate("Actions that are applied to all sites and maybe overruled later on.")
+               .. [[<br /><strong>default.action := </strong>]]
+               .. translate("Main actions file")
+               .. [[<br /><strong>user.action := </strong>]]
+               .. translate("User customizations")
+af.rmempty     = false
+function af.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
+       end
+       local confdir = cd:formvalue(ns.section)
+       local err     = false
+       local file    = ""
+       if type(value) == "table" then
+               local x
+               for _, x in ipairs(value) do
+                       if x and #x > 0 then
+                               if not NXFS.access(confdir .."/".. x) then
+                                       err  = true
+                                       file = x
+                                       break   -- break/leave for on error
+                               end
+                       end
+               end
+       else
+               if not NXFS.access(confdir .."/".. value) then
+                       err  = true
+                       file = value
+               end
+       end
+       if err then
+               return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file)
+       end
+       return value
+end
+
+-- filterfile ------------------------------------------------------------------
+local ff       = ns:taboption("filter", DynamicList, "filterfile")
+ff.title_base  = "Filter files"
+ff.title       = string.format(HELP, "FILTERFILE", ff.title_base )
+ff.description = translate("The filter files contain content modification rules that use regular expressions.")
+ff.rmempty     = false
+function ff.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
+       end
+       local confdir = cd:formvalue(ns.section)
+       local err     = false
+       local file    = ""
+       if type(value) == "table" then
+               local x
+               for _, x in ipairs(value) do
+                       if x and #x > 0 then
+                               if not NXFS.access(confdir .."/".. x) then
+                                       err  = true
+                                       file = x
+                                       break   -- break/leave for on error
+                               end
+                       end
+               end
+       else
+               if not NXFS.access(confdir .."/".. value) then
+                       err  = true
+                       file = value
+               end
+       end
+       if err then
+               return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
+       end
+       return value
+end
+
+-- trustfile -------------------------------------------------------------------
+local tf       = ns:taboption("filter", Value, "trustfile")
+tf.title_base  = "Trust file"
+tf.title       = string.format(HELP, "TRUSTFILE", tf.title_base )
+tf.description = translate("The trust mechanism is an experimental feature for building white-lists "
+               .."and should be used with care.")
+               .. [[<br /><strong>]]
+               .. translate("It is NOT recommended for the casual user.")
+               .. [[</strong>]]
+tf.placeholder = "user.trust"
+tf.rmempty     = true
+function tf.validate(self, value)
+       local confdir = cd:formvalue(ns.section)
+       local err     = false
+       local file    = ""
+       if type(value) == "table" then
+               local x
+               for _, x in ipairs(value) do
+                       if x and #x > 0 then
+                               if not NCFS.access(confdir .."/".. x) then
+                                       err  = true
+                                       file = x
+                                       break   -- break/leave for on error
+                               end
+                       end
+               end
+       else
+               if not NXFS.access(confdir .."/".. value) then
+                       err  = true
+                       file = value
+               end
+       end
+       if err then
+               return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
+       end
+       return value
+end
+
+-- tab: access -- ##############################################################
+
+-- listen-address --------------------------------------------------------------
+local la       = ns:taboption("access", DynamicList, "listen_address")
+la.title_base  = "Listen addresses"
+la.title       = string.format(HELP, "LISTEN-ADDRESS", la.title_base )
+la.description = translate("The address and TCP port on which Privoxy will listen for client requests.")
+               .. [[<br />]]
+               .. translate("Syntax: ")
+               .. "IPv4:Port / [IPv6]:Port / Host:Port"
+la.default     = "127.0.0.1:8118"
+la.rmempty     = false
+function la.validate(self, value)
+       if not value or #value == 0 then
+               return nil, err_tab_access(self.title_base, translate("Mandatory Input: No Data given!") )
+       end
+
+       local function check_value(v)
+               local _ret = UTIL.split(v, "]:")
+               local _ip
+               if _ret[2] then -- ip6 with port
+                       _ip   = string.gsub(_ret[1], "%[", "")  -- remove "[" at beginning
+                       if not DTYP.ip6addr(_ip) then
+                               return translate("Mandatory Input: No valid IPv6 address given!")
+                       elseif not DTYP.port(_ret[2]) then
+                               return translate("Mandatory Input: No valid Port given!")
+                       else
+                               return nil
+                       end
+               end
+               _ret = UTIL.split(v, ":")
+               if not _ret[2] then
+                       return translate("Mandatory Input: No Port given!")
+               end
+               if #_ret[1] > 0 and not DTYP.host(_ret[1]) then -- :8118 is valid address
+                       return translate("Mandatory Input: No valid IPv4 address or host given!")
+               elseif not DTYP.port(_ret[2]) then
+                       return translate("Mandatory Input: No valid Port given!")
+               else
+                       return nil
+               end
+       end
+
+       local err   = ""
+       local entry = ""
+       if type(value) == "table" then
+               local x
+               for _, x in ipairs(value) do
+                       if x and #x > 0 then
+                               err = check_value(x)
+                               if err then
+                                       entry = x
+                                       break
+                               end
+                       end
+               end
+       else
+               err = check_value(value)
+               entry = value
+       end
+       if err then
+               return nil, string.format(err_tab_access(self.title_base, err .. " - %s"), entry )
+       end
+       return value
+end
+
+-- permit-access ---------------------------------------------------------------
+local pa       = ns:taboption("access", DynamicList, "permit_access")
+pa.title       = string.format(HELP, "ACLS", "Permit access" )
+pa.description = translate("Who can access what.")
+               .. [[<br /><strong>]]
+               .. translate("Please read Privoxy manual for details!")
+               .. [[</strong>]]
+pa.rmempty     = true
+
+-- deny-access -----------------------------------------------------------------
+local da       = ns:taboption("access", DynamicList, "deny_access")
+da.title       = string.format(HELP, "ACLS", "Deny Access" )
+da.description = translate("Who can access what.")
+               .. [[<br /><strong>]]
+               .. translate("Please read Privoxy manual for details!")
+               .. [[</strong>]]
+da.rmempty     = true
+
+-- buffer-limit ----------------------------------------------------------------
+local bl       = ns:taboption("access", Value, "buffer_limit")
+bl.title_base  = "Buffer Limit"
+bl.title       = string.format(HELP, "BUFFER-LIMIT", bl.title_base )
+bl.description = translate("Maximum size (in KB) of the buffer for content filtering.")
+               .. [[<br />]]
+               .. translate("Value range 1 to 4096, no entry defaults to 4096")
+bl.default     = 4096
+bl.rmempty     = true
+function bl.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_access(self.title_base, translate("Value is not a number") )
+       elseif v < 1 or v > 4096 then
+               return nil, err_tab_access(self.title_base, translate("Value not between 1 and 4096") )
+       elseif v == self.default then
+               return ""       -- dont need to save default
+       end
+       return value
+end
+
+-- toggle ----------------------------------------------------------------------
+local tgl      = ns:taboption("access", Flag, "toggle")
+tgl.title      = string.format(HELP, "TOGGLE", "Toggle Status" )
+tgl.description        = translate("Enable/Disable filtering when Privoxy starts.")
+               .. [[<br />]]
+               .. translate("Disabled == Transparent Proxy Mode")
+tgl.orientation        = "horizontal"
+tgl.default    = "1"
+tgl.rmempty    = false
+function tgl.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- enable-remote-toggle --------------------------------------------------------
+local ert      = ns:taboption("access", Flag, "enable_remote_toggle")
+ert.title      = string.format(HELP, "ENABLE-REMOTE-TOGGLE", "Enable remote toggle" )
+ert.description        = translate("Whether or not the web-based toggle feature may be used.")
+ert.orientation        = "horizontal"
+ert.rmempty    = true
+function ert.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- enable-remote-http-toggle ---------------------------------------------------
+local eht      = ns:taboption("access", Flag, "enable_remote_http_toggle")
+eht.title      = string.format(HELP, "ENABLE-REMOTE-HTTP-TOGGLE", "Enable remote toggle via HTTP" )
+eht.description        = translate("Whether or not Privoxy recognizes special HTTP headers to change toggle state.")
+               .. [[<br /><strong>]]
+               .. translate("This option will be removed in future releases as it has been obsoleted by the more general header taggers.")
+               .. [[</strong>]]
+eht.orientation        = "horizontal"
+eht.rmempty    = true
+function eht.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- enable-edit-actions ---------------------------------------------------------
+local eea      = ns:taboption("access", Flag, "enable_edit_actions")
+eea.title      = string.format(HELP, "ENABLE-EDIT-ACTIONS", "Enable action file editor" )
+eea.description        = translate("Whether or not the web-based actions file editor may be used.")
+eea.orientation        = "horizontal"
+eea.rmempty    = true
+function eea.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- enforce-blocks --------------------------------------------------------------
+local eb       = ns:taboption("access", Flag, "enforce_blocks")
+eb.title       = string.format(HELP, "ENFORCE-BLOCKS", "Enforce page blocking" )
+eb.description = translate("If enabled, Privoxy hides the 'go there anyway' link. "
+               .. "The user obviously should not be able to bypass any blocks.")
+eb.orientation = "horizontal"
+eb.rmempty     = true
+function eb.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- tab: forward -- #############################################################
+
+-- enable-proxy-authentication-forwarding --------------------------------------
+local paf      = ns:taboption("forward", Flag, "enable_proxy_authentication_forwarding")
+paf.title      = string.format(HELP, "ENABLE-PROXY-AUTHENTICATION-FORWARDING",
+               translate("Enable proxy authentication forwarding") )
+paf.description        = translate("Whether or not proxy authentication through Privoxy should work.")
+               .. [[<br /><strong>]]
+               .. translate("Enabling this option is NOT recommended if there is no parent proxy that requires authentication!")
+               .. [[</strong>]]
+--paf.orientation      = "horizontal"
+paf.rmempty    = true
+function paf.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- forward ---------------------------------------------------------------------
+local fwd      = ns:taboption("forward", DynamicList, "forward")
+fwd.title      = string.format(HELP, "FORWARD", "Forward HTTP" )
+fwd.description        = translate("To which parent HTTP proxy specific requests should be routed.")
+               .. [[<br />]]
+               .. translate("Syntax: target_pattern http_parent[:port]")
+fwd.rmempty    = true
+
+-- forward-socks4 --------------------------------------------------------------
+local fs4      = ns:taboption("forward", DynamicList, "forward_socks4")
+fs4.title      = string.format(HELP, "SOCKS", "Forward SOCKS 4" )
+fs4.description        = translate("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.")
+               .. [[<br />]]
+               .. translate("Syntax: target_pattern socks_proxy[:port] http_parent[:port]")
+fs4.rmempty    = true
+
+-- forward-socks4a -------------------------------------------------------------
+local f4a      = ns:taboption("forward", DynamicList, "forward_socks4a")
+f4a.title      = string.format(HELP, "SOCKS", "Forward SOCKS 4A" )
+f4a.description = fs4.description
+f4a.rmempty    = true
+
+-- forward-socks5 --------------------------------------------------------------
+local fs5      = ns:taboption("forward", DynamicList, "forward_socks5")
+fs5.title      = string.format(HELP, "SOCKS", "Forward SOCKS 5" )
+fs5.description = fs4.description
+fs5.rmempty    = true
+
+-- forward-socks5t -------------------------------------------------------------
+local f5t      = ns:taboption("forward", DynamicList, "forward_socks5t")
+f5t.title      = string.format(HELP, "SOCKS", "Forward SOCKS 5t" )
+f5t.description = fs4.description
+f5t.rmempty    = true
+
+-- tab: misc -- ################################################################
+
+-- accept-intercepted-requests -------------------------------------------------
+local air      = ns:taboption("misc", Flag, "accept_intercepted_requests")
+air.title      = string.format(HELP, "ACCEPT-INTERCEPTED-REQUESTS", "Accept intercepted requests" )
+air.description        = translate("Whether intercepted requests should be treated as valid.")
+air.orientation        = "horizontal"
+air.rmempty    = true
+function air.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- allow-cgi-request-crunching -------------------------------------------------
+local crc      = ns:taboption("misc", Flag, "allow_cgi_request_crunching")
+crc.title      = string.format(HELP, "ALLOW-CGI-REQUEST-CRUNCHING", "Allow CGI request crunching" )
+crc.description        = translate("Whether requests to Privoxy's CGI pages can be blocked or redirected.")
+crc.orientation        = "horizontal"
+crc.rmempty    = true
+function crc.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- split-large-forms -----------------------------------------------------------
+local slf      = ns:taboption("misc", Flag, "split_large_forms")
+slf.title      = string.format(HELP, "SPLIT-LARGE-FORMS", "Split large forms" )
+slf.description        = translate("Whether the CGI interface should stay compatible with broken HTTP clients.")
+slf.orientation        = "horizontal"
+slf.rmempty    = true
+function slf.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- keep-alive-timeout ----------------------------------------------------------
+local kat      = ns:taboption("misc", Value, "keep_alive_timeout")
+kat.title_base = "Keep-alive timeout"
+kat.title      = string.format(HELP, "KEEP-ALIVE-TIMEOUT", kat.title_base)
+kat.description        = translate("Number of seconds after which an open connection will no longer be reused.")
+kat.rmempty    = true
+function kat.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+       elseif v < 1 then
+               return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+       end
+       return value
+end
+
+-- tolerate-pipelining ---------------------------------------------------------
+local tp       = ns:taboption("misc", Flag, "tolerate_pipelining")
+tp.title       = string.format(HELP, "TOLERATE-PIPELINING", "Tolerate pipelining" )
+tp.description = translate("Whether or not pipelined requests should be served.")
+tp.orientation = "horizontal"
+tp.rmempty     = true
+function tp.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- default-server-timeout ------------------------------------------------------
+local dst      = ns:taboption("misc", Value, "default_server_timeout")
+dst.title_base = "Default server timeout"
+dst.title      = string.format(HELP, "DEFAULT-SERVER-TIMEOUT", dst.title_base)
+dst.description        = translate("Assumed server-side keep-alive timeout (in seconds) if not specified by the server.")
+dst.rmempty    = true
+function dst.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+       elseif v < 1 then
+               return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+       end
+       return value
+end
+
+-- connection-sharing ----------------------------------------------------------
+local cs       = ns:taboption("misc", Flag, "connection_sharing")
+cs.title       = string.format(HELP, "CONNECTION-SHARING", "Connection sharing" )
+cs.description = translate("Whether or not outgoing connections that have been kept alive should be shared between different incoming connections.")
+cs.orientation = "horizontal"
+cs.rmempty     = true
+function cs.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- socket-timeout --------------------------------------------------------------
+local st       = ns:taboption("misc", Value, "socket_timeout")
+st.title_base  = "Socket timeout"
+st.title       = string.format(HELP, "SOCKET-TIMEOUT", st.title_base )
+st.description = translate("Number of seconds after which a socket times out if no data is received.")
+st.default     = 300
+st.rmempty     = true
+function st.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+       elseif v < 1 then
+               return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+       elseif v == self.default then
+               return ""       -- dont need to save default
+       end
+       return value
+end
+
+-- max-client-connections ------------------------------------------------------
+local mcc      = ns:taboption("misc", Value, "max_client_connections")
+mcc.title_base = "Max. client connections"
+mcc.title      = string.format(HELP, "MAX-CLIENT-CONNECTIONS", mcc.title_base )
+mcc.description        = translate("Maximum number of client connections that will be served.")
+mcc.default    = 128
+mcc.rmempty    = true
+function mcc.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+       elseif v < 1 then
+               return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
+       elseif v == self.default then
+               return ""       -- dont need to save default
+       end
+       return value
+end
+
+-- handle-as-empty-doc-returns-ok ----------------------------------------------
+local her      = ns:taboption("misc", Flag, "handle_as_empty_doc_returns_ok")
+her.title      = string.format(HELP, "HANDLE-AS-EMPTY-DOC-RETURNS-OK", "Handle as empty doc returns ok" )
+her.description        = translate("The status code Privoxy returns for pages blocked with +handle-as-empty-document.")
+her.orientation        = "horizontal"
+her.rmempty    = true
+function her.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- enable-compression ----------------------------------------------------------
+local ec       = ns:taboption("misc", Flag, "enable_compression")
+ec.title       = string.format(HELP, "ENABLE-COMPRESSION", "Enable compression" )
+ec.description = translate("Whether or not buffered content is compressed before delivery.")
+ec.orientation = "horizontal"
+ec.rmempty     = true
+function ec.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- compression-level -----------------------------------------------------------
+local cl       = ns:taboption("misc", Value, "compression_level")
+cl.title_base  = "Compression level"
+cl.title       = string.format(HELP, "COMPRESSION-LEVEL", cl.title_base )
+cl.description = translate("The compression level that is passed to the zlib library when compressing buffered content.")
+cl.default     = 1
+cl.rmempty     = true
+function cl.validate(self, value)
+       local v = tonumber(value)
+       if not v then
+               return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
+       elseif v < 0 or v > 9 then
+               return nil, err_tab_misc(self.title_base, translate("Value not between 0 and 9") )
+       elseif v == self.default then
+               return ""       -- don't need to save default
+       end
+       return value
+end
+
+-- client-header-order ---------------------------------------------------------
+local cho      = ns:taboption("misc", Value, "client_header_order")
+cho.title      = string.format(HELP, "CLIENT-HEADER-ORDER", "Client header order" )
+cho.description        = translate("The order in which client headers are sorted before forwarding them.")
+               .. [[<br />]]
+               .. translate("Syntax: Client header names delimited by spaces.")
+cho.rmempty    = true
+
+-- "debug"-tab definition -- ###################################################
+
+-- single-threaded -------------------------------------------------------------
+local st       = ns:taboption("debug", Flag, "single_threaded")
+st.title       = string.format(HELP, "SINGLE-THREADED", "Single Threaded" )
+st.description = translate("Whether to run only one server thread.")
+               .. [[<br /><strong>]]
+               .. translate("This option is only there for debugging purposes. It will drastically reduce performance.")
+               .. [[</strong>]]
+st.rmempty     = true
+function st.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 1 ---------------------------------------------------------------------
+local d0       = ns:taboption("debug", Flag, "debug_1")
+d0.title       = string.format(HELP, "DEBUG", "Debug 1" )
+d0.description = translate("Log the destination for each request Privoxy let through. See also 'Debug 1024'.")
+d0.rmempty     = true
+function d0.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 2 ---------------------------------------------------------------------
+local d1       = ns:taboption("debug", Flag, "debug_2")
+d1.title       = string.format(HELP, "DEBUG", "Debug 2" )
+d1.description = translate("Show each connection status")
+d1.rmempty     = true
+function d1.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 4 ---------------------------------------------------------------------
+local d2       = ns:taboption("debug", Flag, "debug_4")
+d2.title       = string.format(HELP, "DEBUG", "Debug 4" )
+d2.description = translate("Show I/O status")
+d2.rmempty     = true
+function d2.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 8 ---------------------------------------------------------------------
+local d3       = ns:taboption("debug", Flag, "debug_8")
+d3.title       = string.format(HELP, "DEBUG", "Debug 8" )
+d3.description = translate("Show header parsing")
+d3.rmempty     = true
+function d3.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 16 --------------------------------------------------------------------
+local d4       = ns:taboption("debug", Flag, "debug_16")
+d4.title       = string.format(HELP, "DEBUG", "Debug 16" )
+d4.description = translate("Log all data written to the network")
+d4.rmempty     = true
+function d4.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 32 --------------------------------------------------------------------
+local d5       = ns:taboption("debug", Flag, "debug_32")
+d5.title       = string.format(HELP, "DEBUG", "Debug 32" )
+d5.description = translate("Debug force feature")
+d5.rmempty     = true
+function d5.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 64 --------------------------------------------------------------------
+local d6       = ns:taboption("debug", Flag, "debug_64")
+d6.title       = string.format(HELP, "DEBUG", "Debug 64" )
+d6.description = translate("Debug regular expression filters")
+d6.rmempty     = true
+function d6.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 128 -------------------------------------------------------------------
+local d7       = ns:taboption("debug", Flag, "debug_128")
+d7.title       = string.format(HELP, "DEBUG", "Debug 128" )
+d7.description = translate("Debug redirects")
+d7.rmempty     = true
+function d7.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 256 -------------------------------------------------------------------
+local d8       = ns:taboption("debug", Flag, "debug_256")
+d8.title       = string.format(HELP, "DEBUG", "Debug 256" )
+d8.description = translate("Debug GIF de-animation")
+d8.rmempty     = true
+function d8.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 512 -------------------------------------------------------------------
+local d9       = ns:taboption("debug", Flag, "debug_512")
+d9.title       = string.format(HELP, "DEBUG", "Debug 512" )
+d9.description = translate("Common Log Format")
+d9.rmempty     = true
+function d9.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 1024 ------------------------------------------------------------------
+local d10      = ns:taboption("debug", Flag, "debug_1024")
+d10.title      = string.format(HELP, "DEBUG", "Debug 1024" )
+d10.description        = translate("Log the destination for requests Privoxy didn't let through, and the reason why.")
+d10.rmempty    = true
+function d10.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 2048 ------------------------------------------------------------------
+local d11      = ns:taboption("debug", Flag, "debug_2048")
+d11.title      = string.format(HELP, "DEBUG", "Debug 2048" )
+d11.description        = translate("CGI user interface")
+d11.rmempty    = true
+function d11.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 4096 ------------------------------------------------------------------
+local d12      = ns:taboption("debug", Flag, "debug_4096")
+d12.title      = string.format(HELP, "DEBUG", "Debug 4096" )
+d12.description        = translate("Startup banner and warnings.")
+d12.rmempty    = true
+function d12.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 8192 ------------------------------------------------------------------
+local d13      = ns:taboption("debug", Flag, "debug_8192")
+d13.title      = string.format(HELP, "DEBUG", "Debug 8192" )
+d13.description        = translate("Non-fatal errors - *we highly recommended enabling this*")
+d13.rmempty    = true
+function d13.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 16384 -----------------------------------------------------------------
+--[[ TODO ???
+local d14      = ns:taboption("debug", Flag, "debug_16384")
+d14.title      = string.format(HELP, "DEBUG", "Debug 16384" )
+d14.description        = translate("")
+d14.rmempty    = true
+function d14.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+]]--
+
+-- debug 32768 -----------------------------------------------------------------
+local d15      = ns:taboption("debug", Flag, "debug_32768")
+d15.title      = string.format(HELP, "DEBUG", "Debug 32768" )
+d15.description        = translate("Log all data read from the network")
+d15.rmempty    = true
+function d15.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- debug 65536 -----------------------------------------------------------------
+local d16      = ns:taboption("debug", Flag, "debug_65536")
+d16.title      = string.format(HELP, "DEBUG", "Debug 65536" )
+d16.description        = translate("Log the applying actions")
+d16.rmempty    = true
+function d16.parse(self, section)
+       CTRL.flag_parse(self, section)
+end
+
+-- tab: logview -- #############################################################
+
+local lv       = ns:taboption("logview", DummyValue, "_logview")
+lv.template    = "privoxy/detail_logview"
+lv.inputtitle  = translate("Read / Reread log file")
+lv.rows                = 50
+function lv.cfgvalue(self, section)
+       local lfile=self.map:get(ns.section, "logdir") .. "/" .. self.map:get(ns.section, "logfile")
+       if NXFS.access(lfile) then
+               return lfile .. "\n" .. translate("Please press [Read] button")
+       end
+       return lfile .. "\n" .. translate("File not found or empty")
+end
+
+return m
diff --git a/applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_logview.htm
new file mode 100755 (executable)
index 0000000..3e19070
--- /dev/null
@@ -0,0 +1,56 @@
+
+<!-- ++ BEGIN ++ Privoxy ++ detail_logview.htm ++ -->
+<script type="text/javascript">//<![CDATA[
+       function onclick_logview(section, bottom)  {
+               // get elements
+               var txt = document.getElementById("cbid.privoxy.privoxy._logview.txt"); // TextArea
+               if ( !txt ) { return; } // security check
+               var lvXHR = new XHR();
+               lvXHR.get('<%=luci.dispatcher.build_url("admin", "services", "privoxy", "logview")%>', null,
+                       function(x) {
+                               if (x.responseText == "_nodata_")
+                                       txt.value = "<%:File not found or empty%>";
+                               else
+                                       txt.value = x.responseText;
+                               if (bottom)
+                                       txt.scrollTop = txt.scrollHeight;
+                               else
+                                       txt.scrollTop = 0;                      }
+               );
+       }
+//]]></script>
+
+<%+cbi/valueheader%>
+
+<br />
+
+<%
+-- one button on top, one at the buttom
+%>
+<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick="onclick_logview(this.name, false)"
+<%=
+attr("name", section) .. attr("id", cbid .. ".btn1") .. attr("value", self.inputtitle)
+%> />
+
+<br /><br />
+
+<%
+-- set a readable style taken from openwrt theme for textarea#syslog
+-- in openwrt theme there are problems with a width of 100 so we check for theme and set to lower value
+%>
+<textarea style="width: <%if media == "/luci-static/openwrt.org" then%>98.7%<%else%>100%<%end%> ; min-height: 500px; border: 3px solid #cccccc; padding: 5px; font-family: monospace; resize: none;" wrap="off" readonly="readonly"
+<%=
+attr("name", cbid .. ".txt") .. attr("id", cbid .. ".txt") .. ifattr(self.rows, "rows")
+%> >
+<%-=pcdata(self:cfgvalue(section))-%>
+</textarea>
+<br /><br />
+
+<%
+-- one button on top, one at the buttom
+%>
+<input class="cbi-button cbi-input-button" style="align: center; width: 100%" type="button" onclick="onclick_logview(this.name, true)"
+<%= attr("name", section) .. attr("id", cbid .. ".btn2") .. attr("value", self.inputtitle) %> />
+
+<%+cbi/valuefooter%>
+<!-- ++ END ++ Privoxy ++ detail_logview.htm ++ -->
diff --git a/applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm b/applications/luci-app-privoxy/luasrc/view/privoxy/detail_startstop.htm
new file mode 100644 (file)
index 0000000..b9de886
--- /dev/null
@@ -0,0 +1,49 @@
+
+<!-- ++ BEGIN ++ Privoxy ++ detail_startstop.htm ++ -->
+<script type="text/javascript">//<![CDATA[
+
+       // show XHR.poll/XHR.get response on button
+       function _data2elements(x) {
+               var btn = document.getElementById("cbid.privoxy.privoxy._startstop");
+               if ( ! btn ) { return; }        // security check
+               if (x.responseText == "0") {
+                       btn.value = "<%:Start%>";
+                       btn.className = "cbi-button cbi-button-apply";
+                       btn.disabled = false;
+               } else {
+                       btn.value = "PID: " + x.responseText;
+                       btn.className = "cbi-button cbi-button-reset";
+                       btn.disabled = false;
+               }
+       }
+
+       // event handler for start/stop button
+       function onclick_startstop(id) {
+               // do start/stop
+               var btnXHR = new XHR();
+               btnXHR.get('<%=luci.dispatcher.build_url("admin", "services", "privoxy", "startstop")%>', null,
+                       function(x) { _data2elements(x); }
+               );
+       }
+
+       XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "privoxy", "status")%>', null,
+               function(x, data) { _data2elements(x); }
+       );
+
+//]]></script>
+
+<%+cbi/valueheader%>
+
+<% if self:cfgvalue(section) ~= false then
+-- We need to garantie that function cfgvalue run first to set missing parameters
+%>
+       <!-- style="font-size: 100%;" needed for openwrt theme to fix font size -->
+       <!-- type="button" onclick="..." enable standard onclick functionalty   -->
+       <input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" style="font-size: 100%;" type="button" onclick="onclick_startstop(this.id)"
+       <%=
+       attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle) .. ifattr(self.disabled, "disabled")
+       %> />
+<% end %>
+
+<%+cbi/valuefooter%>
+<!-- ++ END ++ Privoxy ++ detail_startstop.htm ++ -->
diff --git a/applications/luci-app-privoxy/po/de/privoxy.po b/applications/luci-app-privoxy/po/de/privoxy.po
new file mode 100644 (file)
index 0000000..6ee3af4
--- /dev/null
@@ -0,0 +1,496 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: luci-app-privoxy\n"
+"POT-Creation-Date: 2015-01-18 21:48+0100\n"
+"PO-Revision-Date: 2015-01-18 21:51+0100\n"
+"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
+"Language-Team: \n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+
+msgid ""
+"A URL to be displayed in the error page that users will see if access to an "
+"untrusted page is denied."
+msgstr ""
+"Ein Link auf der Fehlerseite, der Benutzern angezeigt wird, wenn der Zugang "
+"zu einer nicht vertrauenswürdigen Seite verweigert wird."
+
+msgid ""
+"A URL to documentation about the local Privoxy setup, configuration or "
+"policies."
+msgstr ""
+"Ein Link zur Dokumentation Ã¼ber die lokale Privoxy Konfiguration und die "
+"Sicherheitseinstellungen."
+
+msgid "Access Control"
+msgstr "Zugriffskontrolle"
+
+msgid "Actions that are applied to all sites and maybe overruled later on."
+msgstr ""
+"Aktionen, die für alle Websites angewendet werden, und vielleicht später "
+"überschrieben werden."
+
+msgid "An alternative directory where the templates are loaded from."
+msgstr "Eine alternatives Verzeichnis, aus dem die Vorlagen geladen werden."
+
+msgid "An email address to reach the Privoxy administrator."
+msgstr "Eine E-Mail-Adresse, um die Privoxy-Administrator zu erreichen."
+
+msgid ""
+"Assumed server-side keep-alive timeout (in seconds) if not specified by the "
+"server."
+msgstr ""
+"Angenommenes serverseitiges Keep-Alive-Timeout (in Sekunden), falls nicht "
+"vom Server festgelegt."
+
+msgid "CGI user interface"
+msgstr "Protokolliert die CGI Benutzer Schnittstelle"
+
+msgid "Common Log Format"
+msgstr "Gemeinsames Protokollformat"
+
+msgid ""
+"Configure here the routing of HTTP requests through a chain of multiple "
+"proxies. Note that parent proxies can severely decrease your privacy level. "
+"Also specified here are SOCKS proxies."
+msgstr ""
+"Konfigurieren Sie hier das Weiterleiten von HTTP-Anforderungen durch eine "
+"Kette von mehreren Proxies. Beachten Sie, dass  Ã¼bergeordnete Proxies Ihre "
+"Privatsphäre stark verringern können. Auch hier angegeben werden SOCKS-"
+"Proxies."
+
+msgid "Debug GIF de-animation"
+msgstr "Protokolliert die GIF de-animation"
+
+msgid "Debug force feature"
+msgstr "Protokolliert die 'Force' Eigenschaft"
+
+msgid "Debug redirects"
+msgstr "Protokolliert Weiterleitungen"
+
+msgid "Debug regular expression filters"
+msgstr "Protokolliert Filter für reguläre Ausdrücke"
+
+msgid "Directory does not exist!"
+msgstr "Verzeichnis existiert nicht!"
+
+msgid "Disabled == Transparent Proxy Mode"
+msgstr "Deaktiviert == Transparent Proxy Betrieb"
+
+msgid "Enable proxy authentication forwarding"
+msgstr "Aktivieren die Weiterleitung von Proxy-Authentifizierungen"
+
+msgid ""
+"Enable/Disable autostart of Privoxy on system startup and interface events"
+msgstr ""
+"Aktivieren / Deaktivieren des Autostart von Privoxy beim Systemstart und "
+"Schnittstellenereignissen."
+
+msgid "Enable/Disable filtering when Privoxy starts."
+msgstr "Aktivieren / Deaktivieren der Filterung, wenn Privoxy startet."
+
+msgid "Enabled"
+msgstr "Aktiviert"
+
+msgid ""
+"Enabling this option is NOT recommended if there is no parent proxy that "
+"requires authentication!"
+msgstr ""
+"Die Aktivierung dieser Option wird NICHT empfohlen, wenn es keinen "
+"übergeordneten Proxy gibt, der eine Authentifizierung erfordert!"
+
+msgid "File '%s' not found inside Configuration Directory"
+msgstr "Datei '%s' nicht im Konfigurationsverzeichnis gefunden!"
+
+msgid "File not found or empty"
+msgstr "Datei nicht gefunden oder leer"
+
+msgid "Files and Directories"
+msgstr "Dateien und Verzeichnisse"
+
+msgid "For help use link at the relevant option"
+msgstr ""
+"Für Hilfe zur Verwendung, benutzen Sie die Verknüpfung der betreffenden "
+"Option."
+
+msgid "Forwarding"
+msgstr "Weiterleitung"
+
+msgid ""
+"If enabled, Privoxy hides the 'go there anyway' link. The user obviously "
+"should not be able to bypass any blocks."
+msgstr ""
+"Wenn aktiviert, verbirgt Privoxy den Link 'go there anyway'. Normalerweise "
+"sollten Benutzer nicht in der Lage sein, Blockierungen zu umgehen."
+
+msgid ""
+"If you intend to operate Privoxy for more users than just yourself, it might "
+"be a good idea to let them know how to reach you, what you block and why you "
+"do that, your policies, etc."
+msgstr ""
+"Wenn Sie beabsichtigen, Privoxy für mehr Nutzer als nur sich selbst zu "
+"betreiben, ist es eine gute Idee, sie wissen zu lassen, wie sie Sie "
+"erreichen können, was Sie blockieren und warum Sie das tun, etc."
+
+msgid "Invalid email address"
+msgstr "Ungültige Email Adresse"
+
+msgid "It is NOT recommended for the casual user."
+msgstr "Es wird NICHT für den gelegentlichen Anwender empfohlen."
+
+msgid "Local Set-up"
+msgstr "Lokale Einstellungen"
+
+msgid "Location of the Privoxy User Manual."
+msgstr "Ort des Privoxy Benutzer Handbuches"
+
+msgid "Log File Viewer"
+msgstr "Protokolldatei"
+
+msgid "Log all data read from the network"
+msgstr "Protokolliert alle Daten, die vom Netzwerk gelesen werden."
+
+msgid "Log all data written to the network"
+msgstr "Protokolliert alle Daten, die auf das Netzwerk geschrieben werden."
+
+msgid "Log the applying actions"
+msgstr "Protokiolliert angewendete Aktionen"
+
+msgid ""
+"Log the destination for each request Privoxy let through. See also 'Debug "
+"1024'."
+msgstr ""
+"Protokolliert das Ziel für jede Anforderung die Privoxy durchlässt. Siehe "
+"auch 'Debug 1024'."
+
+msgid ""
+"Log the destination for requests Privoxy didn't let through, and the reason "
+"why."
+msgstr ""
+"Protokolliert das Ziel für Anfragen die Privoxy nicht durchgelassen hat, und "
+"den Grund dafür."
+
+msgid "Logging"
+msgstr "Protokollierung"
+
+msgid "Main actions file"
+msgstr "Wichtige Aktionen-Datei"
+
+msgid "Mandatory Input: No Data given!"
+msgstr "Pflichtfeld: Keine Daten angegeben!"
+
+msgid "Mandatory Input: No Directory given!"
+msgstr "Pflichtfeld: Kein Verzeichnis angegeben!"
+
+msgid "Mandatory Input: No File given!"
+msgstr "Pflichtfeld: Keine Datei angegeben!"
+
+msgid "Mandatory Input: No Port given!"
+msgstr "Pflichtfeld: Kein Port angegeben!"
+
+msgid "Mandatory Input: No files given!"
+msgstr "Pflichtfeld: Keine Dateien angegeben!"
+
+msgid "Mandatory Input: No valid IPv4 address or host given!"
+msgstr ""
+"Pflichtfeld: Keine gültige IPv4 Adresse oder gültiger Hostname angegeben!"
+
+msgid "Mandatory Input: No valid IPv6 address given!"
+msgstr "Pflichtfeld: Keine gültige IPv6 Adresse angegeben!"
+
+msgid "Mandatory Input: No valid Port given!"
+msgstr "Pflichtfeld: Keine gültige Port Nummer angegeben!"
+
+msgid "Maximum number of client connections that will be served."
+msgstr "Maximale Anzahl von Client-Verbindungen."
+
+msgid "Maximum size (in KB) of the buffer for content filtering."
+msgstr "Maximale Größe (in KB) des Puffers für die Inhaltsfilterung."
+
+msgid "Miscellaneous"
+msgstr "Verschiedenes"
+
+msgid "No trailing '/', please."
+msgstr "Bitte kein '/' am Ende."
+
+msgid "Non-fatal errors - *we highly recommended enabling this*"
+msgstr ""
+"Protokolliert nicht schwerwiegende Fehler - * Es wird dringend empfohlen, "
+"dieses zu aktivieren *"
+
+msgid ""
+"Number of seconds after which a socket times out if no data is received."
+msgstr ""
+"Anzahl der Sekunden, nach der eine Socket Timeout erfolgt, wenn keine Daten "
+"empfangen werden."
+
+msgid ""
+"Number of seconds after which an open connection will no longer be reused."
+msgstr ""
+"Anzahl von Sekunden, nach der eine offene Verbindung nicht mehr "
+"wiederverwendet wird."
+
+msgid "Please press [Read] button"
+msgstr "Bitte Protokolldatei einlesen"
+
+msgid "Please read Privoxy manual for details!"
+msgstr "Bitte lesen Sie das Privoxy Handbuch für Details!"
+
+msgid "Please update to the current version!"
+msgstr "Aktualisieren Sie bitte auf die aktuelle Version!"
+
+msgid "Privoxy WEB proxy"
+msgstr "Privoxy WEB proxy"
+
+msgid ""
+"Privoxy can (and normally does) use a number of other files for additional "
+"configuration, help and logging. This section of the configuration file "
+"tells Privoxy where to find those other files."
+msgstr ""
+"Privoxy verwendet  (was in der Regel der Fall ist), eine Reihe von anderen "
+"Dateien für eine zusätzliche Konfiguration, Hilfe und Protokollierung. "
+"Dieser Abschnitt der Konfigurationsdatei definiert, wo diese Dateien zu "
+"finden sind."
+
+msgid ""
+"Privoxy is a non-caching web proxy with advanced filtering capabilities for "
+"enhancing privacy, modifying web page data and HTTP headers, controlling "
+"access, and removing ads and other obnoxious Internet junk."
+msgstr ""
+"Privoxy ist ein non-caching Web-Proxy mit erweiterten Filterfunktion zur "
+"Verbesserung der Privatsphäre. Er modifiziert Webseitendaten und HTTP-"
+"Header, kontrolliert den Zugang und das Entfernen von Anzeigen und anderem "
+"abscheulichen Internet Schrott."
+
+msgid "Read / Reread log file"
+msgstr "Protokolldatei (neu) lesen"
+
+msgid "Show I/O status"
+msgstr "Protokolliert den I/O Status"
+
+msgid "Show each connection status"
+msgstr "Protokolliert jeden Verbindungsstatus"
+
+msgid "Show header parsing"
+msgstr "Protokolliert das 'Header parsing'"
+
+msgid "Software update required"
+msgstr "Softwareaktualisierung nötig"
+
+msgid "Start"
+msgstr "Start"
+
+msgid "Start / Stop"
+msgstr "Start / Stopp"
+
+msgid "Start/Stop Privoxy WEB Proxy"
+msgstr "Start/Stopp Privoxy WEB Proxy"
+
+msgid "Startup banner and warnings."
+msgstr "Protokolliert Start-Meldungen und Warnungen"
+
+msgid "Syntax:"
+msgstr "Syntax:"
+
+msgid "Syntax: Client header names delimited by spaces."
+msgstr "Syntax: Client header Namen getrennt durch Leerzeichen."
+
+msgid "Syntax: target_pattern http_parent[:port]"
+msgstr "Syntax: target_pattern http_parent[:port]"
+
+msgid "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+msgstr "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+
+msgid ""
+"The actions file(s) to use. Multiple actionsfile lines are permitted, and "
+"are in fact recommended!"
+msgstr ""
+"Die zu verwendenden Aktion-Datei(en). Mehrere Dateien sind gestattet und "
+"empfohlen!"
+
+msgid ""
+"The address and TCP port on which Privoxy will listen for client requests."
+msgstr ""
+"Die Adresse und das TCP-Port, auf dem Privoxy auf Client-Anforderungen "
+"wartet."
+
+msgid ""
+"The compression level that is passed to the zlib library when compressing "
+"buffered content."
+msgstr ""
+"Die Komprimierungsstufe (0-9), die der zlib-Bibliothek beim Komprimieren "
+"gepufferten Inhaltes Ã¼bergeben wird."
+
+msgid ""
+"The currently installed 'privoxy' package is not supported by LuCI "
+"application."
+msgstr ""
+"Das aktuell installierte 'privoxy' Paket wird von dieser LuCI Anwendung "
+"NICHT unterstützt."
+
+msgid ""
+"The directory where all logging takes place (i.e. where the logfile is "
+"located)."
+msgstr "Das Verzeichnis in dem die Protokolldatei gespeichert wird."
+
+msgid "The directory where the other configuration files are located."
+msgstr "Das Verzeichnis in dem weitere Konfigurationsdateien gespeichert sind."
+
+msgid ""
+"The filter files contain content modification rules that use regular "
+"expressions."
+msgstr ""
+"Die Filterdateien enthalten Ã„nderung des Inhalts, die reguläre Ausdrücke "
+"als  Regeln verwenden."
+
+msgid "The hostname shown on the CGI pages."
+msgstr "Der Hostname der auf CGI-Seiten angezeigt wird."
+
+msgid "The log file to use. File name, relative to log directory."
+msgstr ""
+"Zu verwendende Protokolldatei. Dateiname relativ zum Protokoll-Verzeichnis."
+
+msgid "The order in which client headers are sorted before forwarding them."
+msgstr ""
+"Die Reihenfolge, in der Client-Header sortiert werden, bevor sie "
+"weitergeleitet werden."
+
+msgid ""
+"The status code Privoxy returns for pages blocked with +handle-as-empty-"
+"document."
+msgstr ""
+"Ob Statuscode 200(OK) oder 403(forbidden) für Seiten gemeldet wird, die "
+"durch den Filter 'handle-as-empty-document' blockiert werden."
+
+msgid ""
+"The trust mechanism is an experimental feature for building white-lists and "
+"should be used with care."
+msgstr ""
+"Der Trust-Mechanismus ist eine experimentelle Funktion für den Aufbau von "
+"White-Listen und sollte mit Vorsicht verwendet werden."
+
+msgid ""
+"The value of this option only matters if the experimental trust mechanism "
+"has been activated."
+msgstr ""
+"Der Wert dieser Option ist nur wirksam, wenn der experimentelle Trust-"
+"Mechanismus aktiviert wurde."
+
+msgid ""
+"This option is only there for debugging purposes. It will drastically reduce "
+"performance."
+msgstr ""
+"Diese Option ist ausschließlich zur Fehlersuche. Es wird drastisch die "
+"Leistung beeinträchtigt."
+
+msgid ""
+"This option will be removed in future releases as it has been obsoleted by "
+"the more general header taggers."
+msgstr "Diese Option wird in zukünftigen Versionen entfernt werden."
+
+msgid ""
+"This tab controls the security-relevant aspects of Privoxy's configuration."
+msgstr ""
+"Diese Registerkarte steuert die sicherheitsrelevanten Aspekte der Privoxy "
+"Konfiguration."
+
+msgid ""
+"Through which SOCKS proxy (and optionally to which parent HTTP proxy) "
+"specific requests should be routed."
+msgstr ""
+"An welchen SOCKS-Proxy (und gegebenenfalls an welchen Ã¼bergeordneten HTTP-"
+"Proxy) spezifischen Anforderungen weitergeleitet werden."
+
+msgid "To which parent HTTP proxy specific requests should be routed."
+msgstr ""
+"An welchen Ã¼bergeordneten HTTP-Proxy spezifischen Anforderungen "
+"weitergeleitet werden."
+
+msgid "User customizations"
+msgstr "Benutzerdefinierte Anpassungen"
+
+msgid "Value is not a number"
+msgstr "Eingabe ist keine Zahl"
+
+msgid "Value not between 0 and 9"
+msgstr "Wert nicht zwischen 0 und 9"
+
+msgid "Value not between 1 and 4096"
+msgstr "Wert nicht zwischen 1 und 4096"
+
+msgid "Value not greater 0 or empty"
+msgstr "Wert nicht größer 0 oder leer"
+
+msgid "Value range 1 to 4096, no entry defaults to 4096"
+msgstr "Wertebereich: 1 bis 4096; Keine Angabe setzt 4096."
+
+msgid "Version"
+msgstr "Version"
+
+msgid "Version Information"
+msgstr "Versionsinformation"
+
+msgid "Whether intercepted requests should be treated as valid."
+msgstr "Ob abgefangen Anfragen als gültig behandelt werden."
+
+msgid ""
+"Whether or not Privoxy recognizes special HTTP headers to change toggle "
+"state."
+msgstr ""
+"Ob Privoxy erkannte spezielle HTTP-Header zur Ã„nderung des Toggle-Status "
+"verwendet.."
+
+msgid "Whether or not buffered content is compressed before delivery."
+msgstr ""
+"Ob gepufferte Inhalte vor der Weiterleitung komprimiert werden oder nicht."
+
+msgid ""
+"Whether or not outgoing connections that have been kept alive should be "
+"shared between different incoming connections."
+msgstr ""
+"Ob ausgehende Verbindungen, die am Leben gehalten werden, für verschiedenen "
+"eingehenden Verbindungen gemeinsam genutzt werden oder nicht."
+
+msgid "Whether or not pipelined requests should be served."
+msgstr "Ob Pipeline-Anfragen bedient werden oder nicht."
+
+msgid "Whether or not proxy authentication through Privoxy should work."
+msgstr ""
+"Ob Proxy-Authentifizierungen durch Privoxy weitergeleitet werden oder nicht."
+
+msgid "Whether or not the web-based actions file editor may be used."
+msgstr "De-/Aktiviert den webbasierte Action-Datei Editor."
+
+msgid "Whether or not the web-based toggle feature may be used."
+msgstr "De-Aktiviert die webbasierte Umschaltfunktion."
+
+msgid "Whether requests to Privoxy's CGI pages can be blocked or redirected."
+msgstr ""
+"Ob Anfragen an Privoxy CGI-Seiten gesperrt oder umgeleitet werden können "
+"oder nicht."
+
+msgid ""
+"Whether the CGI interface should stay compatible with broken HTTP clients."
+msgstr ""
+"Ob die CGI-Schnittstelle mit broken HTTP-Clients kompatibel bleibt oder "
+"nicht."
+
+msgid "Whether to run only one server thread."
+msgstr "Ob nur ein Server-Thread ausgeführt wird."
+
+msgid "Who can access what."
+msgstr "Wer kann auf Was zugreifen."
+
+msgid "installed"
+msgstr "installiert"
+
+msgid "or higher"
+msgstr "oder höher"
+
+msgid "required"
+msgstr "benötigt"
diff --git a/applications/luci-app-privoxy/po/templates/privoxy.pot b/applications/luci-app-privoxy/po/templates/privoxy.pot
new file mode 100644 (file)
index 0000000..8f836be
--- /dev/null
@@ -0,0 +1,405 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid ""
+"A URL to be displayed in the error page that users will see if access to an "
+"untrusted page is denied."
+msgstr ""
+
+msgid ""
+"A URL to documentation about the local Privoxy setup, configuration or "
+"policies."
+msgstr ""
+
+msgid "Access Control"
+msgstr ""
+
+msgid "Actions that are applied to all sites and maybe overruled later on."
+msgstr ""
+
+msgid "An alternative directory where the templates are loaded from."
+msgstr ""
+
+msgid "An email address to reach the Privoxy administrator."
+msgstr ""
+
+msgid ""
+"Assumed server-side keep-alive timeout (in seconds) if not specified by the "
+"server."
+msgstr ""
+
+msgid "CGI user interface"
+msgstr ""
+
+msgid "Common Log Format"
+msgstr ""
+
+msgid ""
+"Configure here the routing of HTTP requests through a chain of multiple "
+"proxies. Note that parent proxies can severely decrease your privacy level. "
+"Also specified here are SOCKS proxies."
+msgstr ""
+
+msgid "Debug GIF de-animation"
+msgstr ""
+
+msgid "Debug force feature"
+msgstr ""
+
+msgid "Debug redirects"
+msgstr ""
+
+msgid "Debug regular expression filters"
+msgstr ""
+
+msgid "Directory does not exist!"
+msgstr ""
+
+msgid "Disabled == Transparent Proxy Mode"
+msgstr ""
+
+msgid "Enable proxy authentication forwarding"
+msgstr ""
+
+msgid ""
+"Enable/Disable autostart of Privoxy on system startup and interface events"
+msgstr ""
+
+msgid "Enable/Disable filtering when Privoxy starts."
+msgstr ""
+
+msgid "Enabled"
+msgstr ""
+
+msgid ""
+"Enabling this option is NOT recommended if there is no parent proxy that "
+"requires authentication!"
+msgstr ""
+
+msgid "File '%s' not found inside Configuration Directory"
+msgstr ""
+
+msgid "File not found or empty"
+msgstr ""
+
+msgid "Files and Directories"
+msgstr ""
+
+msgid "For help use link at the relevant option"
+msgstr ""
+
+msgid "Forwarding"
+msgstr ""
+
+msgid ""
+"If enabled, Privoxy hides the 'go there anyway' link. The user obviously "
+"should not be able to bypass any blocks."
+msgstr ""
+
+msgid ""
+"If you intend to operate Privoxy for more users than just yourself, it might "
+"be a good idea to let them know how to reach you, what you block and why you "
+"do that, your policies, etc."
+msgstr ""
+
+msgid "Invalid email address"
+msgstr ""
+
+msgid "It is NOT recommended for the casual user."
+msgstr ""
+
+msgid "Local Set-up"
+msgstr ""
+
+msgid "Location of the Privoxy User Manual."
+msgstr ""
+
+msgid "Log File Viewer"
+msgstr ""
+
+msgid "Log all data read from the network"
+msgstr ""
+
+msgid "Log all data written to the network"
+msgstr ""
+
+msgid "Log the applying actions"
+msgstr ""
+
+msgid ""
+"Log the destination for each request Privoxy let through. See also 'Debug "
+"1024'."
+msgstr ""
+
+msgid ""
+"Log the destination for requests Privoxy didn't let through, and the reason "
+"why."
+msgstr ""
+
+msgid "Logging"
+msgstr ""
+
+msgid "Main actions file"
+msgstr ""
+
+msgid "Mandatory Input: No Data given!"
+msgstr ""
+
+msgid "Mandatory Input: No Directory given!"
+msgstr ""
+
+msgid "Mandatory Input: No File given!"
+msgstr ""
+
+msgid "Mandatory Input: No Port given!"
+msgstr ""
+
+msgid "Mandatory Input: No files given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid IPv4 address or host given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid IPv6 address given!"
+msgstr ""
+
+msgid "Mandatory Input: No valid Port given!"
+msgstr ""
+
+msgid "Maximum number of client connections that will be served."
+msgstr ""
+
+msgid "Maximum size (in KB) of the buffer for content filtering."
+msgstr ""
+
+msgid "Miscellaneous"
+msgstr ""
+
+msgid "No trailing '/', please."
+msgstr ""
+
+msgid "Non-fatal errors - *we highly recommended enabling this*"
+msgstr ""
+
+msgid ""
+"Number of seconds after which a socket times out if no data is received."
+msgstr ""
+
+msgid ""
+"Number of seconds after which an open connection will no longer be reused."
+msgstr ""
+
+msgid "Please press [Read] button"
+msgstr ""
+
+msgid "Please read Privoxy manual for details!"
+msgstr ""
+
+msgid "Please update to the current version!"
+msgstr ""
+
+msgid "Privoxy WEB proxy"
+msgstr ""
+
+msgid ""
+"Privoxy can (and normally does) use a number of other files for additional "
+"configuration, help and logging. This section of the configuration file "
+"tells Privoxy where to find those other files."
+msgstr ""
+
+msgid ""
+"Privoxy is a non-caching web proxy with advanced filtering capabilities for "
+"enhancing privacy, modifying web page data and HTTP headers, controlling "
+"access, and removing ads and other obnoxious Internet junk."
+msgstr ""
+
+msgid "Read / Reread log file"
+msgstr ""
+
+msgid "Show I/O status"
+msgstr ""
+
+msgid "Show each connection status"
+msgstr ""
+
+msgid "Show header parsing"
+msgstr ""
+
+msgid "Software update required"
+msgstr ""
+
+msgid "Start"
+msgstr ""
+
+msgid "Start / Stop"
+msgstr ""
+
+msgid "Start/Stop Privoxy WEB Proxy"
+msgstr ""
+
+msgid "Startup banner and warnings."
+msgstr ""
+
+msgid "Syntax:"
+msgstr ""
+
+msgid "Syntax: Client header names delimited by spaces."
+msgstr ""
+
+msgid "Syntax: target_pattern http_parent[:port]"
+msgstr ""
+
+msgid "Syntax: target_pattern socks_proxy[:port] http_parent[:port]"
+msgstr ""
+
+msgid ""
+"The actions file(s) to use. Multiple actionsfile lines are permitted, and "
+"are in fact recommended!"
+msgstr ""
+
+msgid ""
+"The address and TCP port on which Privoxy will listen for client requests."
+msgstr ""
+
+msgid ""
+"The compression level that is passed to the zlib library when compressing "
+"buffered content."
+msgstr ""
+
+msgid ""
+"The currently installed 'privoxy' package is not supported by LuCI "
+"application."
+msgstr ""
+
+msgid ""
+"The directory where all logging takes place (i.e. where the logfile is "
+"located)."
+msgstr ""
+
+msgid "The directory where the other configuration files are located."
+msgstr ""
+
+msgid ""
+"The filter files contain content modification rules that use regular "
+"expressions."
+msgstr ""
+
+msgid "The hostname shown on the CGI pages."
+msgstr ""
+
+msgid "The log file to use. File name, relative to log directory."
+msgstr ""
+
+msgid "The order in which client headers are sorted before forwarding them."
+msgstr ""
+
+msgid ""
+"The status code Privoxy returns for pages blocked with +handle-as-empty-"
+"document."
+msgstr ""
+
+msgid ""
+"The trust mechanism is an experimental feature for building white-lists and "
+"should be used with care."
+msgstr ""
+
+msgid ""
+"The value of this option only matters if the experimental trust mechanism "
+"has been activated."
+msgstr ""
+
+msgid ""
+"This option is only there for debugging purposes. It will drastically reduce "
+"performance."
+msgstr ""
+
+msgid ""
+"This option will be removed in future releases as it has been obsoleted by "
+"the more general header taggers."
+msgstr ""
+
+msgid ""
+"This tab controls the security-relevant aspects of Privoxy's configuration."
+msgstr ""
+
+msgid ""
+"Through which SOCKS proxy (and optionally to which parent HTTP proxy) "
+"specific requests should be routed."
+msgstr ""
+
+msgid "To which parent HTTP proxy specific requests should be routed."
+msgstr ""
+
+msgid "User customizations"
+msgstr ""
+
+msgid "Value is not a number"
+msgstr ""
+
+msgid "Value not between 0 and 9"
+msgstr ""
+
+msgid "Value not between 1 and 4096"
+msgstr ""
+
+msgid "Value not greater 0 or empty"
+msgstr ""
+
+msgid "Value range 1 to 4096, no entry defaults to 4096"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
+msgid "Version Information"
+msgstr ""
+
+msgid "Whether intercepted requests should be treated as valid."
+msgstr ""
+
+msgid ""
+"Whether or not Privoxy recognizes special HTTP headers to change toggle "
+"state."
+msgstr ""
+
+msgid "Whether or not buffered content is compressed before delivery."
+msgstr ""
+
+msgid ""
+"Whether or not outgoing connections that have been kept alive should be "
+"shared between different incoming connections."
+msgstr ""
+
+msgid "Whether or not pipelined requests should be served."
+msgstr ""
+
+msgid "Whether or not proxy authentication through Privoxy should work."
+msgstr ""
+
+msgid "Whether or not the web-based actions file editor may be used."
+msgstr ""
+
+msgid "Whether or not the web-based toggle feature may be used."
+msgstr ""
+
+msgid "Whether requests to Privoxy's CGI pages can be blocked or redirected."
+msgstr ""
+
+msgid ""
+"Whether the CGI interface should stay compatible with broken HTTP clients."
+msgstr ""
+
+msgid "Whether to run only one server thread."
+msgstr ""
+
+msgid "Who can access what."
+msgstr ""
+
+msgid "installed"
+msgstr ""
+
+msgid "or higher"
+msgstr ""
+
+msgid "required"
+msgstr ""
diff --git a/applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy b/applications/luci-app-privoxy/root/etc/uci-defaults/luci-privoxy
new file mode 100755 (executable)
index 0000000..3405479
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# no longer needed for "Save and Apply" to restart privoxy
+# luci-app-privoxy calls /etc/init.d/privoxy reload
+uci -q batch <<-EOF >/dev/null
+       delete ucitrack.@privoxy[-1]
+       commit ucitrack
+EOF
+
+rm -f /tmp/luci-indexcache
+
+exit 0
index 4068cdb..0d73832 100644 (file)
@@ -1,23 +1,24 @@
 -- Copyright 2008 Steven Barth <steven@midlink.org>
--- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
+-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
 -- Licensed to the public under the Apache License 2.0.
 
 local uci = require "luci.model.uci".cursor()
 local bit = require "nixio".bit
+local ip  = require "luci.ip"
 
 -------------------- Init --------------------
 
 --
 -- Find link-local address
 --
-LL_PREFIX = luci.ip.IPv6("fe80::/64")
 function find_ll()
-       for _, r in ipairs(luci.sys.net.routes6()) do
-               if LL_PREFIX:contains(r.dest) and r.dest:higher(LL_PREFIX) then
-                       return r.dest:sub(LL_PREFIX)
+       local _, r
+       for _, r in ipairs(ip.routes({ family = 6, dest = "fe80::/64" })) do
+               if r.dest:higher("fe80:0:0:0:ff:fe00:0:0") then
+                       return (r.dest - "fe80::")
                end
        end
-       return luci.ip.IPv6("::")
+       return ip.IPv6("::")
 end
 
 --
@@ -33,15 +34,15 @@ local ipv4_netsz  = uci:get("siit", "ipv4", "netsize")     or "24"
 --
 -- Find IPv4 allocation pool
 --
-local gv4_net = luci.ip.IPv4(ipv4_pool)
+local gv4_net = ip.IPv4(ipv4_pool)
 
 --
 -- Generate ULA
 --
-local ula = luci.ip.IPv6("::/64")
+local ula = ip.IPv6("::/64")
 
 for _, prefix in ipairs({ ula_prefix, ula_global, ula_subnet }) do
-       ula = ula:add(luci.ip.IPv6(prefix))
+       ula = ula:add(ip.IPv6(prefix))
 end
 
 ula = ula:add(find_ll())
@@ -72,7 +73,7 @@ uci:foreach("wireless", "wifi-device",
 lanip = f:field(Value, "ipaddr", "LAN IPv4 subnet")
 function lanip.formvalue(self, section)
        local val = self.map:formvalue(self:cbid(section))
-       local net = luci.ip.IPv4("%s/%i" %{ val, ipv4_netsz })
+       local net = ip.IPv4("%s/%i" %{ val, ipv4_netsz })
 
        if net then
                if gv4_net:contains(net) then
@@ -110,7 +111,7 @@ function mode.write(self, section, value)
        --
        -- Find LAN IPv4 range
        --
-       local lan_net = luci.ip.IPv4(
+       local lan_net = ip.IPv4(
                ( lanip:formvalue(section) or "172.16.0.1" ) .. "/" .. ipv4_netsz
        )
 
@@ -182,7 +183,7 @@ function mode.write(self, section, value)
                })
 
                -- use full siit subnet
-               siit_route = luci.ip.IPv6(siit_prefix .. "/96")
+               siit_route = ip.IPv6(siit_prefix .. "/96")
 
                -- v4 <-> siit route
                uci:delete_all("network", "route",
@@ -212,7 +213,7 @@ function mode.write(self, section, value)
                })
 
                -- derive siit subnet from lan config
-               siit_route = luci.ip.IPv6(
+               siit_route = ip.IPv6(
                        siit_prefix .. "/" .. (96 + lan_net:prefix())
                ):add(lan_net[2])
 
@@ -301,7 +302,7 @@ function mode.write(self, section, value)
 
        -- siit0 route
        uci:delete_all("network", "route6",
-               function(s) return siit_route:contains(luci.ip.IPv6(s.target)) end)
+               function(s) return siit_route:contains(ip.IPv6(s.target)) end)
 
        uci:section("network", "route6", nil, {
                interface = "siit0",
index 97d0400..4add435 100644 (file)
@@ -23,14 +23,26 @@ function index()
        page.leaf   = true
 end
 
+function ip_to_mac(ip)
+       local ipc = require "luci.ip"
+       local i, n
+
+       for i, n in ipairs(ipc.neighbors()) do
+               if n.mac and n.dest and n.dest:equal(ip) then
+                       return n.mac
+               end
+       end
+end
+
 function action_dispatch()
        local uci = luci.model.uci.cursor_state()
-       local mac = luci.sys.net.ip4mac(luci.http.getenv("REMOTE_ADDR")) or ""
+       local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR")) or ""
        local access = false
 
        uci:foreach("luci_splash", "lease", function(s)
                if s.mac and s.mac:lower() == mac then access = true end
        end)
+
        uci:foreach("luci_splash", "whitelist", function(s)
                if s.mac and s.mac:lower() == mac then access = true end
        end)
@@ -51,13 +63,13 @@ function blacklist()
 end
 
 function action_activate()
-       local ip = luci.http.getenv("REMOTE_ADDR") or "127.0.0.1"
-       local mac = luci.sys.net.ip4mac(ip:match("^[\[::ffff:]*(%d+.%d+%.%d+%.%d+)\]*$"))
+       local ipc = require "luci.ip"
+       local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1") or ""
        local uci_state = require "luci.model.uci".cursor_state()
        local blacklisted = false
        if mac and luci.http.formvalue("accept") then
                uci:foreach("luci_splash", "blacklist",
-                       function(s) if s.mac:lower() == mac or s.mac == mac then blacklisted = true end
+                       function(s) if s.mac and s.mac:lower() == mac then blacklisted = true end
                end)
                if blacklisted then     
                        luci.http.redirect(luci.dispatcher.build_url("splash" ,"blocked"))
index 67bb2fc..831fa75 100644 (file)
@@ -9,6 +9,7 @@ local utl = require "luci.util"
 local ipt = require "luci.sys.iptparser".IptParser()
 local uci = require "luci.model.uci".cursor_state()
 local wat = require "luci.tools.webadmin"
+local ipc = require "luci.ip"
 local fs  = require "nixio.fs"
 
 local clients = { }
@@ -100,10 +101,12 @@ if fs.access(leasefile) then
        end
 end
 
-for i, a in ipairs(luci.sys.net.arptable()) do
-       local c = clients[a["HW address"]:lower()]
-       if c and not c.ip then
-               c.ip = a["IP address"]
+for i, n in ipairs(ipc.neighbors({ family = 4 })) do
+       if n.mac and n.dest then
+               local c = clients[n.mac]
+               if c and not c.ip then
+                       c.ip = n.dest:string()
+               end
        end
 end
 
index 0f8bdc2..2870dbe 100755 (executable)
@@ -2,14 +2,12 @@
 
 utl = require "luci.util"
 sys = require "luci.sys"
+ipc = require "luci.ip"
 
-require("luci.model.uci")
-require("luci.sys.iptparser")
 
 -- Init state session
-local uci = luci.model.uci.cursor_state()
-local ipt = luci.sys.iptparser.IptParser()
-local net = sys.net
+local uci = require "luci.model.uci".cursor_state()
+local ipt = require "luci.sys.iptparser".IptParser()
 local fs = require "nixio.fs"
 local ip = require "luci.ip"
 
@@ -139,6 +137,36 @@ function ipvalid(ipaddr)
        return false
 end
 
+function mac_to_ip(mac)
+       local ipaddr = nil
+       ipc.neighbors({ family = 4 }, function(n)
+               if n.mac == mac and n.dest then
+                       ipaddr = n.dest:string()
+               end
+       end)
+       return ipaddr
+end
+
+function mac_to_dev(mac)
+       local dev = nil
+       ipc.neighbors({ family = 4 }, function(n)
+               if n.mac == mac and n.dev then
+                       dev = n.dev
+               end
+       end)
+       return dev
+end
+
+function ip_to_mac(ip)
+       local mac = nil
+       ipc.neighbors({ family = 4 }, function(n)
+               if n.mac and n.dest and n.dest:equal(ip) then
+                       mac = n.mac
+               end
+       end)
+       return mac
+end
+
 function main(argv)
        local cmd = table.remove(argv, 1)
        local arg = argv[1]
@@ -157,7 +185,6 @@ function main(argv)
 
                lock()
 
-               local arp_cache      = net.arptable()
                local leased_macs    = get_known_macs("lease")
                local blacklist_macs = get_known_macs("blacklist")
                local whitelist_macs = get_known_macs("whitelist")
@@ -167,17 +194,12 @@ function main(argv)
                        if adr:find(":") then
                                mac = adr:lower()
                        else
-                               for _, e in ipairs(arp_cache) do
-                                       if e["IP address"] == adr then
-                                               mac = e["HW address"]:lower()
-                                               break
-                                       end
-                               end
+                               mac = ip_to_mac(adr)
                        end
 
                        if mac and cmd == "add-rules" then
                                if leased_macs[mac] then
-                                       add_lease(mac, arp_cache, true)
+                                       add_lease(mac, true)
                                elseif blacklist_macs[mac] then
                                        add_blacklist_rule(mac)
                                elseif whitelist_macs[mac] then
@@ -277,15 +299,6 @@ function main(argv)
        end
 end
 
--- Get current arp cache
-function get_arpcache()
-       local arpcache = { }
-       for _, entry in ipairs(net.arptable()) do
-               arpcache[entry["HW address"]:lower()] = { entry["Device"]:lower(), entry["IP address"]:lower() }
-       end
-       return arpcache
-end
-
 -- Get a list of known mac addresses
 function get_known_macs(list)
        local leased_macs = { }
@@ -355,17 +368,11 @@ function convert_mac_to_secname(mac)
 end
 
 -- Add a lease to state and invoke add_rule
-function add_lease(mac, arp, no_uci)
+function add_lease(mac, no_uci)
        mac = mac:lower()
 
        -- Get current ip address
-       local ipaddr
-       for _, entry in ipairs(arp or net.arptable()) do
-               if entry["HW address"]:lower() == mac then
-                       ipaddr = entry["IP address"]
-                       break
-               end
-       end
+       local ipaddr = mac_to_ip(mac)
 
        -- Add lease if there is an ip addr
        if ipaddr then
@@ -598,8 +605,6 @@ function sync()
        uci:revert("luci_splash_leases")
 
         
-       local arpcache = get_arpcache()
-
        local blackwhitelist = uci:get_all("luci_splash")
        local whitelist_total = 0
        local whitelist_online = 0
@@ -618,7 +623,7 @@ function sync()
                                leasecount = leasecount + 1
 
                                 -- only count leases_online for connected clients
-                                if arpcache[v.mac] then
+                               if mac_to_ip(v.mac) then
                                        leases_online = leases_online + 1
                                 end
 
@@ -643,7 +648,7 @@ function sync()
                        whitelist_total = whitelist_total + 1
                        if s.mac then
                                local mac = s.mac:lower()
-                               if arpcache[mac] then
+                               if mac_to_ip(mac) then
                                        whitelist_online = whitelist_online + 1
                                end
                        end
@@ -652,7 +657,7 @@ function sync()
                        blacklist_total = blacklist_total + 1
                        if s.mac then
                                local mac = s.mac:lower()
-                               if arpcache[mac] then
+                               if mac_to_ip(mac) then
                                        blacklist_online = blacklist_online + 1
                                end
                        end
@@ -693,7 +698,6 @@ end
 
 -- Show client info
 function list()
-       local arpcache = get_arpcache()
        -- Find traffic usage
        local function traffic(lease)
                local traffic_in  = 0
@@ -722,12 +726,11 @@ function list()
                if s[".type"] == "lease" and s.mac then
                        local ti, to = traffic(s)
                        local mac = s.mac:lower()
-                       local arp = arpcache[mac]
                        print(string.format(
                                "%-17s  %-15s  %-9s  %3dm  %-7s  %7dKB  %7dKB",
                                mac, s.ipaddr, "leased",
                                math.floor(( os.time() - tonumber(s.start) ) / 60),
-                               arp and arp[1] or "?", ti, to
+                               mac_to_dev(mac) or "?", ti, to
                        ))
                end
        end
@@ -738,11 +741,10 @@ function list()
        ) do
                if (s[".type"] == "whitelist" or s[".type"] == "blacklist") and s.mac then
                        local mac = s.mac:lower()
-                       local arp = arpcache[mac]
                        print(string.format(
                                "%-17s  %-15s  %-9s  %4s  %-7s  %9s  %9s",
-                               mac, arp and arp[2] or "?", s[".type"],
-                               "- ", arp and arp[1] or "?", "-", "-"
+                               mac, mac_to_ip(mac) or "?", s[".type"],
+                               "- ", mac_to_dev(mac) or "?", "-", "-"
                        ))
                end
        end
index 329341d..c532b4a 100644 (file)
@@ -150,7 +150,6 @@ function statistics_render()
                if png then
                        luci.http.prepare_content("image/png")
                        l12.pump.all(l12.source.file(png), luci.http.write)
-                       png:close()
                end
                return
        end
index 8fc697f..790bf29 100644 (file)
@@ -19,7 +19,7 @@ function index()
 end
 
 function act_status()
-       local ipt = io.popen("iptables --line-numbers -t nat -xnvL MINIUPNPD")
+       local ipt = io.popen("iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null")
        if ipt then
                local fwd = { }
                while true do
diff --git a/build/luadoc/doc.lua b/build/luadoc/doc.lua
new file mode 100755 (executable)
index 0000000..383dde2
--- /dev/null
@@ -0,0 +1,126 @@
+#!/usr/bin/env lua
+-------------------------------------------------------------------------------
+-- LuaDoc launcher.
+-- @release $Id: luadoc.lua.in,v 1.1 2008/02/17 06:42:51 jasonsantos Exp $
+-------------------------------------------------------------------------------
+
+--local source = debug.getinfo(1).source or ""
+--local mypath = source:match("@(.+)/[^/]+")
+
+--package.path = package.path .. ";" .. mypath .. "/?.lua;" .. mypath .. "/?/init.lua"
+
+require "luadoc.init"
+
+-------------------------------------------------------------------------------
+-- Print version number.
+
+local function print_version ()
+       print (string.format("%s\n%s\n%s", 
+               luadoc._VERSION, 
+               luadoc._DESCRIPTION, 
+               luadoc._COPYRIGHT))
+end
+
+-------------------------------------------------------------------------------
+-- Print usage message.
+
+local function print_help ()
+       print ("Usage: "..arg[0]..[[ [options|files]
+Generate documentation from files. Available options are:
+  -d path                      output directory path
+  -t path                      template directory path
+  -h, --help                   print this help and exit
+      --noindexpage            do not generate global index page
+      --nofiles                do not generate documentation for files
+      --nomodules              do not generate documentation for modules
+      --doclet doclet_module   doclet module to generate output
+      --taglet taglet_module   taglet module to parse input code
+  -q, --quiet                  suppress all normal output
+  -v, --version                print version information]])
+end
+
+local function off_messages (arg, i, options)
+       options.verbose = nil
+end
+
+-------------------------------------------------------------------------------
+-- Process options. TODO: use getopts.
+-- @class table
+-- @name OPTIONS
+
+local OPTIONS = {
+       d = function (arg, i, options)
+               local dir = arg[i+1]
+               if string.sub (dir, -2) ~= "/" then
+                       dir = dir..'/'
+               end
+               options.output_dir = dir
+               return 1
+       end,
+       t = function (arg, i, options)
+               local dir = arg[i+1]
+               if string.sub (dir, -2) ~= "/" then
+                       dir = dir..'/'
+               end
+               options.template_dir = dir
+               return 1
+       end,
+       h = print_help,
+       help = print_help,
+       q = off_messages,
+       quiet = off_messages,
+       v = print_version,
+       version = print_version,
+       doclet = function (arg, i, options)
+               options.doclet = arg[i+1]
+               return 1
+       end,
+       taglet = function (arg, i, options)
+               options.taglet = arg[i+1]
+               return 1
+       end,
+}
+
+-------------------------------------------------------------------------------
+
+local function process_options (arg)
+       local files = {}
+       local options = require "luadoc.config"
+       local i = 1
+       while i <= #arg do
+               local argi = arg[i]
+               if string.sub (argi, 1, 1) ~= '-' then
+                       table.insert (files, argi)
+               else
+                       local opt = string.sub (argi, 2)
+                       if string.sub (opt, 1, 1) == '-' then
+                               opt = string.gsub (opt, "%-", "")
+                       end
+                       if OPTIONS[opt] then
+                               if OPTIONS[opt] (arg, i, options) then
+                                       i = i + 1
+                               end
+                       else
+                               options[opt] = 1
+                       end
+               end
+               i = i+1
+       end
+       return files, options
+end 
+
+-------------------------------------------------------------------------------
+-- Main function. Process command-line parameters and call luadoc processor.
+
+function main (arg)
+       -- Process options
+       local argc = #arg
+       if argc < 1 then
+               print_help ()
+               return
+       end
+       local files, options = process_options (arg)
+       return luadoc.main(files, options)
+end
+
+main(arg)
diff --git a/build/luadoc/luadoc/config.lua b/build/luadoc/luadoc/config.lua
new file mode 100644 (file)
index 0000000..9e4b9de
--- /dev/null
@@ -0,0 +1,34 @@
+-------------------------------------------------------------------------------
+-- LuaDoc configuration file. This file contains the default options for 
+-- luadoc operation. These options can be overriden by the command line tool
+-- @see luadoc.print_help
+-- @release $Id: config.lua,v 1.6 2007/04/18 14:28:39 tomas Exp $
+-------------------------------------------------------------------------------
+
+module "luadoc.config"
+
+-------------------------------------------------------------------------------
+-- Default options
+-- @class table
+-- @name default_options
+-- @field output_dir default output directory for generated documentation, used
+-- by several doclets
+-- @field taglet parser used to analyze source code input
+-- @field doclet documentation generator
+-- @field template_dir directory with documentation templates, used by the html
+-- doclet
+-- @field verbose command line tool configuration to output processing 
+-- information
+
+local default_options = {
+       output_dir = "",
+       taglet = "luadoc.taglet.standard",
+       doclet = "luadoc.doclet.html",
+       -- TODO: find a way to define doclet specific options
+       template_dir = "luadoc/doclet/html/",
+       nomodules = false,
+       nofiles = false,
+       verbose = true,
+}
+
+return default_options
diff --git a/build/luadoc/luadoc/doclet/debug.lua b/build/luadoc/luadoc/doclet/debug.lua
new file mode 100644 (file)
index 0000000..0b75f84
--- /dev/null
@@ -0,0 +1,46 @@
+-----------------------------------------------------------------
+-- LuaDoc debugging facilities.
+-- @release $Id: debug.lua,v 1.3 2007/04/18 14:28:39 tomas Exp $
+-----------------------------------------------------------------
+
+module "luadoc.doclet.debug"
+
+function printline()
+       print(string.rep('-', 79))
+end
+
+-----------------------------------------------------------------
+-- Print debug information about document
+-- @param doc Table with the structured documentation.
+
+function start (doc)
+       print("Files:")
+       for _, filepath in ipairs(doc.files) do
+               print('\t', filepath)
+       end
+       printline()
+
+       print("Modules:")
+       for _, modulename in ipairs(doc.modules) do
+               print('\t', modulename)
+       end
+       printline()
+       
+       for i, v in pairs(doc.files) do
+               print('\t', i, v)
+       end
+       printline()
+       for i, v in pairs(doc.files[doc.files[1]]) do
+               print(i, v)
+       end
+       
+       printline()
+       for i, v in pairs(doc.files[doc.files[1]].doc[1]) do
+               print(i, v)
+       end
+       printline()
+       print("Params")
+       for i, v in pairs(doc.files[doc.files[1]].doc[1].param) do
+               print(i, v)
+       end
+end
diff --git a/build/luadoc/luadoc/doclet/formatter.lua b/build/luadoc/luadoc/doclet/formatter.lua
new file mode 100644 (file)
index 0000000..2d72538
--- /dev/null
@@ -0,0 +1,84 @@
+-------------------------------------------------------------------------------
+-- Doclet to format source code according to LuaDoc standard tags. This doclet
+-- (re)write .lua files adding missing standard tags. Texts are formatted to
+-- 80 columns and function parameters are added based on code analysis.
+--
+-- @release $Id: formatter.lua,v 1.5 2007/04/18 14:28:39 tomas Exp $
+-------------------------------------------------------------------------------
+
+local util = require "luadoc.util"
+local assert, ipairs, pairs, type = assert, ipairs, pairs, type
+local string = require"string"
+local table = require"table"
+
+module "luadoc.doclet.formatter"
+
+options = {
+       output_dir = "./",
+}
+
+-------------------------------------------------------------------------------
+-- Assembly the output filename for an input file.
+-- TODO: change the name of this function
+function out_file (filename)
+       local h = filename
+       h = options.output_dir..h
+       return h
+end
+
+-------------------------------------------------------------------------------
+-- Generate a new lua file for each input lua file. If the user does not 
+-- specify a different output directory input files will be rewritten.
+-- @param doc documentation table
+
+function start (doc)
+       local todo = "<TODO>"
+       
+       -- Process files
+       for i, file_doc in ipairs(doc.files) do
+               -- assembly the filename
+               local filename = out_file(file_doc.name)
+               luadoc.logger:info(string.format("generating file `%s'", filename))
+
+               -- TODO: confirm file overwrite
+               local f = posix.open(filename, "w")
+               assert(f, string.format("could not open `%s' for writing", filename))
+
+               for _, block in ipairs(file_doc.doc) do
+
+                       -- write reorganized comments
+                       f:write(string.rep("-", 80).."\n")
+                       
+                       -- description
+                       f:write(util.comment(util.wrap(block.description, 77)))
+                       f:write("\n")
+                       
+                       if block.class == "function" then
+                               -- parameters
+                               table.foreachi(block.param, function (_, param_name)
+                                       f:write(util.comment(util.wrap(string.format("@param %s %s", param_name, block.param[param_name] or todo), 77)))
+                                       f:write("\n")
+                               end)
+                               
+                               -- return
+                               if type(block.ret) == "table" then
+                                       table.foreachi(block.ret, function (_, ret)
+                                               f:write(util.comment(util.wrap(string.format("@return %s", ret), 77)).."\n")
+                                       end)
+                               else
+                                       f:write(util.comment(util.wrap(string.format("@return %s", block.ret or todo), 77)).."\n")
+                               end
+                       end
+                       
+                       -- TODO: usage
+                       -- TODO: see
+
+                       -- write code
+                       for _, line in ipairs(block.code) do
+                               f:write(line.."\n")
+                       end
+               end
+               
+               f:close()
+       end
+end
diff --git a/build/luadoc/luadoc/doclet/html.lua b/build/luadoc/luadoc/doclet/html.lua
new file mode 100644 (file)
index 0000000..e77fb74
--- /dev/null
@@ -0,0 +1,275 @@
+-------------------------------------------------------------------------------
+-- Doclet that generates HTML output. This doclet generates a set of html files
+-- based on a group of templates. The main templates are:
+-- <ul>
+-- <li>index.lp: index of modules and files;</li>
+-- <li>file.lp: documentation for a lua file;</li>
+-- <li>module.lp: documentation for a lua module;</li>
+-- <li>function.lp: documentation for a lua function. This is a
+-- sub-template used by the others.</li>
+-- </ul>
+--
+-- @release $Id: html.lua,v 1.29 2007/12/21 17:50:48 tomas Exp $
+-------------------------------------------------------------------------------
+
+local assert, getfenv, ipairs, loadstring, pairs, setfenv, tostring, tonumber, type = assert, getfenv, ipairs, loadstring, pairs, setfenv, tostring, tonumber, type
+local io = require"io"
+local posix = require "nixio.fs"
+local lp = require "luadoc.lp"
+local luadoc = require"luadoc"
+local package = package
+local string = require"string"
+local table = require"table"
+
+module "luadoc.doclet.html"
+
+-------------------------------------------------------------------------------
+-- Looks for a file `name' in given path. Removed from compat-5.1
+-- @param path String with the path.
+-- @param name String with the name to look for.
+-- @return String with the complete path of the file found
+--     or nil in case the file is not found.
+
+local function search (path, name)
+  for c in string.gfind(path, "[^;]+") do
+    c = string.gsub(c, "%?", name)
+    local f = io.open(c)
+    if f then   -- file exist?
+      f:close()
+      return c
+    end
+  end
+  return nil    -- file not found
+end
+
+-------------------------------------------------------------------------------
+-- Include the result of a lp template into the current stream.
+
+function include (template, env)
+       -- template_dir is relative to package.path
+       local templatepath = options.template_dir .. template
+
+       -- search using package.path (modified to search .lp instead of .lua
+       local search_path = string.gsub(package.path, "%.lua", "")
+       local templatepath = search(search_path, templatepath)
+       assert(templatepath, string.format("template `%s' not found", template))
+
+       env = env or {}
+       env.table = table
+       env.io = io
+       env.lp = lp
+       env.ipairs = ipairs
+       env.tonumber = tonumber
+       env.tostring = tostring
+       env.type = type
+       env.luadoc = luadoc
+       env.options = options
+
+       return lp.include(templatepath, env)
+end
+
+-------------------------------------------------------------------------------
+-- Returns a link to a html file, appending "../" to the link to make it right.
+-- @param html Name of the html file to link to
+-- @return link to the html file
+
+function link (html, from)
+       local h = html
+       from = from or ""
+       string.gsub(from, "/", function () h = "../" .. h end)
+       return h
+end
+
+-------------------------------------------------------------------------------
+-- Returns the name of the html file to be generated from a module.
+-- Files with "lua" or "luadoc" extensions are replaced by "html" extension.
+-- @param modulename Name of the module to be processed, may be a .lua file or
+-- a .luadoc file.
+-- @return name of the generated html file for the module
+
+function module_link (modulename, doc, from)
+       -- TODO: replace "." by "/" to create directories?
+       -- TODO: how to deal with module names with "/"?
+       assert(modulename)
+       assert(doc)
+       from = from or ""
+
+       if doc.modules[modulename] == nil then
+--             logger:error(string.format("unresolved reference to module `%s'", modulename))
+               return
+       end
+
+       local href = "modules/" .. modulename .. ".html"
+       string.gsub(from, "/", function () href = "../" .. href end)
+       return href
+end
+
+-------------------------------------------------------------------------------
+-- Returns the name of the html file to be generated from a lua(doc) file.
+-- Files with "lua" or "luadoc" extensions are replaced by "html" extension.
+-- @param to Name of the file to be processed, may be a .lua file or
+-- a .luadoc file.
+-- @param from path of where am I, based on this we append ..'s to the
+-- beginning of path
+-- @return name of the generated html file
+
+function file_link (to, from)
+       assert(to)
+       from = from or ""
+
+       local href = to
+       href = string.gsub(href, "lua$", "html")
+       href = string.gsub(href, "luadoc$", "html")
+       href = "files/" .. href
+       string.gsub(from, "/", function () href = "../" .. href end)
+       return href
+end
+
+-------------------------------------------------------------------------------
+-- Returns a link to a function or to a table
+-- @param fname name of the function or table to link to.
+-- @param doc documentation table
+-- @param kind String specying the kinf of element to link ("functions" or "tables").
+
+function link_to (fname, doc, module_doc, file_doc, from, kind)
+       assert(fname)
+       assert(doc)
+       from = from or ""
+       kind = kind or "functions"
+
+       if file_doc then
+               for _, func_name in pairs(file_doc[kind]) do
+                       if func_name == fname then
+                               return file_link(file_doc.name, from) .. "#" .. fname
+                       end
+               end
+       end
+
+       if module_doc and module_doc[kind] then
+               for func_name, tbl in pairs(module_doc[kind]) do
+                       if func_name == fname then
+                               return "#" .. fname
+                       end
+               end
+       end
+
+       local _, _, modulename, fname = string.find(fname, "^(.-)[%.%:]?([^%.%:]*)$")
+       assert(fname)
+
+       -- if fname does not specify a module, use the module_doc
+       if string.len(modulename) == 0 and module_doc then
+               modulename = module_doc.name
+       end
+
+       local module_doc = doc.modules[modulename]
+       if not module_doc then
+--             logger:error(string.format("unresolved reference to function `%s': module `%s' not found", fname, modulename))
+               return
+       end
+
+       for _, func_name in pairs(module_doc[kind]) do
+               if func_name == fname then
+                       return module_link(modulename, doc, from) .. "#" .. fname
+               end
+       end
+
+--     logger:error(string.format("unresolved reference to function `%s' of module `%s'", fname, modulename))
+end
+
+-------------------------------------------------------------------------------
+-- Make a link to a file, module or function
+
+function symbol_link (symbol, doc, module_doc, file_doc, from)
+       assert(symbol)
+       assert(doc)
+
+       local href =
+--             file_link(symbol, from) or
+               module_link(symbol, doc, from) or
+               link_to(symbol, doc, module_doc, file_doc, from, "functions") or
+               link_to(symbol, doc, module_doc, file_doc, from, "tables")
+
+       if not href then
+               logger:error(string.format("unresolved reference to symbol `%s'", symbol))
+       end
+
+       return href or ""
+end
+
+-------------------------------------------------------------------------------
+-- Assembly the output filename for an input file.
+-- TODO: change the name of this function
+function out_file (filename)
+       local h = filename
+       h = string.gsub(h, "lua$", "html")
+       h = string.gsub(h, "luadoc$", "html")
+       h = "files/" .. h
+--     h = options.output_dir .. string.gsub (h, "^.-([%w_]+%.html)$", "%1")
+       h = options.output_dir .. h
+       return h
+end
+
+-------------------------------------------------------------------------------
+-- Assembly the output filename for a module.
+-- TODO: change the name of this function
+function out_module (modulename)
+       local h = modulename .. ".html"
+       h = "modules/" .. h
+       h = options.output_dir .. h
+       return h
+end
+
+-----------------------------------------------------------------
+-- Generate the output.
+-- @param doc Table with the structured documentation.
+
+function start (doc)
+       -- Generate index file
+       if (#doc.files > 0 or #doc.modules > 0) and (not options.noindexpage) then
+               local filename = options.output_dir.."index.html"
+               logger:info(string.format("generating file `%s'", filename))
+               local f = posix.open(filename, "w")
+               assert(f, string.format("could not open `%s' for writing", filename))
+               io.output(f)
+               include("index.lp", { doc = doc })
+               f:close()
+       end
+
+       -- Process modules
+       if not options.nomodules then
+               for _, modulename in ipairs(doc.modules) do
+                       local module_doc = doc.modules[modulename]
+                       -- assembly the filename
+                       local filename = out_module(modulename)
+                       logger:info(string.format("generating file `%s'", filename))
+
+                       local f = posix.open(filename, "w")
+                       assert(f, string.format("could not open `%s' for writing", filename))
+                       io.output(f)
+                       include("module.lp", { doc = doc, module_doc = module_doc })
+                       f:close()
+               end
+       end
+
+       -- Process files
+       if not options.nofiles then
+               for _, filepath in ipairs(doc.files) do
+                       local file_doc = doc.files[filepath]
+                       -- assembly the filename
+                       local filename = out_file(file_doc.name)
+                       logger:info(string.format("generating file `%s'", filename))
+
+                       local f = posix.open(filename, "w")
+                       assert(f, string.format("could not open `%s' for writing", filename))
+                       io.output(f)
+                       include("file.lp", { doc = doc, file_doc = file_doc} )
+                       f:close()
+               end
+       end
+
+       -- copy extra files
+       local f = posix.open(options.output_dir.."luadoc.css", "w")
+       io.output(f)
+       include("luadoc.css")
+       f:close()
+end
diff --git a/build/luadoc/luadoc/doclet/html/constant.lp b/build/luadoc/luadoc/doclet/html/constant.lp
new file mode 100644 (file)
index 0000000..2e35392
--- /dev/null
@@ -0,0 +1,28 @@
+<%
+if module_doc then
+       from = "modules/"..module_doc.name
+elseif file_doc then
+       from = "files/.."..file_doc.name
+else
+       from = ""
+end
+%>
+
+<dt><%=const.private and "local " or ""%><a name="<%=const.name%>"></a><strong><%=const.name:gsub(".+%.","")%></strong></dt>
+<dd>
+<%=const.description or ""%>
+
+<%if type(const.see) == "string" then %>
+<h3>See also:</h3>
+       <a href="<%=const.see%>"><%=const.see%></a>
+<%elseif type(const.see) == "table" and #const.see > 0 then %>
+<h3>See also:</h3>
+<ul>
+       <%for i = 1, #const.see do%>
+       <li><a href="<%=luadoc.doclet.html.symbol_link(const.see[i], doc, module_doc, file_doc, from)%>">
+               <%=const.see[i]:gsub(".+%.","")%>
+       </a>
+       <%end%>
+</ul
+<%end%>
+</dd>
diff --git a/build/luadoc/luadoc/doclet/html/file.lp b/build/luadoc/luadoc/doclet/html/file.lp
new file mode 100644 (file)
index 0000000..68f4864
--- /dev/null
@@ -0,0 +1,112 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+    <title>Reference</title>
+    <link rel="stylesheet" href="<%=luadoc.doclet.html.link('luadoc.css', 'files/'..file_doc.name)%>" type="text/css" />
+       <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
+</head>
+
+<body>
+<div id="container">
+
+<div id="product">
+       <div id="product_logo"></div>
+       <div id="product_name"><big><b></b></big></div>
+       <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<%=luadoc.doclet.html.include("menu.lp", { doc=doc, file_doc=file_doc })%>
+
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h1>File <code><%=file_doc.name%></code></h1>
+
+<%if file_doc.description then%>
+<p><%=file_doc.description%></p>
+<%end%>
+<%if file_doc.author then%>
+<p><b><%= #file_doc.author>1 and "Authors" or "Author" %>:</b>
+<table class="authors_list">
+<%for _, author in ipairs(file_doc.author) do%>
+       <tr><td class="name"><%= author %></td></tr>
+<%end%>
+</table>
+</p>
+<%end%>
+<%if file_doc.copyright then%>
+<p>Copyright &copy;<%=file_doc.copyright%></p>
+<%end%>
+<%if file_doc.release then%>
+<p><small><b>Release:</b> <%=file_doc.release%></small></p>
+<%end%>
+
+<%if #file_doc.functions > 0 then%>
+<h2>Functions</h2>
+<table class="function_list">
+<%for _, func_name in ipairs(file_doc.functions) do
+  local func_data = file_doc.functions[func_name]%>
+       <tr>
+       <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_name%></a>&nbsp;(<%=table.concat(func_data.param or {}, ", ")%>)</td>
+       <td class="summary"><%=func_data.summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+
+<%if #file_doc.tables > 0 then%>
+<h2>Tables</h2>
+<table class="table_list">
+<%for _, tab_name in ipairs(file_doc.tables) do%>
+       <tr>
+       <td class="name" nowrap><a href="#<%=tab_name%>"><%=tab_name%></a></td>
+       <td class="summary"><%=file_doc.tables[tab_name].summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+
+<br/>
+<br/>
+
+
+
+<%if #file_doc.functions > 0 then%>
+<h2><a name="functions"></a>Functions</h2>
+<dl class="function">
+<%for _, func_name in ipairs(file_doc.functions) do%>
+<%=luadoc.doclet.html.include("function.lp", { doc=doc, file_doc=file_doc, func=file_doc.functions[func_name] })%>
+<%end%>
+</dl>
+<%end%>
+
+
+<%if #file_doc.tables > 0 then%>
+<h2><a name="tables"></a>Tables</h2>
+<dl class="table">
+<%for _, tab_name in ipairs(file_doc.tables) do%>
+<%=luadoc.doclet.html.include("table.lp", { doc=doc, file_doc=file_doc, tab=file_doc.tables[tab_name] })%>
+<%end%>
+</dl>
+<%end%>
+
+
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+       <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" --> 
+</body>
+</html>
diff --git a/build/luadoc/luadoc/doclet/html/function.lp b/build/luadoc/luadoc/doclet/html/function.lp
new file mode 100644 (file)
index 0000000..29d403e
--- /dev/null
@@ -0,0 +1,64 @@
+<%
+if module_doc then
+       from = "modules/"..module_doc.name
+elseif file_doc then
+       from = "files/.."..file_doc.name
+else
+       from = ""
+end
+%>
+
+<dt><%=func.private and "local " or ""%><a name="<%=func.name%>"></a><strong><%=func.printname%></strong>&nbsp;(<%=table.concat(func.param or {}, ", ")%>)</dt>
+<dd>
+<%=func.description or ""%>
+
+<%if type(func.param) == "table" and #func.param > 0 then%>
+<h3>Parameters</h3>
+<ul>
+       <%for p = 1, #func.param do%>
+       <li>
+         <%=func.param[p]%>: <%=func.param[func.param[p]] or ""%>
+       </li>
+       <%end%>
+</ul>
+<%end%>
+
+
+<%if type(func.usage) == "string" then%>
+<h3>Usage:</h3>
+<%=func.usage%>
+<%elseif type(func.usage) == "table" then%>
+<h3>Usage</h3>
+<ul>
+       <%for _, usage in ipairs(func.usage) do%>
+       <li><%= usage %>
+       <%end%>
+</ul>
+<%end%>
+
+<%if type(func.ret) == "string" then%>
+<h3>Return value:</h3>
+<%=func.ret%>
+<%elseif type(func.ret) == "table" then%>
+<h3>Return values:</h3>
+<ol>
+       <%for _, ret in ipairs(func.ret) do%>
+       <li><%= ret %>
+       <%end%>
+</ol>
+<%end%>
+
+<%if type(func.see) == "string" then %>
+<h3>See also:</h3>
+       <a href="<%=func.see%>"><%=func.see%></a>
+<%elseif type(func.see) == "table" and #func.see > 0 then %>
+<h3>See also:</h3>
+<ul>
+       <%for i = 1, #func.see do%>
+       <li><a href="<%=luadoc.doclet.html.symbol_link(func.see[i], doc, module_doc, file_doc, from)%>">
+               <%=(oop and func.see[i]:gsub("%.",":") or func.see[i]:gsub(".+%.",""))%>
+       </a>
+       <%end%>
+</ul>
+<%end%>
+</dd>
diff --git a/build/luadoc/luadoc/doclet/html/index.lp b/build/luadoc/luadoc/doclet/html/index.lp
new file mode 100644 (file)
index 0000000..b4b9f5c
--- /dev/null
@@ -0,0 +1,67 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+    <title>Reference</title>
+    <link rel="stylesheet" href="<%=luadoc.doclet.html.link("luadoc.css")%>" type="text/css" />
+       <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
+</head>
+
+<body>
+<div id="container">
+
+<div id="product">
+       <div id="product_logo"></div>
+       <div id="product_name"><big><b></b></big></div>
+       <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<%=luadoc.doclet.html.include("menu.lp", { doc=doc })%>
+
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+
+<%if not options.nomodules and #doc.modules > 0 then%>
+<h2>Modules</h2>
+<table class="module_list">
+<!--<tr><td colspan="2">Modules</td></tr>-->
+<%for _, modulename in ipairs(doc.modules) do%>
+       <tr>
+               <td class="name"><a href="<%=luadoc.doclet.html.module_link(modulename, doc)%>"><%=modulename%></a></td>
+               <td class="summary"><%=doc.modules[modulename].summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+
+
+<%if not options.nofiles and #doc.files > 0 then%>
+<h2>Files</h2>
+<table class="file_list">
+<!--<tr><td colspan="2">Files</td></tr>-->
+<%for _, filepath in ipairs(doc.files) do%>
+       <tr>
+               <td class="name"><a href="<%=luadoc.doclet.html.file_link(filepath)%>"><%=filepath%></a></td>
+               <td class="summary"></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+       <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" --> 
+</body>
+</html>
diff --git a/build/luadoc/luadoc/doclet/html/luadoc.css b/build/luadoc/luadoc/doclet/html/luadoc.css
new file mode 100644 (file)
index 0000000..f9f9749
--- /dev/null
@@ -0,0 +1,285 @@
+body { 
+    margin-left: 1em; 
+    margin-right: 1em; 
+    font-family: arial, helvetica, geneva, sans-serif;
+       background-color:#ffffff; margin:0px;
+}
+
+code {
+    font-family: "Andale Mono", monospace; 
+}
+
+tt {
+    font-family: "Andale Mono", monospace; 
+}
+
+body, td, th { font-size: 11pt; }
+
+h1, h2, h3, h4 { margin-left: 0em; }
+
+textarea, pre, tt { font-size:10pt; }
+body, td, th { color:#000000; }
+small { font-size:0.85em; }
+h1 { font-size:1.5em; }
+h2 { font-size:1.25em; }
+h3 { font-size:1.15em; }
+h4 { font-size:1.06em; }
+
+a:link { font-weight:bold; color: #004080; text-decoration: none; }
+a:visited { font-weight:bold; color: #006699; text-decoration: none; }
+a:link:hover { text-decoration:underline; }
+hr { color:#cccccc }
+img { border-width: 0px; }
+
+
+h3 { padding: 1em 0 0.5em; }
+
+p { margin-left: 1em; }
+
+p.name { 
+    font-family: "Andale Mono", monospace; 
+    padding-top: 1em;
+    margin-left: 0em; 
+}
+
+blockquote { margin-left: 3em; }
+
+pre.example {
+    background-color: rgb(245, 245, 245);
+    border-top-width: 1px;
+    border-right-width: 1px;
+    border-bottom-width: 1px;
+    border-left-width: 1px;
+    border-top-style: solid;
+    border-right-style: solid;
+    border-bottom-style: solid;
+    border-left-style: solid;
+    border-top-color: silver;
+    border-right-color: silver;
+    border-bottom-color: silver;
+    border-left-color: silver;
+    padding: 1em;
+    margin-left: 1em;
+    margin-right: 1em;
+    font-family: "Andale Mono", monospace; 
+    font-size: smaller;
+}
+
+
+hr { 
+    margin-left: 0em;
+       background: #00007f; 
+       border: 0px;
+       height: 1px;
+}
+
+ul { list-style-type: disc; }
+
+table.index { border: 1px #00007f; }
+table.index td { text-align: left; vertical-align: top; }
+table.index ul { padding-top: 0em; margin-top: 0em; }
+
+table {
+    border: 1px solid black;
+    border-collapse: collapse;
+    margin: 1em auto;
+}
+th {
+    border: 1px solid black;
+    padding: 0.5em;
+}
+td {
+    border: 1px solid black;
+    padding: 0.5em;
+}
+div.header, div.footer { margin-left: 0em; }
+
+#container
+{
+       margin-left: 1em;
+       margin-right: 1em;
+       background-color: #f0f0f0;
+}
+
+#product
+{
+       text-align: center;
+       border-bottom: 1px solid #cccccc;
+       background-color: #ffffff;
+}
+
+#product big {
+       font-size: 2em;
+}
+
+#product_logo
+{
+}
+
+#product_name
+{
+}
+
+#product_description
+{
+}
+
+#main
+{
+       background-color: #f0f0f0;
+       border-left: 2px solid #cccccc;
+}
+
+#navigation
+{
+       float: left;
+       width: 18em;
+       margin: 0;
+       vertical-align: top;
+       background-color: #f0f0f0;
+       overflow:visible;
+}
+
+#navigation h1 {
+       background-color:#e7e7e7;
+       font-size:1.1em;
+       color:#000000;
+       text-align:left;
+       margin:0px;
+       padding:0.2em;
+       border-top:1px solid #dddddd;
+       border-bottom:1px solid #dddddd;
+}
+
+#navigation ul
+{
+       font-size:1em;
+       list-style-type: none;
+       padding: 0;
+       margin: 1px;
+}
+
+#navigation li
+{
+       text-indent: -1em;
+       margin: 0em 0em 0em 0.5em;
+       display: block;
+       padding: 3px 0px 0px 12px;
+}
+
+#navigation li li a
+{
+       padding: 0px 3px 0px -1em;
+}
+
+#content
+{
+       margin-left: 18em;
+       padding: 1em;
+       border-left: 2px solid #cccccc;
+       border-right: 2px solid #cccccc;
+       background-color: #ffffff;
+}
+
+#about
+{
+       clear: both;
+       margin: 0;
+       padding: 5px;
+       border-top: 2px solid #cccccc;
+       background-color: #ffffff;
+}
+
+@media print {
+       body { 
+               font: 12pt "Times New Roman", "TimeNR", Times, serif;
+       }
+       a { font-weight:bold; color: #004080; text-decoration: underline; }
+       
+       #main\r  {\r              background-color: #ffffff;\r             border-left: 0px;\r      }\r      
+       #container\r     {\r              margin-left: 2%;\r               margin-right: 2%;\r              background-color: #ffffff;\r     }
+       
+       #content\r       {\r              margin-left: 0px;\r              padding: 1em;\r          border-left: 0px;\r              border-right: 0px;\r             background-color: #ffffff;\r     }
+       
+       #navigation\r    {\r              display: none;
+       }
+       pre.example {
+               font-family: "Andale Mono", monospace; 
+               font-size: 10pt;
+               page-break-inside: avoid;
+       }
+}
+
+table.module_list td
+{
+       border-width: 1px;
+       padding: 3px;
+       border-style: solid;
+       border-color: #cccccc;
+}
+table.module_list td.name { background-color: #f0f0f0; }
+table.module_list td.summary { width: 100%; }
+
+table.file_list
+{
+       border-width: 1px;
+       border-style: solid;
+       border-color: #cccccc;
+       border-collapse: collapse;
+}
+table.file_list td
+{
+       border-width: 1px;
+       padding: 3px;
+       border-style: solid;
+       border-color: #cccccc;
+}
+table.file_list td.name { background-color: #f0f0f0; }
+table.file_list td.summary { width: 100%; }
+
+
+table.function_list
+{
+       border-width: 1px;
+       border-style: solid;
+       border-color: #cccccc;
+       border-collapse: collapse;
+}
+table.function_list td
+{
+       border-width: 1px;
+       padding: 3px;
+       border-style: solid;
+       border-color: #cccccc;
+}
+table.function_list td.name { background-color: #f0f0f0; }
+table.function_list td.summary { width: 100%; }
+
+
+table.table_list
+{
+       border-width: 1px;
+       border-style: solid;
+       border-color: #cccccc;
+       border-collapse: collapse;
+}
+table.table_list td
+{
+       border-width: 1px;
+       padding: 3px;
+       border-style: solid;
+       border-color: #cccccc;
+}
+table.table_list td.name { background-color: #f0f0f0; }
+table.table_list td.summary { width: 100%; }
+
+dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
+dl.function dd {padding: 0.5em 0;}
+dl.function h3 {margin: 0; font-size: medium;}
+
+dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;}
+dl.table dd {padding-bottom: 1em;}
+dl.table h3 {padding: 0; margin: 0; font-size: medium;}
+
+#TODO: make module_list, file_list, function_list, table_list inherit from a list
+
diff --git a/build/luadoc/luadoc/doclet/html/menu.lp b/build/luadoc/luadoc/doclet/html/menu.lp
new file mode 100644 (file)
index 0000000..0fe3652
--- /dev/null
@@ -0,0 +1,55 @@
+<%
+if module_doc then
+       from = "modules/"..module_doc.name
+elseif file_doc then
+       from = "files/.."..file_doc.name
+else
+       from = ""
+end
+%>
+
+<h1>LuaDoc</h1>
+<ul>
+       <%if not module_doc and not file_doc then%>
+       <li><strong>Index</strong></li>
+       <%else%>
+       <li><a href="<%=luadoc.doclet.html.link("index.html", from)%>">Index</a></li>
+       <%end%>
+</ul>
+
+
+<!-- Module list -->
+<%if not options.nomodules and #doc.modules > 0 then%>
+<h1>Modules</h1>
+<ul>
+<%for _, modulename in ipairs(doc.modules) do
+       if module_doc and module_doc.name == modulename then%>
+       <li><strong><%=modulename%></strong></li>
+       <%else%>
+       <li>
+               <a href="<%=luadoc.doclet.html.module_link(modulename, doc, from)%>"><%=modulename%></a>
+       </li>
+<%     end
+end%>
+</ul>
+<%end%>
+
+
+<!-- File list -->
+<%if not options.nofiles and #doc.files > 0 then%>
+<h1>Files</h1>
+<ul>
+<%for _, filepath in ipairs(doc.files) do
+       if file_doc and file_doc.name == filepath then%>
+       <li><strong><%=filepath%></strong></li>
+       <%else%>
+       <li>
+               <a href="<%=luadoc.doclet.html.file_link(filepath, from)%>"><%=filepath%></a>
+       </li>
+<%     end
+end%>
+</ul>
+<%end%>
+
+
+
diff --git a/build/luadoc/luadoc/doclet/html/module.lp b/build/luadoc/luadoc/doclet/html/module.lp
new file mode 100644 (file)
index 0000000..0798c1b
--- /dev/null
@@ -0,0 +1,155 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+    <title>Reference</title>
+    <link rel="stylesheet" href="<%=luadoc.doclet.html.link('luadoc.css', 'modules/'..module_doc.name)%>" type="text/css" />
+       <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
+</head>
+
+<body>
+<div id="container">
+
+<div id="product">
+       <div id="product_logo"></div>
+       <div id="product_name"><big><b></b></big></div>
+       <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<%=luadoc.doclet.html.include("menu.lp", { doc=doc, module_doc=module_doc })%>
+<% oop = not not ( module_doc.doc[1] and module_doc.doc[1].cstyle == "instance" ) %>
+
+</div><!-- id="navigation" -->
+
+<div id="content">
+
+<h1><%=( oop and "Object Instance" or "Class" )%> <code><%=module_doc.name%></code></h1>
+
+<p><%=module_doc.description%></p>
+<%if module_doc.author then%>
+<p><b><%= #module_doc.author>1 and "Authors" or "Author" %>:</b>
+<table class="authors_list">
+<%for _, author in ipairs(module_doc.author) do%>
+       <tr><td class="name"><%= author %></td></tr>
+<%end%>
+</table>
+</p>
+<%end%>
+<%if module_doc.copyright then%>
+<p>Copyright&copy; <%=module_doc.copyright%></p>
+<%end%>
+<%if module_doc.release then%>
+<p><small><b>Release:</b> <%=module_doc.release%></small></p>
+<%end%>
+
+<%if #module_doc.constants > 0 then %>
+<h2>Constants</h2>
+<table class="function_list">
+<%for _, const_name in ipairs(module_doc.constants) do
+  local const_data = module_doc.constants[const_name]%>
+       <tr>
+       <td class="name" nowrap><code><%=const_data.private and "local " or ""%><%=(const_name:gsub(".+%.",""))%></code></td>
+       <td class="summary"><%=const_data.summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+<% local funcs = { }; if #module_doc.functions > 0 then %>
+<h2>Functions</h2>
+<table class="function_list">
+<%
+for _, func_name in ipairs(module_doc.functions) do
+  funcs[#funcs+1] = func_name
+end
+
+table.sort(funcs, function(a, b)
+  local func_data_a = module_doc.functions[a]
+  local func_data_b = module_doc.functions[b]
+  local x = func_data_a.sort or a
+  local y = func_data_b.sort or b
+  return x < y
+end)
+
+for _, func_name in ipairs(funcs) do
+  local func_data = module_doc.functions[func_name]
+
+  func_data.printname = func_name:gsub("^%d+#", "")
+  if oop then
+       func_data.printname = func_data.printname:gsub("%.", ":")
+  else
+    func_data.printname = func_data.printname:gsub("^.+%.", "")
+  end
+%>
+       <tr>
+       <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_data.printname%></a>&nbsp;(<%=table.concat(module_doc.functions[func_name].param or {}, ", ")%>)</td>
+       <td class="summary"><%=module_doc.functions[func_name].summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+
+<% local tabs = { }; if #module_doc.tables > 0 then%>
+<h2>Tables</h2>
+<table class="table_list">
+<%
+for _, tab_name in ipairs(module_doc.tables) do
+  tabs[#tabs+1] = tab_name
+end
+
+table.sort(tabs, function(a, b)
+  local tab_data_a = module_doc.tables[a]
+  local tab_data_b = module_doc.tables[b]
+  local x = tab_data_a.sort or a
+  local y = tab_data_b.sort or b
+  return x < y
+end)
+
+for _, tab_name in ipairs(tabs) do
+%>
+       <tr>
+       <td class="name" nowrap><a href="#<%=tab_name%>"><%=tab_name%></a></td>
+       <td class="summary"><%=module_doc.tables[tab_name].summary%></td>
+       </tr>
+<%end%>
+</table>
+<%end%>
+
+
+<br/>
+<br/>
+
+<%if #module_doc.functions > 0 then%>
+<h2><a name="functions"></a>Functions</h2>
+<dl class="function">
+<%for _, func_name in ipairs(funcs) do%>
+<%=luadoc.doclet.html.include("function.lp", { doc=doc, module_doc=module_doc, func=module_doc.functions[func_name], oop=oop })%>
+<%end%>
+</dl>
+<%end%>
+
+<%if #module_doc.tables > 0 then%>
+<h2><a name="tables"></a>Tables</h2>
+<dl class="table">
+<%for _, tab_name in ipairs(tabs) do%>
+<%=luadoc.doclet.html.include("table.lp", { doc=doc, module_doc=module_doc, tab=module_doc.tables[tab_name] })%>
+<%end%>
+</dl>
+<%end%>
+
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+       <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/build/luadoc/luadoc/doclet/html/table.lp b/build/luadoc/luadoc/doclet/html/table.lp
new file mode 100644 (file)
index 0000000..5cd0239
--- /dev/null
@@ -0,0 +1,15 @@
+<dt><a name="<%=tab.name%>"></a><strong><%=tab.name%></strong></dt>
+<dd><%=tab.description%>
+
+<%if type(tab.field) == "table" and #tab.field > 0 then%>
+<em>Fields</em>
+<ul>
+       <%for p = 1, #tab.field do%>
+       <li>
+         <%=tab.field[p]%>: <%=tab.field[tab.field[p]] or ""%>
+       </li>
+       <%end%>
+</ul>
+<%end%>
+
+</dd>
diff --git a/build/luadoc/luadoc/doclet/raw.lua b/build/luadoc/luadoc/doclet/raw.lua
new file mode 100644 (file)
index 0000000..1e880b8
--- /dev/null
@@ -0,0 +1,12 @@
+-----------------------------------------------------------------
+-- @release $Id: raw.lua,v 1.5 2007/04/18 14:28:39 tomas Exp $
+-----------------------------------------------------------------
+
+module "luadoc.doclet.raw"
+
+-----------------------------------------------------------------
+-- Generate the output.
+-- @param doc Table with the structured documentation.
+
+function start (doc)
+end
diff --git a/build/luadoc/luadoc/init.lua b/build/luadoc/luadoc/init.lua
new file mode 100644 (file)
index 0000000..649515d
--- /dev/null
@@ -0,0 +1,50 @@
+-------------------------------------------------------------------------------
+-- LuaDoc main function.
+-- @release $Id: init.lua,v 1.4 2008/02/17 06:42:51 jasonsantos Exp $
+-------------------------------------------------------------------------------
+
+local require = require
+
+local util = require "luadoc.util"
+
+logger = {}
+
+module ("luadoc")
+
+-------------------------------------------------------------------------------
+-- LuaDoc version number.
+
+_COPYRIGHT = "Copyright (c) 2003-2007 The Kepler Project"
+_DESCRIPTION = "Documentation Generator Tool for the Lua language"
+_VERSION = "LuaDoc 3.0.1"
+
+-------------------------------------------------------------------------------
+-- Main function
+-- @see luadoc.doclet.html, luadoc.doclet.formatter, luadoc.doclet.raw
+-- @see luadoc.taglet.standard
+
+function main (files, options)
+       logger = util.loadlogengine(options)
+
+       -- load config file
+       if options.config ~= nil then
+               -- load specified config file
+               dofile(options.config)
+       else
+               -- load default config file
+               require("luadoc.config")
+       end
+       
+       local taglet = require(options.taglet)
+       local doclet = require(options.doclet)
+
+       -- analyze input
+       taglet.options = options
+       taglet.logger = logger
+       local doc = taglet.start(files)
+
+       -- generate output
+       doclet.options = options
+       doclet.logger = logger
+       doclet.start(doc)
+end
diff --git a/build/luadoc/luadoc/lp.lua b/build/luadoc/luadoc/lp.lua
new file mode 100644 (file)
index 0000000..adf84f9
--- /dev/null
@@ -0,0 +1,130 @@
+----------------------------------------------------------------------------
+-- Lua Pages Template Preprocessor.
+--
+-- @release $Id: lp.lua,v 1.7 2007/04/18 14:28:39 tomas Exp $
+----------------------------------------------------------------------------
+
+local assert, error, getfenv, loadstring, setfenv = assert, error, getfenv, loadstring, setfenv
+local find, format, gsub, strsub = string.find, string.format, string.gsub, string.sub
+local concat, tinsert = table.concat, table.insert
+local open = io.open
+
+module (...)
+
+----------------------------------------------------------------------------
+-- function to do output
+local outfunc = "io.write"
+-- accepts the old expression field: `$| <Lua expression> |$'
+local compatmode = true
+
+--
+-- Builds a piece of Lua code which outputs the (part of the) given string.
+-- @param s String.
+-- @param i Number with the initial position in the string.
+-- @param f Number with the final position in the string (default == -1).
+-- @return String with the correspondent Lua code which outputs the part of the string.
+--
+local function out (s, i, f)
+       s = strsub(s, i, f or -1)
+       if s == "" then return s end
+       -- we could use `%q' here, but this way we have better control
+       s = gsub(s, "([\\\n\'])", "\\%1")
+       -- substitute '\r' by '\'+'r' and let `loadstring' reconstruct it
+       s = gsub(s, "\r", "\\r")
+       return format(" %s('%s'); ", outfunc, s)
+end
+
+
+----------------------------------------------------------------------------
+-- Translate the template to Lua code.
+-- @param s String to translate.
+-- @return String with translated code.
+----------------------------------------------------------------------------
+function translate (s)
+       if compatmode then
+               s = gsub(s, "$|(.-)|%$", "<?lua = %1 ?>")
+               s = gsub(s, "<!%-%-$$(.-)$$%-%->", "<?lua %1 ?>")
+       end
+       s = gsub(s, "<%%(.-)%%>", "<?lua %1 ?>")
+       local res = {}
+       local start = 1   -- start of untranslated part in `s'
+       while true do
+               local ip, fp, target, exp, code = find(s, "<%?(%w*)[ \t]*(=?)(.-)%?>", start)
+               if not ip then break end
+               tinsert(res, out(s, start, ip-1))
+               if target ~= "" and target ~= "lua" then
+                       -- not for Lua; pass whole instruction to the output
+                       tinsert(res, out(s, ip, fp))
+               else
+                       if exp == "=" then   -- expression?
+                               tinsert(res, format(" %s(%s);", outfunc, code))
+                       else  -- command
+                               tinsert(res, format(" %s ", code))
+                       end
+               end
+               start = fp + 1
+       end
+       tinsert(res, out(s, start))
+       return concat(res)
+end
+
+
+----------------------------------------------------------------------------
+-- Defines the name of the output function.
+-- @param f String with the name of the function which produces output.
+
+function setoutfunc (f)
+       outfunc = f
+end
+
+----------------------------------------------------------------------------
+-- Turns on or off the compatibility with old CGILua 3.X behavior.
+-- @param c Boolean indicating if the compatibility mode should be used.
+
+function setcompatmode (c)
+       compatmode = c
+end
+
+----------------------------------------------------------------------------
+-- Internal compilation cache.
+
+local cache = {}
+
+----------------------------------------------------------------------------
+-- Translates a template into a Lua function.
+-- Does NOT execute the resulting function.
+-- Uses a cache of templates.
+-- @param string String with the template to be translated.
+-- @param chunkname String with the name of the chunk, for debugging purposes.
+-- @return Function with the resulting translation.
+
+function compile (string, chunkname)
+       local f, err = cache[string]
+       if f then return f end
+       f, err = loadstring (translate (string), chunkname)
+       if not f then error (err, 3) end
+       cache[string] = f
+       return f
+end
+
+----------------------------------------------------------------------------
+-- Translates and executes a template in a given file.
+-- The translation creates a Lua function which will be executed in an
+-- optionally given environment.
+-- @param filename String with the name of the file containing the template.
+-- @param env Table with the environment to run the resulting function.
+
+function include (filename, env)
+       -- read the whole contents of the file
+       local fh = assert (open (filename))
+       local src = fh:read("*a")
+       fh:close()
+       -- translates the file into a function
+       local prog = compile (src, '@'..filename)
+       local _env
+       if env then
+               _env = getfenv (prog)
+               setfenv (prog, env)
+       end
+       prog ()
+end
diff --git a/build/luadoc/luadoc/taglet/standard.lua b/build/luadoc/luadoc/taglet/standard.lua
new file mode 100644 (file)
index 0000000..ef925f8
--- /dev/null
@@ -0,0 +1,567 @@
+-------------------------------------------------------------------------------
+-- @release $Id: standard.lua,v 1.39 2007/12/21 17:50:48 tomas Exp $
+-------------------------------------------------------------------------------
+
+local assert, pairs, tostring, type = assert, pairs, tostring, type
+local io = require "io"
+local posix = require "nixio.fs"
+local luadoc = require "luadoc"
+local util = require "luadoc.util"
+local tags = require "luadoc.taglet.standard.tags"
+local string = require "string"
+local table = require "table"
+
+module 'luadoc.taglet.standard'
+
+-------------------------------------------------------------------------------
+-- Creates an iterator for an array base on a class type.
+-- @param t array to iterate over
+-- @param class name of the class to iterate over
+
+function class_iterator (t, class)
+       return function ()
+               local i = 1
+               return function ()
+                       while t[i] and t[i].class ~= class do
+                               i = i + 1
+                       end
+                       local v = t[i]
+                       i = i + 1
+                       return v
+               end
+       end
+end
+
+-- Patterns for function recognition
+local identifiers_list_pattern = "%s*(.-)%s*"
+local identifier_pattern = "[^%(%s]+"
+local function_patterns = {
+       "^()%s*function%s*("..identifier_pattern..")%s*%("..identifiers_list_pattern.."%)",
+       "^%s*(local%s)%s*function%s*("..identifier_pattern..")%s*%("..identifiers_list_pattern.."%)",
+       "^()%s*("..identifier_pattern..")%s*%=%s*function%s*%("..identifiers_list_pattern.."%)",
+}
+
+-------------------------------------------------------------------------------
+-- Checks if the line contains a function definition
+-- @param line string with line text
+-- @return function information or nil if no function definition found
+
+local function check_function (line)
+       line = util.trim(line)
+
+       local info = table.foreachi(function_patterns, function (_, pattern)
+               local r, _, l, id, param = string.find(line, pattern)
+               if r ~= nil then
+                       return {
+                               name = id,
+                               private = (l == "local"),
+                               param = { } --util.split("%s*,%s*", param),
+                       }
+               end
+       end)
+
+       -- TODO: remove these assert's?
+       if info ~= nil then
+               assert(info.name, "function name undefined")
+               assert(info.param, string.format("undefined parameter list for function `%s'", info.name))
+       end
+
+       return info
+end
+
+-------------------------------------------------------------------------------
+-- Checks if the line contains a module definition.
+-- @param line string with line text
+-- @param currentmodule module already found, if any
+-- @return the name of the defined module, or nil if there is no module
+-- definition
+
+local function check_module (line, currentmodule)
+       line = util.trim(line)
+
+       -- module"x.y"
+       -- module'x.y'
+       -- module[[x.y]]
+       -- module("x.y")
+       -- module('x.y')
+       -- module([[x.y]])
+       -- module(...)
+
+       local r, _, modulename = string.find(line, "^module%s*[%s\"'(%[]+([^,\"')%]]+)")
+       if r then
+               -- found module definition
+               logger:debug(string.format("found module `%s'", modulename))
+               return modulename
+       end
+       return currentmodule
+end
+
+-- Patterns for constant recognition
+local constant_patterns = {
+       "^()%s*([A-Z][A-Z0-9_]*)%s*=",
+       "^%s*(local%s)%s*([A-Z][A-Z0-9_]*)%s*=",
+}
+
+-------------------------------------------------------------------------------
+-- Checks if the line contains a constant definition
+-- @param line string with line text
+-- @return constant information or nil if no constant definition found
+
+local function check_constant (line)
+       line = util.trim(line)
+
+       local info = table.foreachi(constant_patterns, function (_, pattern)
+               local r, _, l, id = string.find(line, pattern)
+               if r ~= nil then
+                       return {
+                               name = id,
+                               private = (l == "local"),
+                       }
+               end
+       end)
+
+       -- TODO: remove these assert's?
+       if info ~= nil then
+               assert(info.name, "constant name undefined")
+       end
+
+       return info
+end
+
+-------------------------------------------------------------------------------
+-- Extracts summary information from a description. The first sentence of each
+-- doc comment should be a summary sentence, containing a concise but complete
+-- description of the item. It is important to write crisp and informative
+-- initial sentences that can stand on their own
+-- @param description text with item description
+-- @return summary string or nil if description is nil
+
+local function parse_summary (description)
+       -- summary is never nil...
+       description = description or ""
+
+       -- append an " " at the end to make the pattern work in all cases
+       description = description.." "
+
+       -- read until the first period followed by a space or tab
+       local summary = string.match(description, "(.-%.)[%s\t]")
+
+       -- if pattern did not find the first sentence, summary is the whole description
+       summary = summary or description
+
+       return summary
+end
+
+-------------------------------------------------------------------------------
+-- @param f file handle
+-- @param line current line being parsed
+-- @param modulename module already found, if any
+-- @return current line
+-- @return code block
+-- @return modulename if found
+
+local function parse_code (f, line, modulename)
+       local code = {}
+       while line ~= nil do
+               if string.find(line, "^[\t ]*%-%-%-") then
+                       -- reached another luadoc block, end this parsing
+                       return line, code, modulename
+               else
+                       -- look for a module definition
+                       modulename = check_module(line, modulename)
+
+                       table.insert(code, line)
+                       line = f:read()
+               end
+       end
+       -- reached end of file
+       return line, code, modulename
+end
+
+-------------------------------------------------------------------------------
+-- Parses the information inside a block comment
+-- @param block block with comment field
+-- @return block parameter
+
+local function parse_comment (block, first_line, modulename)
+
+       -- get the first non-empty line of code
+       local code = table.foreachi(block.code, function(_, line)
+               if not util.line_empty(line) then
+                       -- `local' declarations are ignored in two cases:
+                       -- when the `nolocals' option is turned on; and
+                       -- when the first block of a file is parsed (this is
+                       --      necessary to avoid confusion between the top
+                       --      local declarations and the `module' definition.
+                       if (options.nolocals or first_line) and line:find"^%s*local" then
+                               return
+                       end
+                       return line
+               end
+       end)
+
+       -- parse first line of code
+       if code ~= nil then
+               local func_info = check_function(code)
+               local module_name = check_module(code)
+               local const_info = check_constant(code)
+               if func_info then
+                       block.class = "function"
+                       block.name = func_info.name
+                       block.param = func_info.param
+                       block.private = func_info.private
+               elseif const_info then
+                       block.class = "constant"
+                       block.name = const_info.name
+                       block.private = const_info.private
+               elseif module_name then
+                       block.class = "module"
+                       block.name = module_name
+                       block.param = {}
+               else
+                       block.param = {}
+               end
+       else
+               -- TODO: comment without any code. Does this means we are dealing
+               -- with a file comment?
+       end
+
+       -- parse @ tags
+       local currenttag = "description"
+       local currenttext
+
+       table.foreachi(block.comment, function (_, line)
+               line = util.trim_comment(line)
+
+               local r, _, tag, text = string.find(line, "@([_%w%.]+)%s+(.*)")
+               if r ~= nil then
+                       -- found new tag, add previous one, and start a new one
+                       -- TODO: what to do with invalid tags? issue an error? or log a warning?
+                       tags.handle(currenttag, block, currenttext)
+
+                       currenttag = tag
+                       currenttext = text
+               else
+                       currenttext = util.concat(currenttext, "\n" .. line)
+                       assert(string.sub(currenttext, 1, 1) ~= " ", string.format("`%s', `%s'", currenttext, line))
+               end
+       end)
+       tags.handle(currenttag, block, currenttext)
+
+       -- extracts summary information from the description
+       block.summary = parse_summary(block.description)
+       assert(string.sub(block.description, 1, 1) ~= " ", string.format("`%s'", block.description))
+
+       if block.name and block.class == "module" then
+               modulename = block.name
+       end
+
+       return block, modulename
+end
+
+-------------------------------------------------------------------------------
+-- Parses a block of comment, started with ---. Read until the next block of
+-- comment.
+-- @param f file handle
+-- @param line being parsed
+-- @param modulename module already found, if any
+-- @return line
+-- @return block parsed
+-- @return modulename if found
+
+local function parse_block (f, line, modulename, first)
+       local multiline = not not (line and line:match("%[%["))
+       local block = {
+               comment = {},
+               code = {},
+       }
+
+       while line ~= nil do
+               if (multiline == true and string.find(line, "%]%]") ~= nil) or
+                  (multiline == false and string.find(line, "^[\t ]*%-%-") == nil) then
+                       -- reached end of comment, read the code below it
+                       -- TODO: allow empty lines
+                       line, block.code, modulename = parse_code(f, line, modulename)
+
+                       -- parse information in block comment
+                       block, modulename = parse_comment(block, first, modulename)
+
+                       return line, block, modulename
+               else
+                       table.insert(block.comment, line)
+                       line = f:read()
+               end
+       end
+       -- reached end of file
+
+       -- parse information in block comment
+       block, modulename = parse_comment(block, first, modulename)
+
+       return line, block, modulename
+end
+
+-------------------------------------------------------------------------------
+-- Parses a file documented following luadoc format.
+-- @param filepath full path of file to parse
+-- @param doc table with documentation
+-- @return table with documentation
+
+function parse_file (filepath, doc, handle, prev_line, prev_block, prev_modname)
+       local blocks = { prev_block }
+       local modulename = prev_modname
+
+       -- read each line
+       local f = handle or io.open(filepath, "r")
+       local i = 1
+       local line = prev_line or f:read()
+       local first = true
+       while line ~= nil do
+
+               if string.find(line, "^[\t ]*%-%-%-") then
+                       -- reached a luadoc block
+                       local block, newmodname
+                       line, block, newmodname = parse_block(f, line, modulename, first)
+
+                       if modulename and newmodname and newmodname ~= modulename then
+                               doc = parse_file( nil, doc, f, line, block, newmodname )
+                       else
+                               table.insert(blocks, block)
+                               modulename = newmodname
+                       end
+               else
+                       -- look for a module definition
+                       local newmodname = check_module(line, modulename)
+
+                       if modulename and newmodname and newmodname ~= modulename then
+                               parse_file( nil, doc, f )
+                       else
+                               modulename = newmodname
+                       end
+
+                       -- TODO: keep beginning of file somewhere
+
+                       line = f:read()
+               end
+               first = false
+               i = i + 1
+       end
+
+       if not handle then
+               f:close()
+       end
+
+       if filepath then
+               -- store blocks in file hierarchy
+               assert(doc.files[filepath] == nil, string.format("doc for file `%s' already defined", filepath))
+               table.insert(doc.files, filepath)
+               doc.files[filepath] = {
+                       type = "file",
+                       name = filepath,
+                       doc = blocks,
+       --              functions = class_iterator(blocks, "function"),
+       --              tables = class_iterator(blocks, "table"),
+               }
+       --
+               local first = doc.files[filepath].doc[1]
+               if first and modulename then
+                       doc.files[filepath].author = first.author
+                       doc.files[filepath].copyright = first.copyright
+                       doc.files[filepath].description = first.description
+                       doc.files[filepath].release = first.release
+                       doc.files[filepath].summary = first.summary
+               end
+       end
+
+       -- if module definition is found, store in module hierarchy
+       if modulename ~= nil then
+               if modulename == "..." then
+                       assert( filepath, "Can't determine name for virtual module from filepatch" )
+                       modulename = string.gsub (filepath, "%.lua$", "")
+                       modulename = string.gsub (modulename, "/", ".")
+               end
+               if doc.modules[modulename] ~= nil then
+                       -- module is already defined, just add the blocks
+                       table.foreachi(blocks, function (_, v)
+                               table.insert(doc.modules[modulename].doc, v)
+                       end)
+               else
+                       -- TODO: put this in a different module
+                       table.insert(doc.modules, modulename)
+                       doc.modules[modulename] = {
+                               type = "module",
+                               name = modulename,
+                               doc = blocks,
+--                             functions = class_iterator(blocks, "function"),
+--                             tables = class_iterator(blocks, "table"),
+                               author = first and first.author,
+                               copyright = first and first.copyright,
+                               description = "",
+                               release = first and first.release,
+                               summary = "",
+                       }
+
+                       -- find module description
+                       for m in class_iterator(blocks, "module")() do
+                               doc.modules[modulename].description = util.concat(
+                                       doc.modules[modulename].description,
+                                       m.description)
+                               doc.modules[modulename].summary = util.concat(
+                                       doc.modules[modulename].summary,
+                                       m.summary)
+                               if m.author then
+                                       doc.modules[modulename].author = m.author
+                               end
+                               if m.copyright then
+                                       doc.modules[modulename].copyright = m.copyright
+                               end
+                               if m.release then
+                                       doc.modules[modulename].release = m.release
+                               end
+                               if m.name then
+                                       doc.modules[modulename].name = m.name
+                               end
+                       end
+                       doc.modules[modulename].description = doc.modules[modulename].description or (first and first.description) or ""
+                       doc.modules[modulename].summary = doc.modules[modulename].summary or (first and first.summary) or ""
+               end
+
+               -- make functions table
+               doc.modules[modulename].functions = {}
+               for f in class_iterator(blocks, "function")() do
+                       if f and f.name then
+                               table.insert(doc.modules[modulename].functions, f.name)
+                               doc.modules[modulename].functions[f.name] = f
+                       end
+               end
+
+               -- make tables table
+               doc.modules[modulename].tables = {}
+               for t in class_iterator(blocks, "table")() do
+                       if t and t.name then
+                               table.insert(doc.modules[modulename].tables, t.name)
+                               doc.modules[modulename].tables[t.name] = t
+                       end
+               end
+
+               -- make constants table
+               doc.modules[modulename].constants = {}
+               for c in class_iterator(blocks, "constant")() do
+                       if c and c.name then
+                               table.insert(doc.modules[modulename].constants, c.name)
+                               doc.modules[modulename].constants[c.name] = c
+                       end
+               end
+       end
+
+       if filepath then
+               -- make functions table
+               doc.files[filepath].functions = {}
+               for f in class_iterator(blocks, "function")() do
+                       if f and f.name then
+                               table.insert(doc.files[filepath].functions, f.name)
+                               doc.files[filepath].functions[f.name] = f
+                       end
+               end
+
+               -- make tables table
+               doc.files[filepath].tables = {}
+               for t in class_iterator(blocks, "table")() do
+                       if t and t.name then
+                               table.insert(doc.files[filepath].tables, t.name)
+                               doc.files[filepath].tables[t.name] = t
+                       end
+               end
+       end
+
+       return doc
+end
+
+-------------------------------------------------------------------------------
+-- Checks if the file is terminated by ".lua" or ".luadoc" and calls the
+-- function that does the actual parsing
+-- @param filepath full path of the file to parse
+-- @param doc table with documentation
+-- @return table with documentation
+-- @see parse_file
+
+function file (filepath, doc)
+       local patterns = { "%.lua$", "%.luadoc$" }
+       local valid = table.foreachi(patterns, function (_, pattern)
+               if string.find(filepath, pattern) ~= nil then
+                       return true
+               end
+       end)
+
+       if valid then
+               logger:info(string.format("processing file `%s'", filepath))
+               doc = parse_file(filepath, doc)
+       end
+
+       return doc
+end
+
+-------------------------------------------------------------------------------
+-- Recursively iterates through a directory, parsing each file
+-- @param path directory to search
+-- @param doc table with documentation
+-- @return table with documentation
+
+function directory (path, doc)
+       for f in posix.dir(path) do
+               local fullpath = path .. "/" .. f
+               local attr = posix.stat(fullpath)
+               assert(attr, string.format("error stating file `%s'", fullpath))
+
+               if attr.type == "reg" then
+                       doc = file(fullpath, doc)
+               elseif attr.type == "dir" and f ~= "." and f ~= ".." then
+                       doc = directory(fullpath, doc)
+               end
+       end
+       return doc
+end
+
+-- Recursively sorts the documentation table
+local function recsort (tab)
+       table.sort (tab)
+       -- sort list of functions by name alphabetically
+       for f, doc in pairs(tab) do
+               if doc.functions then
+                       table.sort(doc.functions)
+               end
+               if doc.tables then
+                       table.sort(doc.tables)
+               end
+       end
+end
+
+-------------------------------------------------------------------------------
+
+function start (files, doc)
+       assert(files, "file list not specified")
+
+       -- Create an empty document, or use the given one
+       doc = doc or {
+               files = {},
+               modules = {},
+       }
+       assert(doc.files, "undefined `files' field")
+       assert(doc.modules, "undefined `modules' field")
+
+       table.foreachi(files, function (_, path)
+               local attr = posix.stat(path)
+               assert(attr, string.format("error stating path `%s'", path))
+
+               if attr.type == "reg" then
+                       doc = file(path, doc)
+               elseif attr.type == "dir" then
+                       doc = directory(path, doc)
+               end
+       end)
+
+       -- order arrays alphabetically
+       recsort(doc.files)
+       recsort(doc.modules)
+
+       return doc
+end
diff --git a/build/luadoc/luadoc/taglet/standard/tags.lua b/build/luadoc/luadoc/taglet/standard/tags.lua
new file mode 100644 (file)
index 0000000..e9d0354
--- /dev/null
@@ -0,0 +1,191 @@
+-------------------------------------------------------------------------------
+-- Handlers for several tags
+-- @release $Id: tags.lua,v 1.8 2007/09/05 12:39:09 tomas Exp $
+-------------------------------------------------------------------------------
+
+local luadoc = require "luadoc"
+local util = require "luadoc.util"
+local string = require "string"
+local table = require "table"
+local assert, type, tostring, tonumber = assert, type, tostring, tonumber
+
+module "luadoc.taglet.standard.tags"
+
+-------------------------------------------------------------------------------
+
+local function author (tag, block, text)
+       block[tag] = block[tag] or {}
+       if not text then
+               luadoc.logger:warn("author `name' not defined [["..text.."]]: skipping")
+               return
+       end
+       table.insert (block[tag], text)
+end
+
+-------------------------------------------------------------------------------
+-- Set the class of a comment block. Classes can be "module", "function",
+-- "table". The first two classes are automatic, extracted from the source code
+
+local function class (tag, block, text)
+       block[tag] = text
+end
+
+-------------------------------------------------------------------------------
+
+local function cstyle (tag, block, text)
+       block[tag] = text
+end
+
+-------------------------------------------------------------------------------
+
+local function sort (tag, block, text)
+       block[tag] = tonumber(text) or 0
+end
+
+-------------------------------------------------------------------------------
+
+local function copyright (tag, block, text)
+       block[tag] = text
+end
+
+-------------------------------------------------------------------------------
+
+local function description (tag, block, text)
+       block[tag] = text
+end
+
+-------------------------------------------------------------------------------
+
+local function field (tag, block, text)
+       if block["class"] ~= "table" then
+               luadoc.logger:warn("documenting `field' for block that is not a `table'")
+       end
+       block[tag] = block[tag] or {}
+
+       local _, _, name, desc = string.find(text, "^([_%w%.]+)%s+(.*)")
+       assert(name, "field name not defined")
+
+       table.insert(block[tag], name)
+       block[tag][name] = desc
+end
+
+-------------------------------------------------------------------------------
+-- Set the name of the comment block. If the block already has a name, issue
+-- an error and do not change the previous value
+
+local function name (tag, block, text)
+       if block[tag] and bloc