Merge pull request #333 from legendtang/master
authorJo-Philipp Wich <jow@openwrt.org>
Tue, 10 Mar 2015 17:55:15 +0000 (18:55 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Tue, 10 Mar 2015 17:55:15 +0000 (18:55 +0100)
themes/bootstrap: add media queries to bootstrap-theme for better responsive UI on mobile devices

22 files changed:
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/global_value.htm [new file with mode: 0644]
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-privoxy/Makefile
applications/luci-app-privoxy/luasrc/controller/privoxy.lua
applications/luci-app-privoxy/luasrc/model/cbi/privoxy.lua [new file with mode: 0755]
applications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua [deleted file]
applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua [deleted file]
applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua
applications/luci-app-upnp/luasrc/controller/upnp.lua
contrib/package/community-profiles/files/etc/config/profile_potsdam
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua
themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css

index 18906cd..f20b49e 100644 (file)
@@ -6,32 +6,33 @@
 
 include $(TOPDIR)/rules.mk
 
-# LuCI specific settings
-LUCI_TITLE:=LuCI Support for Dynamic DNS Client (ddns-scripts)
-LUCI_DEPENDS:=+luci-mod-admin-full +ddns-scripts
-
 PKG_NAME:=luci-app-ddns
 
 # Version == major.minor.patch
 # increase on new functionality (minor) or patches (patch)
-PKG_VERSION:=2.1.1
+PKG_VERSION:=2.2.1
 
 # Release == build
 # increase on changes of translation files
-PKG_RELEASE:=0
+PKG_RELEASE:=1
 
 PKG_LICENSE:=Apache-2.0
 PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
 
+# 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)
-       Maintainer: $(PKG_MAINTAINER)
+       .
+       Version: $(PKG_VERSION)-$(PKG_RELEASE)
+       $(PKG_MAINTAINER)
 endef
 
-include ../../luci.mk
+include $(TOPDIR)/feeds/luci/luci.mk
 
 # call BuildPackage - OpenWrt buildroot signature
index 56d2b66..0b82021 100644 (file)
@@ -15,7 +15,7 @@ local SYS  = require "luci.sys"
 local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
 local UTIL = require "luci.util"
 
-DDNS_MIN = "2.1.0-2"   -- minimum version of service required
+DDNS_MIN = "2.2.0-1"   -- minimum version of service required
 
 function index()
        local nxfs      = require "nixio.fs"            -- global definitions not available
@@ -36,6 +36,7 @@ function index()
        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
@@ -90,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_"
@@ -103,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
@@ -149,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
@@ -164,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"
index 77753c0..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 009ba99..ff7aa7a 100644 (file)
@@ -8,7 +8,7 @@ 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
 -- correct ddns-scripts version
@@ -88,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 83b10e9..9e8df2d 100644 (file)
@@ -27,8 +27,6 @@ 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="javascript:alert(']]
                .. translate("Version Information")
                .. [[\n\nluci-app-ddns]]
@@ -109,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 2fbcff8..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
@@ -100,25 +100,67 @@ end
 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
+       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
-       return (tonumber(SYS.call(
-               [[opkg compare-versions "]] .. ver1 .. [[" "]] .. comp .. [[" "]] .. ver2 .. [["]]
-               )) == 1)
+       -- all equal then true
+       return true
 end
 
 -- read version information for given package if installed
 function ipkg_ver_installed(pkg)
-       if not pkg then
-               return nil
-       end
-       -- opkg list-installed [pkg] | cut -d " " -f 3 - return version as sting
-       local ver = SYS.exec([[opkg list-installed ]] .. pkg .. [[ | cut -d " " -f 3 ]])
-       if (#ver > 0) then
-               return ver
+       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 nil
+       return version
 end
 
 -- replacement of build-in read of UCI option
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 6cca0e7..ea8e4a1 100644 (file)
                                } 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";
                );
        }
 
-       var ddns_ov_XHR = new XHR();
        // force to immediate show status on page load (not waiting for XHR.poll)
-       ddns_ov_XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+       XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(data);
+                       if (data) { _data2elements(data); }
                }
        );
 
        // define only ONE XHR.poll in a page because if one is running it blocks the other one
        // optimum is to define on Map or Section Level from here you can reach all elements
        // we need update every 15 seconds only
-       ddns_ov_XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+       XHR.poll(15, '<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(data);
+                       if (data) { _data2elements(data); }
                }
        );
 
index 7c60726..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 interface
-                       if (data[i].iface == "_nonet_")
+                       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) ) {
                }
        }
 
-       var ddns_status_XHR = new XHR();
        // force to immediate show status (not waiting for XHR.poll)
-       ddns_status_XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
+       XHR.get('<%=luci.dispatcher.build_url("admin", "services", "ddns", "status")%>', null,
                function(x, data) {
-                       _data2elements(x, data);
+                       if (data) { _data2elements(x, data); }
                }
        );
 
-       ddns_status_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 b965a91..f6e0d5e 100644 (file)
@@ -1,8 +1,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: luci-app-ddns\n"
-"POT-Creation-Date: 2015-01-17 18:28+0100\n"
-"PO-Revision-Date: 2015-01-17 18:36+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: \n"
 "Language: de\n"
@@ -20,9 +20,15 @@ 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"
 
@@ -38,12 +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 "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 "
@@ -59,6 +67,9 @@ 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"
 
@@ -71,8 +82,18 @@ msgstr "Konfigurationsfehler"
 msgid "Configuration"
 msgstr "Einstellungen"
 
-msgid "Configure here the details for selected Dynamic DNS service"
-msgstr "Konfiguriere hier die Details für den gewählten Dynamik DNS Dienst"
+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 /"
@@ -113,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 "
@@ -159,6 +183,16 @@ 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"
 
@@ -206,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"
 
@@ -227,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"
 
@@ -263,6 +314,9 @@ 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"
@@ -271,6 +325,13 @@ 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 "
@@ -298,6 +359,11 @@ 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"
 
@@ -307,6 +373,12 @@ 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"
 
@@ -314,6 +386,13 @@ 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 ""
@@ -338,9 +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."
@@ -349,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"
 
@@ -357,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 "
@@ -428,6 +514,9 @@ msgstr "Start"
 msgid "Start / Stop"
 msgstr "Start / Stopp"
 
+msgid "Status directory"
+msgstr "Status-Verzeichnis"
+
 msgid "Stopped"
 msgstr "Angehalten"
 
@@ -444,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"
 
@@ -466,6 +561,9 @@ 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 "
@@ -511,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 "
@@ -548,12 +649,12 @@ msgstr "hier aktivieren"
 msgid "file or directory not found or not 'IGNORE'"
 msgstr "Datei oder Verzeichnis nicht gefunden oder nicht 'IGNORE'"
 
+msgid "help"
+msgstr "Hilfe"
+
 msgid "hours"
 msgstr "Stunden"
 
-msgid "install update here"
-msgstr "Aktualisierung hier installieren"
-
 msgid "installed"
 msgstr "installiert"
 
@@ -615,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 4b983ce..6e4f2fe 100644 (file)
@@ -7,9 +7,15 @@ msgstr ""
 msgid "-- custom --"
 msgstr ""
 
+msgid "-- default --"
+msgstr ""
+
 msgid "Advanced Settings"
 msgstr ""
 
+msgid "Allow non-public IP's"
+msgstr ""
+
 msgid "Applying changes"
 msgstr ""
 
@@ -23,8 +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 "Bind Network"
+msgstr ""
+
+msgid "Binding to a specific network not supported"
 msgstr ""
 
 msgid ""
@@ -37,6 +47,9 @@ msgid ""
 "UDP when requesting DNS server"
 msgstr ""
 
+msgid "Casual users should not change this setting"
+msgstr ""
+
 msgid "Check Interval"
 msgstr ""
 
@@ -49,7 +62,15 @@ msgstr ""
 msgid "Configuration"
 msgstr ""
 
-msgid "Configure here the details for selected Dynamic DNS service"
+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 ""
@@ -84,6 +105,9 @@ msgstr ""
 msgid "DNS-Server"
 msgstr ""
 
+msgid "Date format"
+msgstr ""
+
 msgid "Defines the Web page to read systems IPv4-Address from"
 msgstr ""
 
@@ -115,6 +139,13 @@ 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 ""
 
@@ -158,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 ""
 
@@ -179,6 +216,14 @@ msgstr ""
 msgid "Format: IP or FQDN"
 msgstr ""
 
+msgid ""
+"GNU Wget will use the IP of given network, cURL will use the physical "
+"interface."
+msgstr ""
+
+msgid "Global Settings"
+msgstr ""
+
 msgid "HTTPS not supported"
 msgstr ""
 
@@ -212,12 +257,20 @@ 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 ""
 
@@ -238,6 +291,9 @@ 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 ""
 
@@ -247,6 +303,12 @@ msgstr ""
 msgid "Log File Viewer"
 msgstr ""
 
+msgid "Log directory"
+msgstr ""
+
+msgid "Log length"
+msgstr ""
+
 msgid "Log to file"
 msgstr ""
 
@@ -254,6 +316,11 @@ 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 ""
@@ -276,22 +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"
@@ -360,6 +433,9 @@ msgstr ""
 msgid "Start / Stop"
 msgstr ""
 
+msgid "Status directory"
+msgstr ""
+
 msgid "Stopped"
 msgstr ""
 
@@ -374,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 ""
 
@@ -394,6 +476,9 @@ msgstr ""
 msgid "Use HTTP Secure"
 msgstr ""
 
+msgid "Use cURL"
+msgstr ""
+
 msgid "User defined script to read systems IP-Address"
 msgstr ""
 
@@ -430,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 ""
 
@@ -463,10 +551,10 @@ msgstr ""
 msgid "file or directory not found or not 'IGNORE'"
 msgstr ""
 
-msgid "hours"
+msgid "help"
 msgstr ""
 
-msgid "install update here"
+msgid "hours"
 msgstr ""
 
 msgid "installed"
@@ -529,6 +617,9 @@ msgstr ""
 msgid "please select 'IPv4' address version in"
 msgstr ""
 
+msgid "please set to 'default'"
+msgstr ""
+
 msgid "proxy port missing"
 msgstr ""
 
index 4c1fc57..bc2c57e 100644 (file)
@@ -6,33 +6,33 @@
 
 include $(TOPDIR)/rules.mk
 
-# LuCI specific settings
-LUCI_TITLE:=LuCI Support for Privoxy WEB proxy
-LUCI_DEPENDS:=+luci-mod-admin-full +privoxy
-LUCI_PKGARCH:=all
-
 PKG_NAME:=luci-app-privoxy
 
 # Version == major.minor.patch
 # increase "minor" on new functionality and "patch" on patches/optimization
-PKG_VERSION:=1.0.2
+PKG_VERSION:=1.0.3
 
 # Release == build
 # increase on changes of translation files
-PKG_RELEASE:=0
+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)
-       Maintainer: $(PKG_MAINTAINER)
+       .
+       Version: $(PKG_VERSION)-$(PKG_RELEASE)
+       $(PKG_MAINTAINER)
 endef
 
-include ../../luci.mk
+include $(TOPDIR)/feeds/luci/luci.mk
 
 # call BuildPackage - OpenWrt buildroot signature
index de73d0c..9ffc404 100755 (executable)
@@ -7,26 +7,16 @@ 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()
-       local _sys      = require "luci.sys"
-       local _verinst  = _sys.exec([[opkg list-installed ]] .. "privoxy" .. [[ | cut -d " " -f 3 ]])
-       local _cmd      = [[opkg compare-versions "]] .. _verinst .. [[" ">=" "]] .. "3.0.22-0" .. [["]]
-       local _verok    = tonumber(_sys.call(_cmd))
-
-       -- check config file and version
-       if not nixio.fs.access("/etc/config/privoxy") or (_verok == 0) then
-               entry( {"admin", "services", "privoxy"}, cbi("privoxy/apperror",
-                       {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true }), _("Privoxy WEB proxy"), 59)
-       else
-               entry( {"admin", "services", "privoxy"}, cbi("privoxy/detail"), _("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
+       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
@@ -80,18 +70,71 @@ function get_pid(from_lua)
        end
 end
 
--- get the "name" of the current active theme
-function get_theme()
-       local _uci  = UCI.cursor()
-       local _base = _uci:get("luci", "main", "mediaurlbase")  -- only pathname
-       _uci:unload("luci")
+-- 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
 
-       for k, v in pairs(luci.config.themes) do
-               if k:sub(1, 1) ~= "." and v == _base then
-                       return k
+               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
-       return nil
+       -- 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
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/model/cbi/privoxy/apperror.lua b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/apperror.lua
deleted file mode 100755 (executable)
index fcbb880..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
--- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
--- Licensed under the Apache License, Version 2.0
-
-local CTRL = require "luci.controller.privoxy" -- this application's controller
-local DISP = require "luci.dispatcher"
-local SYS  = require "luci.sys"
-
-local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
-
--- cbi-map -- ##################################################################
-local m        = Map("privoxy")
-m.title        = [[</a><a href="javascript:alert(']]
-               .. translate("Version Information")
-               .. [[\n\nluci-app-privoxy]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]]
-               .. SYS.exec([[opkg list-installed ]] .. [[luci-app-privoxy]] .. [[ | cut -d " " -f 3 ]])
-               .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
-               .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]]
-               .. SYS.exec([[opkg list-installed ]] .. [[privoxy]] .. [[ | cut -d " " -f 3 ]])
-               .. [[\n\n]]
-       .. [[')">]]
-       .. translate("Privoxy WEB proxy")
-m.description = 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.")
-
--- cbi-section -- ##############################################################
-local s = m:section(SimpleSection)
-s.title = [[<font color="red">]] .. [[<strong>]]
-       .. translate("Software update required")
-       .. [[</strong>]] .. [[</font>]]
-
--- old privoxy sofware version --------------------------------------------------------------
-local v    = s:option(DummyValue, "_update_needed")
-v.titleref = DISP.build_url("admin", "system", "packages")
-v.rawhtml  = true
---v.title    = [[<h3>]] .. [[<font color="red">]] .. [[<strong>]]
---        .. translate("Software update required")
---        .. [[</strong>]] .. [[</font>]] .. [[</h3>]] .. [[<br />]]
-v.value    = [[<h3>]] .. [[<strong>]]
-          .. translate("The currently installed 'privoxy' package is not supported by LuCI application.")
-          .. [[<br />]]
-          .. translate("Please update to the current version!")
-          .. [[</strong>]] .. [[</h3>]]
-return m
diff --git a/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua b/applications/luci-app-privoxy/luasrc/model/cbi/privoxy/detail.lua
deleted file mode 100755 (executable)
index 2c846a1..0000000
+++ /dev/null
@@ -1,928 +0,0 @@
--- Copyright 2014 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 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 LFLF = (CTRL.get_theme() == "Bootstrap") and [[<br /><br /><br />]] or [[]]
-local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
-
--- cbi-map -- ##################################################################
-local m        = Map("privoxy")
-m.title        = [[</a><a href="javascript:alert(']]
-               .. translate("Version Information")
-               .. [[\n\nluci-app-privoxy]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]]
-               .. SYS.exec([[opkg list-installed ]] .. [[luci-app-privoxy]] .. [[ | cut -d " " -f 3 ]])
-               .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
-               .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
-               .. [[\n\t]] .. translate("Version") .. [[:\t]]
-               .. SYS.exec([[opkg list-installed ]] .. [[privoxy]] .. [[ | cut -d " " -f 3 ]])
-               .. [[\n\n]]
-       .. [[')">]]
-       .. translate("Privoxy WEB proxy")
-m.description = 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>]]
-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.")
-               .. LFLF )
-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.")
-               .. LFLF )
-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.")
-               .. LFLF )
-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.")
-               .. LFLF )
-
-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", DynamicList, "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 td       = ns:taboption("filter", Value, "templdir")
-td.title_base  = "Template Directory"
-td.title       = string.format(HELP, "TEMPLDIR", td.title_base )
-td.description = translate("An alternative directory where the templates are loaded from.")
-               .. [[<br />]]
-               .. translate("No trailing '/', please.")
-td.placeholder = "/etc/privoxy/templates"
-td.rmempty     = true
-function td.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
-
--- 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 = "sites.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 -----------------------------------------------------------------------
-local d1       = ns:taboption("debug", Flag, "debug_1")
-d1.title       = string.format(HELP, "DEBUG", "Debug 1" )
-d1.description = translate("Log the destination for each request Privoxy let through. See also 'Debug 1024'.")
-d1.rmempty     = true
-function d1.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d2       = ns:taboption("debug", Flag, "debug_2")
-d2.title       = string.format(HELP, "DEBUG", "Debug 2" )
-d2.description = translate("Show each connection status")
-d2.rmempty     = true
-function d2.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d3       = ns:taboption("debug", Flag, "debug_4")
-d3.title       = string.format(HELP, "DEBUG", "Debug 4" )
-d3.description = translate("Show I/O status")
-d3.rmempty     = true
-function d3.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d4       = ns:taboption("debug", Flag, "debug_8")
-d4.title       = string.format(HELP, "DEBUG", "Debug 8" )
-d4.description = translate("Show header parsing")
-d4.rmempty     = true
-function d4.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d5       = ns:taboption("debug", Flag, "debug_16")
-d5.title       = string.format(HELP, "DEBUG", "Debug 16" )
-d5.description = translate("Log all data written to the network")
-d5.rmempty     = true
-function d5.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d6       = ns:taboption("debug", Flag, "debug_32")
-d6.title       = string.format(HELP, "DEBUG", "Debug 32" )
-d6.description = translate("Debug force feature")
-d6.rmempty     = true
-function d6.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d7       = ns:taboption("debug", Flag, "debug_64")
-d7.title       = string.format(HELP, "DEBUG", "Debug 64" )
-d7.description = translate("Debug regular expression filters")
-d7.rmempty     = true
-function d7.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d8       = ns:taboption("debug", Flag, "debug_128")
-d8.title       = string.format(HELP, "DEBUG", "Debug 128" )
-d8.description = translate("Debug redirects")
-d8.rmempty     = true
-function d8.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d9       = ns:taboption("debug", Flag, "debug_256")
-d9.title       = string.format(HELP, "DEBUG", "Debug 256" )
-d9.description = translate("Debug GIF de-animation")
-d9.rmempty     = true
-function d9.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d10      = ns:taboption("debug", Flag, "debug_512")
-d10.title      = string.format(HELP, "DEBUG", "Debug 512" )
-d10.description        = translate("Common Log Format")
-d10.rmempty    = true
-function d10.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d11      = ns:taboption("debug", Flag, "debug_1024")
-d11.title      = string.format(HELP, "DEBUG", "Debug 1024" )
-d11.description        = translate("Log the destination for requests Privoxy didn't let through, and the reason why.")
-d11.rmempty    = true
-function d11.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d12      = ns:taboption("debug", Flag, "debug_2048")
-d12.title      = string.format(HELP, "DEBUG", "Debug 2048" )
-d12.description        = translate("CGI user interface")
-d12.rmempty    = true
-function d12.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d13      = ns:taboption("debug", Flag, "debug_4096")
-d13.title      = string.format(HELP, "DEBUG", "Debug 4096" )
-d13.description        = translate("Startup banner and warnings.")
-d13.rmempty    = true
-function d13.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-local d14      = ns:taboption("debug", Flag, "debug_8192")
-d14.title      = string.format(HELP, "DEBUG", "Debug 8192" )
-d14.description        = translate("Non-fatal errors - *we highly recommended enabling this*")
-d14.rmempty    = true
-function d14.parse(self, section)
-       CTRL.flag_parse(self, section)
-end
-
--- debug -----------------------------------------------------------------------
-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 -----------------------------------------------------------------------
-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
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
index bde824f..c15624a 100644 (file)
@@ -13,3 +13,7 @@ config 'defaults' 'wifi_device'
 
 config 'defaults' 'bssidscheme'
        option '5' '02:CA:FF:EE:BA:BE'
+
+config 'defaults' 'interface'
+        option 'dns' '85.214.20.141 213.73.91.35 194.150.168.168'
+
index c2e5c72..e092be6 100644 (file)
@@ -135,7 +135,7 @@ end
 
 -- dhcp setup was requested, create section and reload page
 if m:formvalue("cbid.dhcp._enable._enable") then
-       m.uci:section("dhcp", "dhcp", nil, {
+       m.uci:section("dhcp", "dhcp", arg[1], {
                interface = arg[1],
                start     = "100",
                limit     = "150",
index 9b5ee3a..b19a6a0 100644 (file)
@@ -421,6 +421,10 @@ fieldset legend {
        /* IE6-7 */
 
 }
+form .cbi-tab-descr {
+       line-height: 18px;
+       margin-bottom: 18px;
+}
 
 form .clearfix,
 form .cbi-value {
@@ -1929,9 +1933,9 @@ td.cbi-value-field var {
        float: left;
 }
 
-.uci-change-legend-label>ins,
-.uci-change-legend-label>del,
-.uci-change-legend-label>var {
+.uci-change-legend-label > ins,
+.uci-change-legend-label > del,
+.uci-change-legend-label > var {
        float: left;
        margin-right: 4px;
        width: 10px;