1 -- Copyright 2014-2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
2 -- Licensed under the Apache License, Version 2.0
4 local NXFS = require "nixio.fs"
5 local SYS = require "luci.sys"
6 local UTIL = require "luci.util"
7 local DISP = require "luci.dispatcher"
8 local DTYP = require "luci.cbi.datatypes"
9 local CTRL = require "luci.controller.privoxy" -- this application's controller
11 -- Bootstrap theme needs 2 or 3 additional linefeeds for tab description for better optic
12 local HELP = [[<a href="http://www.privoxy.org/user-manual/config.html#%s" target="_blank">%s</a>]]
14 local VERINST = CTRL.ipkg_ver_installed("privoxy")
15 local VEROK = CTRL.ipkg_ver_compare(VERINST,">=",CTRL.PRIVOXY_MIN)
17 local TITLE = [[<a href="javascript:alert(']]
18 .. translate("Version Information")
19 .. [[\n\nluci-app-privoxy]]
20 .. [[\n\t]] .. translate("Version") .. [[:\t]]
21 .. CTRL.ipkg_ver_installed("luci-app-privoxy")
22 .. [[\n\nprivoxy ]] .. translate("required") .. [[:]]
23 .. [[\n\t]] .. translate("Version") .. [[:\t]] .. CTRL.PRIVOXY_MIN .. [[ ]] .. translate("or higher")
24 .. [[\n\nprivoxy ]] .. translate("installed") .. [[:]]
25 .. [[\n\t]] .. translate("Version") .. [[:\t]] .. VERINST
28 .. translate("Privoxy WEB proxy")
31 local DESC = translate("Privoxy is a non-caching web proxy with advanced filtering "
32 .. "capabilities for enhancing privacy, modifying web page data and HTTP headers, "
33 .. "controlling access, and removing ads and other obnoxious Internet junk.")
35 .. translate("For help use link at the relevant option")
38 -- Error handling if wrong privoxy version installed -- ########################
39 if not nixio.fs.access("/etc/config/privoxy") or not VEROK then
40 local f = SimpleForm("_no_config")
47 local s = f:section(SimpleSection)
48 s.title = [[<font color="red">]] .. [[<strong>]]
49 .. translate("Software update required")
50 .. [[</strong>]] .. [[</font>]]
52 local v = s:option(DummyValue, "_update_needed")
53 v.titleref = DISP.build_url("admin", "system", "packages")
55 v.value = [[<h3><strong><br /><br /> ]]
56 .. translate("The currently installed 'privoxy' package is not supported by LuCI application.")
57 .. [[<br /><br /> ]]
58 .. translate("required") .. ": " .. CTRL.PRIVOXY_MIN .. " *** ".. translate("installed") .. ": " .. VERINST
59 .. [[<br /><br /> ]]
60 .. translate("Please update to the current version!")
61 .. [[<br /><br /></strong></h3>]]
65 -- cbi-map -- ##################################################################
66 local m = Map("privoxy")
69 function m.commit_handler(self)
70 if self.changed then -- changes ?
71 os.execute("/etc/init.d/privoxy reload &") -- reload configuration
75 -- cbi-section -- ##############################################################
76 local ns = m:section( NamedSection, "privoxy", "privoxy")
79 translate("Local Set-up"),
80 translate("If you intend to operate Privoxy for more users than just yourself, "
81 .. "it might be a good idea to let them know how to reach you, what you block "
82 .. "and why you do that, your policies, etc.") )
83 local function err_tab_local(title, msg)
84 return string.format(translate("Local Set-up") .. " - %s: %s", title, msg )
88 translate("Files and Directories"),
89 translate("Privoxy can (and normally does) use a number of other files "
90 .. "for additional configuration, help and logging. This section of "
91 .. "the configuration file tells Privoxy where to find those other files.") )
92 local function err_tab_filter(title, msg)
93 return string.format(translate("Files and Directories") .. " - %s: %s", title, msg )
97 translate("Access Control"),
98 translate("This tab controls the security-relevant aspects of Privoxy's configuration.") )
99 local function err_tab_access(title, msg)
100 return string.format(translate("Access Control") .. " - %s: %s", title, msg )
104 translate("Forwarding"),
105 translate("Configure here the routing of HTTP requests through a chain of multiple proxies. "
106 .. "Note that parent proxies can severely decrease your privacy level. "
107 .. "Also specified here are SOCKS proxies.") )
110 translate("Miscellaneous"),
112 local function err_tab_misc(self, msg)
113 return string.format(translate("Miscellaneous") .. " - %s: %s", self.title_base, msg )
117 translate("Logging"),
121 translate("Log File Viewer"),
124 -- tab: local -- ###############################################################
126 -- start/stop button -----------------------------------------------------------
127 local btn = ns:taboption("local", Button, "_startstop")
128 btn.title = translate("Start / Stop")
129 btn.description = translate("Start/Stop Privoxy WEB Proxy")
130 btn.template = "privoxy/detail_startstop"
131 function btn.cfgvalue(self, section)
132 local pid = CTRL.get_pid(true)
134 btn.inputtitle = "PID: " .. pid
135 btn.inputstyle = "reset"
138 btn.inputtitle = translate("Start")
139 btn.inputstyle = "apply"
145 -- enabled ---------------------------------------------------------------------
146 local ena = ns:taboption("local", Flag, "_enabled")
147 ena.title = translate("Enabled")
148 ena.description = translate("Enable/Disable autostart of Privoxy on system startup and interface events")
149 ena.orientation = "horizontal" -- put description under the checkbox
151 function ena.cfgvalue(self, section)
152 return (SYS.init.enabled("privoxy")) and "1" or "0"
154 function ena.validate(self, value)
155 error("Validate " .. value)
157 function ena.write(self, section, value)
158 --error("Write " .. value)
160 return SYS.init.enable("privoxy")
162 return SYS.init.disable("privoxy")
166 -- hostname --------------------------------------------------------------------
167 local hn = ns:taboption("local", Value, "hostname")
168 hn.title = string.format(HELP, "HOSTNAME", "Hostname" )
169 hn.description = translate("The hostname shown on the CGI pages.")
170 hn.placeholder = SYS.hostname()
174 -- user-manual -----------------------------------------------------------------
175 local um = ns:taboption("local", Value, "user_manual")
176 um.title = string.format(HELP, "USER-MANUAL", "User Manual" )
177 um.description = translate("Location of the Privoxy User Manual.")
178 um.placeholder = "http://www.privoxy.org/user-manual/"
182 -- admin-address ---------------------------------------------------------------
183 local aa = ns:taboption("local", Value, "admin_address")
184 aa.title_base = "Admin Email"
185 aa.title = string.format(HELP, "ADMIN-ADDRESS", aa.title_base )
186 aa.description = translate("An email address to reach the Privoxy administrator.")
187 aa.placeholder = "privoxy.admin@example.com"
190 function aa.validate(self, value)
191 if not value or #value == 0 then
194 if not (value:match("[A-Za-z0-9%.%%%+%-]+@[A-Za-z0-9%.%%%+%-]+%.%w%w%w?%w?")) then
195 return nil, err_tab_local(self.title_base, translate("Invalid email address") )
200 -- proxy-info-url --------------------------------------------------------------
201 local piu = ns:taboption("local", Value, "proxy_info_url")
202 piu.title = string.format(HELP, "PROXY-INFO-URL", "Proxy Info URL" )
203 piu.description = translate("A URL to documentation about the local Privoxy setup, configuration or policies.")
207 -- trust-info-url --------------------------------------------------------------
208 local tiu = ns:taboption("local", Value, "trust_info_url")
209 tiu.title = string.format(HELP, "TRUST-INFO-URL", "Trust Info URLs" )
210 tiu.description = translate("A URL to be displayed in the error page that users will see if access to an untrusted page is denied.")
211 .. [[<br /><strong>]]
212 .. translate("The value of this option only matters if the experimental trust mechanism has been activated.")
217 -- tab: filter -- ##############################################################
219 -- logdir ----------------------------------------------------------------------
220 local ld = ns:taboption("filter", Value, "logdir")
221 ld.title_base = "Log Directory"
222 ld.title = string.format(HELP, "LOGDIR", ld.title_base )
223 ld.description = translate("The directory where all logging takes place (i.e. where the logfile is located).")
225 .. translate("No trailing '/', please.")
226 ld.default = "/var/log"
228 function ld.validate(self, value)
229 if not value or #value == 0 then
230 return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
231 elseif not NXFS.access(value) then
232 return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
238 -- logfile ---------------------------------------------------------------------
239 local lf = ns:taboption("filter", Value, "logfile")
240 lf.title_base = "Log File"
241 lf.title = string.format(HELP, "LOGFILE", lf.title_base )
242 lf.description = translate("The log file to use. File name, relative to log directory.")
243 lf.default = "privoxy.log"
245 function lf.validate(self, value)
246 if not value or #value == 0 then
247 return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No File given!") )
253 -- confdir ---------------------------------------------------------------------
254 local cd = ns:taboption("filter", Value, "confdir")
255 cd.title_base = "Configuration Directory"
256 cd.title = string.format(HELP, "CONFDIR", cd.title_base )
257 cd.description = translate("The directory where the other configuration files are located.")
259 .. translate("No trailing '/', please.")
260 cd.default = "/etc/privoxy"
262 function cd.validate(self, value)
263 if not value or #value == 0 then
264 return nil, err_tab_filter(self.title_base, translate("Mandatory Input: No Directory given!") )
265 elseif not NXFS.access(value) then
266 return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
272 -- templdir --------------------------------------------------------------------
273 local tld = ns:taboption("filter", Value, "templdir")
274 tld.title_base = "Template Directory"
275 tld.title = string.format(HELP, "TEMPLDIR", tld.title_base )
276 tld.description = translate("An alternative directory where the templates are loaded from.")
278 .. translate("No trailing '/', please.")
279 tld.placeholder = "/etc/privoxy/templates"
281 function tld.validate(self, value)
282 if not NXFS.access(value) then
283 return nil, err_tab_filter(self.title_base, translate("Directory does not exist!") )
289 -- temporary-directory ---------------------------------------------------------
290 local td = ns:taboption("filter", Value, "temporary_directory")
291 td.title_base = "Temporary Directory"
292 td.title = string.format(HELP, "TEMPORARY-DIRECTORY", td.title_base )
293 td.description = translate("A directory where Privoxy can create temporary files.")
294 .. [[<br /><strong>]]
295 .. translate("Only when using 'external filters', Privoxy has to create temporary files.")
299 -- actionsfile -----------------------------------------------------------------
300 local af = ns:taboption("filter", DynamicList, "actionsfile")
301 af.title_base = "Action Files"
302 af.title = string.format(HELP, "ACTIONSFILE", af.title_base)
303 af.description = translate("The actions file(s) to use. Multiple actionsfile lines are permitted, and are in fact recommended!")
304 .. [[<br /><strong>match-all.action := </strong>]]
305 .. translate("Actions that are applied to all sites and maybe overruled later on.")
306 .. [[<br /><strong>default.action := </strong>]]
307 .. translate("Main actions file")
308 .. [[<br /><strong>user.action := </strong>]]
309 .. translate("User customizations")
311 function af.validate(self, value)
312 if not value or #value == 0 then
313 return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
315 local confdir = cd:formvalue(ns.section)
318 if type(value) == "table" then
320 for _, x in ipairs(value) do
322 if not NXFS.access(confdir .."/".. x) then
325 break -- break/leave for on error
330 if not NXFS.access(confdir .."/".. value) then
336 return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file)
341 -- filterfile ------------------------------------------------------------------
342 local ff = ns:taboption("filter", DynamicList, "filterfile")
343 ff.title_base = "Filter files"
344 ff.title = string.format(HELP, "FILTERFILE", ff.title_base )
345 ff.description = translate("The filter files contain content modification rules that use regular expressions.")
347 function ff.validate(self, value)
348 if not value or #value == 0 then
349 return nil, err_tab_access(self.title_base, translate("Mandatory Input: No files given!") )
351 local confdir = cd:formvalue(ns.section)
354 if type(value) == "table" then
356 for _, x in ipairs(value) do
358 if not NXFS.access(confdir .."/".. x) then
361 break -- break/leave for on error
366 if not NXFS.access(confdir .."/".. value) then
372 return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
377 -- trustfile -------------------------------------------------------------------
378 local tf = ns:taboption("filter", Value, "trustfile")
379 tf.title_base = "Trust file"
380 tf.title = string.format(HELP, "TRUSTFILE", tf.title_base )
381 tf.description = translate("The trust mechanism is an experimental feature for building white-lists "
382 .."and should be used with care.")
383 .. [[<br /><strong>]]
384 .. translate("It is NOT recommended for the casual user.")
386 tf.placeholder = "user.trust"
388 function tf.validate(self, value)
389 local confdir = cd:formvalue(ns.section)
392 if type(value) == "table" then
394 for _, x in ipairs(value) do
396 if not NCFS.access(confdir .."/".. x) then
399 break -- break/leave for on error
404 if not NXFS.access(confdir .."/".. value) then
410 return nil, string.format(err_tab_filter(self.title_base, translate("File '%s' not found inside Configuration Directory") ), file )
415 -- tab: access -- ##############################################################
417 -- listen-address --------------------------------------------------------------
418 local la = ns:taboption("access", DynamicList, "listen_address")
419 la.title_base = "Listen addresses"
420 la.title = string.format(HELP, "LISTEN-ADDRESS", la.title_base )
421 la.description = translate("The address and TCP port on which Privoxy will listen for client requests.")
423 .. translate("Syntax: ")
424 .. "IPv4:Port / [IPv6]:Port / Host:Port"
425 la.default = "127.0.0.1:8118"
427 function la.validate(self, value)
428 if not value or #value == 0 then
429 return nil, err_tab_access(self.title_base, translate("Mandatory Input: No Data given!") )
432 local function check_value(v)
433 local _ret = UTIL.split(v, "]:")
435 if _ret[2] then -- ip6 with port
436 _ip = string.gsub(_ret[1], "%[", "") -- remove "[" at beginning
437 if not DTYP.ip6addr(_ip) then
438 return translate("Mandatory Input: No valid IPv6 address given!")
439 elseif not DTYP.port(_ret[2]) then
440 return translate("Mandatory Input: No valid Port given!")
445 _ret = UTIL.split(v, ":")
447 return translate("Mandatory Input: No Port given!")
449 if #_ret[1] > 0 and not DTYP.host(_ret[1]) then -- :8118 is valid address
450 return translate("Mandatory Input: No valid IPv4 address or host given!")
451 elseif not DTYP.port(_ret[2]) then
452 return translate("Mandatory Input: No valid Port given!")
460 if type(value) == "table" then
462 for _, x in ipairs(value) do
472 err = check_value(value)
476 return nil, string.format(err_tab_access(self.title_base, err .. " - %s"), entry )
481 -- permit-access ---------------------------------------------------------------
482 local pa = ns:taboption("access", DynamicList, "permit_access")
483 pa.title = string.format(HELP, "ACLS", "Permit access" )
484 pa.description = translate("Who can access what.")
485 .. [[<br /><strong>]]
486 .. translate("Please read Privoxy manual for details!")
490 -- deny-access -----------------------------------------------------------------
491 local da = ns:taboption("access", DynamicList, "deny_access")
492 da.title = string.format(HELP, "ACLS", "Deny Access" )
493 da.description = translate("Who can access what.")
494 .. [[<br /><strong>]]
495 .. translate("Please read Privoxy manual for details!")
499 -- buffer-limit ----------------------------------------------------------------
500 local bl = ns:taboption("access", Value, "buffer_limit")
501 bl.title_base = "Buffer Limit"
502 bl.title = string.format(HELP, "BUFFER-LIMIT", bl.title_base )
503 bl.description = translate("Maximum size (in KB) of the buffer for content filtering.")
505 .. translate("Value range 1 to 4096, no entry defaults to 4096")
508 function bl.validate(self, value)
509 local v = tonumber(value)
511 return nil, err_tab_access(self.title_base, translate("Value is not a number") )
512 elseif v < 1 or v > 4096 then
513 return nil, err_tab_access(self.title_base, translate("Value not between 1 and 4096") )
514 elseif v == self.default then
515 return "" -- dont need to save default
520 -- toggle ----------------------------------------------------------------------
521 local tgl = ns:taboption("access", Flag, "toggle")
522 tgl.title = string.format(HELP, "TOGGLE", "Toggle Status" )
523 tgl.description = translate("Enable/Disable filtering when Privoxy starts.")
525 .. translate("Disabled == Transparent Proxy Mode")
526 tgl.orientation = "horizontal"
529 function tgl.parse(self, section)
530 CTRL.flag_parse(self, section)
533 -- enable-remote-toggle --------------------------------------------------------
534 local ert = ns:taboption("access", Flag, "enable_remote_toggle")
535 ert.title = string.format(HELP, "ENABLE-REMOTE-TOGGLE", "Enable remote toggle" )
536 ert.description = translate("Whether or not the web-based toggle feature may be used.")
537 ert.orientation = "horizontal"
539 function ert.parse(self, section)
540 CTRL.flag_parse(self, section)
543 -- enable-remote-http-toggle ---------------------------------------------------
544 local eht = ns:taboption("access", Flag, "enable_remote_http_toggle")
545 eht.title = string.format(HELP, "ENABLE-REMOTE-HTTP-TOGGLE", "Enable remote toggle via HTTP" )
546 eht.description = translate("Whether or not Privoxy recognizes special HTTP headers to change toggle state.")
547 .. [[<br /><strong>]]
548 .. translate("This option will be removed in future releases as it has been obsoleted by the more general header taggers.")
550 eht.orientation = "horizontal"
552 function eht.parse(self, section)
553 CTRL.flag_parse(self, section)
556 -- enable-edit-actions ---------------------------------------------------------
557 local eea = ns:taboption("access", Flag, "enable_edit_actions")
558 eea.title = string.format(HELP, "ENABLE-EDIT-ACTIONS", "Enable action file editor" )
559 eea.description = translate("Whether or not the web-based actions file editor may be used.")
560 eea.orientation = "horizontal"
562 function eea.parse(self, section)
563 CTRL.flag_parse(self, section)
566 -- enforce-blocks --------------------------------------------------------------
567 local eb = ns:taboption("access", Flag, "enforce_blocks")
568 eb.title = string.format(HELP, "ENFORCE-BLOCKS", "Enforce page blocking" )
569 eb.description = translate("If enabled, Privoxy hides the 'go there anyway' link. "
570 .. "The user obviously should not be able to bypass any blocks.")
571 eb.orientation = "horizontal"
573 function eb.parse(self, section)
574 CTRL.flag_parse(self, section)
577 -- tab: forward -- #############################################################
579 -- enable-proxy-authentication-forwarding --------------------------------------
580 local paf = ns:taboption("forward", Flag, "enable_proxy_authentication_forwarding")
581 paf.title = string.format(HELP, "ENABLE-PROXY-AUTHENTICATION-FORWARDING",
582 translate("Enable proxy authentication forwarding") )
583 paf.description = translate("Whether or not proxy authentication through Privoxy should work.")
584 .. [[<br /><strong>]]
585 .. translate("Enabling this option is NOT recommended if there is no parent proxy that requires authentication!")
587 --paf.orientation = "horizontal"
589 function paf.parse(self, section)
590 CTRL.flag_parse(self, section)
593 -- forward ---------------------------------------------------------------------
594 local fwd = ns:taboption("forward", DynamicList, "forward")
595 fwd.title = string.format(HELP, "FORWARD", "Forward HTTP" )
596 fwd.description = translate("To which parent HTTP proxy specific requests should be routed.")
598 .. translate("Syntax: target_pattern http_parent[:port]")
601 -- forward-socks4 --------------------------------------------------------------
602 local fs4 = ns:taboption("forward", DynamicList, "forward_socks4")
603 fs4.title = string.format(HELP, "SOCKS", "Forward SOCKS 4" )
604 fs4.description = translate("Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.")
606 .. translate("Syntax: target_pattern socks_proxy[:port] http_parent[:port]")
609 -- forward-socks4a -------------------------------------------------------------
610 local f4a = ns:taboption("forward", DynamicList, "forward_socks4a")
611 f4a.title = string.format(HELP, "SOCKS", "Forward SOCKS 4A" )
612 f4a.description = fs4.description
615 -- forward-socks5 --------------------------------------------------------------
616 local fs5 = ns:taboption("forward", DynamicList, "forward_socks5")
617 fs5.title = string.format(HELP, "SOCKS", "Forward SOCKS 5" )
618 fs5.description = fs4.description
621 -- forward-socks5t -------------------------------------------------------------
622 local f5t = ns:taboption("forward", DynamicList, "forward_socks5t")
623 f5t.title = string.format(HELP, "SOCKS", "Forward SOCKS 5t" )
624 f5t.description = fs4.description
627 -- tab: misc -- ################################################################
629 -- accept-intercepted-requests -------------------------------------------------
630 local air = ns:taboption("misc", Flag, "accept_intercepted_requests")
631 air.title = string.format(HELP, "ACCEPT-INTERCEPTED-REQUESTS", "Accept intercepted requests" )
632 air.description = translate("Whether intercepted requests should be treated as valid.")
633 air.orientation = "horizontal"
635 function air.parse(self, section)
636 CTRL.flag_parse(self, section)
639 -- allow-cgi-request-crunching -------------------------------------------------
640 local crc = ns:taboption("misc", Flag, "allow_cgi_request_crunching")
641 crc.title = string.format(HELP, "ALLOW-CGI-REQUEST-CRUNCHING", "Allow CGI request crunching" )
642 crc.description = translate("Whether requests to Privoxy's CGI pages can be blocked or redirected.")
643 crc.orientation = "horizontal"
645 function crc.parse(self, section)
646 CTRL.flag_parse(self, section)
649 -- split-large-forms -----------------------------------------------------------
650 local slf = ns:taboption("misc", Flag, "split_large_forms")
651 slf.title = string.format(HELP, "SPLIT-LARGE-FORMS", "Split large forms" )
652 slf.description = translate("Whether the CGI interface should stay compatible with broken HTTP clients.")
653 slf.orientation = "horizontal"
655 function slf.parse(self, section)
656 CTRL.flag_parse(self, section)
659 -- keep-alive-timeout ----------------------------------------------------------
660 local kat = ns:taboption("misc", Value, "keep_alive_timeout")
661 kat.title_base = "Keep-alive timeout"
662 kat.title = string.format(HELP, "KEEP-ALIVE-TIMEOUT", kat.title_base)
663 kat.description = translate("Number of seconds after which an open connection will no longer be reused.")
665 function kat.validate(self, value)
666 local v = tonumber(value)
668 return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
670 return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
675 -- tolerate-pipelining ---------------------------------------------------------
676 local tp = ns:taboption("misc", Flag, "tolerate_pipelining")
677 tp.title = string.format(HELP, "TOLERATE-PIPELINING", "Tolerate pipelining" )
678 tp.description = translate("Whether or not pipelined requests should be served.")
679 tp.orientation = "horizontal"
681 function tp.parse(self, section)
682 CTRL.flag_parse(self, section)
685 -- default-server-timeout ------------------------------------------------------
686 local dst = ns:taboption("misc", Value, "default_server_timeout")
687 dst.title_base = "Default server timeout"
688 dst.title = string.format(HELP, "DEFAULT-SERVER-TIMEOUT", dst.title_base)
689 dst.description = translate("Assumed server-side keep-alive timeout (in seconds) if not specified by the server.")
691 function dst.validate(self, value)
692 local v = tonumber(value)
694 return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
696 return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
701 -- connection-sharing ----------------------------------------------------------
702 local cs = ns:taboption("misc", Flag, "connection_sharing")
703 cs.title = string.format(HELP, "CONNECTION-SHARING", "Connection sharing" )
704 cs.description = translate("Whether or not outgoing connections that have been kept alive should be shared between different incoming connections.")
705 cs.orientation = "horizontal"
707 function cs.parse(self, section)
708 CTRL.flag_parse(self, section)
711 -- socket-timeout --------------------------------------------------------------
712 local st = ns:taboption("misc", Value, "socket_timeout")
713 st.title_base = "Socket timeout"
714 st.title = string.format(HELP, "SOCKET-TIMEOUT", st.title_base )
715 st.description = translate("Number of seconds after which a socket times out if no data is received.")
718 function st.validate(self, value)
719 local v = tonumber(value)
721 return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
723 return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
724 elseif v == self.default then
725 return "" -- dont need to save default
730 -- max-client-connections ------------------------------------------------------
731 local mcc = ns:taboption("misc", Value, "max_client_connections")
732 mcc.title_base = "Max. client connections"
733 mcc.title = string.format(HELP, "MAX-CLIENT-CONNECTIONS", mcc.title_base )
734 mcc.description = translate("Maximum number of client connections that will be served.")
737 function mcc.validate(self, value)
738 local v = tonumber(value)
740 return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
742 return nil, err_tab_misc(self.title_base, translate("Value not greater 0 or empty") )
743 elseif v == self.default then
744 return "" -- dont need to save default
749 -- handle-as-empty-doc-returns-ok ----------------------------------------------
750 local her = ns:taboption("misc", Flag, "handle_as_empty_doc_returns_ok")
751 her.title = string.format(HELP, "HANDLE-AS-EMPTY-DOC-RETURNS-OK", "Handle as empty doc returns ok" )
752 her.description = translate("The status code Privoxy returns for pages blocked with +handle-as-empty-document.")
753 her.orientation = "horizontal"
755 function her.parse(self, section)
756 CTRL.flag_parse(self, section)
759 -- enable-compression ----------------------------------------------------------
760 local ec = ns:taboption("misc", Flag, "enable_compression")
761 ec.title = string.format(HELP, "ENABLE-COMPRESSION", "Enable compression" )
762 ec.description = translate("Whether or not buffered content is compressed before delivery.")
763 ec.orientation = "horizontal"
765 function ec.parse(self, section)
766 CTRL.flag_parse(self, section)
769 -- compression-level -----------------------------------------------------------
770 local cl = ns:taboption("misc", Value, "compression_level")
771 cl.title_base = "Compression level"
772 cl.title = string.format(HELP, "COMPRESSION-LEVEL", cl.title_base )
773 cl.description = translate("The compression level that is passed to the zlib library when compressing buffered content.")
776 function cl.validate(self, value)
777 local v = tonumber(value)
779 return nil, err_tab_misc(self.title_base, translate("Value is not a number") )
780 elseif v < 0 or v > 9 then
781 return nil, err_tab_misc(self.title_base, translate("Value not between 0 and 9") )
782 elseif v == self.default then
783 return "" -- don't need to save default
788 -- client-header-order ---------------------------------------------------------
789 local cho = ns:taboption("misc", Value, "client_header_order")
790 cho.title = string.format(HELP, "CLIENT-HEADER-ORDER", "Client header order" )
791 cho.description = translate("The order in which client headers are sorted before forwarding them.")
793 .. translate("Syntax: Client header names delimited by spaces.")
796 -- "debug"-tab definition -- ###################################################
798 -- single-threaded -------------------------------------------------------------
799 local st = ns:taboption("debug", Flag, "single_threaded")
800 st.title = string.format(HELP, "SINGLE-THREADED", "Single Threaded" )
801 st.description = translate("Whether to run only one server thread.")
802 .. [[<br /><strong>]]
803 .. translate("This option is only there for debugging purposes. It will drastically reduce performance.")
806 function st.parse(self, section)
807 CTRL.flag_parse(self, section)
810 -- debug 1 ---------------------------------------------------------------------
811 local d0 = ns:taboption("debug", Flag, "debug_1")
812 d0.title = string.format(HELP, "DEBUG", "Debug 1" )
813 d0.description = translate("Log the destination for each request Privoxy let through. See also 'Debug 1024'.")
815 function d0.parse(self, section)
816 CTRL.flag_parse(self, section)
819 -- debug 2 ---------------------------------------------------------------------
820 local d1 = ns:taboption("debug", Flag, "debug_2")
821 d1.title = string.format(HELP, "DEBUG", "Debug 2" )
822 d1.description = translate("Show each connection status")
824 function d1.parse(self, section)
825 CTRL.flag_parse(self, section)
828 -- debug 4 ---------------------------------------------------------------------
829 local d2 = ns:taboption("debug", Flag, "debug_4")
830 d2.title = string.format(HELP, "DEBUG", "Debug 4" )
831 d2.description = translate("Show I/O status")
833 function d2.parse(self, section)
834 CTRL.flag_parse(self, section)
837 -- debug 8 ---------------------------------------------------------------------
838 local d3 = ns:taboption("debug", Flag, "debug_8")
839 d3.title = string.format(HELP, "DEBUG", "Debug 8" )
840 d3.description = translate("Show header parsing")
842 function d3.parse(self, section)
843 CTRL.flag_parse(self, section)
846 -- debug 16 --------------------------------------------------------------------
847 local d4 = ns:taboption("debug", Flag, "debug_16")
848 d4.title = string.format(HELP, "DEBUG", "Debug 16" )
849 d4.description = translate("Log all data written to the network")
851 function d4.parse(self, section)
852 CTRL.flag_parse(self, section)
855 -- debug 32 --------------------------------------------------------------------
856 local d5 = ns:taboption("debug", Flag, "debug_32")
857 d5.title = string.format(HELP, "DEBUG", "Debug 32" )
858 d5.description = translate("Debug force feature")
860 function d5.parse(self, section)
861 CTRL.flag_parse(self, section)
864 -- debug 64 --------------------------------------------------------------------
865 local d6 = ns:taboption("debug", Flag, "debug_64")
866 d6.title = string.format(HELP, "DEBUG", "Debug 64" )
867 d6.description = translate("Debug regular expression filters")
869 function d6.parse(self, section)
870 CTRL.flag_parse(self, section)
873 -- debug 128 -------------------------------------------------------------------
874 local d7 = ns:taboption("debug", Flag, "debug_128")
875 d7.title = string.format(HELP, "DEBUG", "Debug 128" )
876 d7.description = translate("Debug redirects")
878 function d7.parse(self, section)
879 CTRL.flag_parse(self, section)
882 -- debug 256 -------------------------------------------------------------------
883 local d8 = ns:taboption("debug", Flag, "debug_256")
884 d8.title = string.format(HELP, "DEBUG", "Debug 256" )
885 d8.description = translate("Debug GIF de-animation")
887 function d8.parse(self, section)
888 CTRL.flag_parse(self, section)
891 -- debug 512 -------------------------------------------------------------------
892 local d9 = ns:taboption("debug", Flag, "debug_512")
893 d9.title = string.format(HELP, "DEBUG", "Debug 512" )
894 d9.description = translate("Common Log Format")
896 function d9.parse(self, section)
897 CTRL.flag_parse(self, section)
900 -- debug 1024 ------------------------------------------------------------------
901 local d10 = ns:taboption("debug", Flag, "debug_1024")
902 d10.title = string.format(HELP, "DEBUG", "Debug 1024" )
903 d10.description = translate("Log the destination for requests Privoxy didn't let through, and the reason why.")
905 function d10.parse(self, section)
906 CTRL.flag_parse(self, section)
909 -- debug 2048 ------------------------------------------------------------------
910 local d11 = ns:taboption("debug", Flag, "debug_2048")
911 d11.title = string.format(HELP, "DEBUG", "Debug 2048" )
912 d11.description = translate("CGI user interface")
914 function d11.parse(self, section)
915 CTRL.flag_parse(self, section)
918 -- debug 4096 ------------------------------------------------------------------
919 local d12 = ns:taboption("debug", Flag, "debug_4096")
920 d12.title = string.format(HELP, "DEBUG", "Debug 4096" )
921 d12.description = translate("Startup banner and warnings.")
923 function d12.parse(self, section)
924 CTRL.flag_parse(self, section)
927 -- debug 8192 ------------------------------------------------------------------
928 local d13 = ns:taboption("debug", Flag, "debug_8192")
929 d13.title = string.format(HELP, "DEBUG", "Debug 8192" )
930 d13.description = translate("Non-fatal errors - *we highly recommended enabling this*")
932 function d13.parse(self, section)
933 CTRL.flag_parse(self, section)
936 -- debug 16384 -----------------------------------------------------------------
938 local d14 = ns:taboption("debug", Flag, "debug_16384")
939 d14.title = string.format(HELP, "DEBUG", "Debug 16384" )
940 d14.description = translate("")
942 function d14.parse(self, section)
943 CTRL.flag_parse(self, section)
947 -- debug 32768 -----------------------------------------------------------------
948 local d15 = ns:taboption("debug", Flag, "debug_32768")
949 d15.title = string.format(HELP, "DEBUG", "Debug 32768" )
950 d15.description = translate("Log all data read from the network")
952 function d15.parse(self, section)
953 CTRL.flag_parse(self, section)
956 -- debug 65536 -----------------------------------------------------------------
957 local d16 = ns:taboption("debug", Flag, "debug_65536")
958 d16.title = string.format(HELP, "DEBUG", "Debug 65536" )
959 d16.description = translate("Log the applying actions")
961 function d16.parse(self, section)
962 CTRL.flag_parse(self, section)
965 -- tab: logview -- #############################################################
967 local lv = ns:taboption("logview", DummyValue, "_logview")
968 lv.template = "privoxy/detail_logview"
969 lv.inputtitle = translate("Read / Reread log file")
971 function lv.cfgvalue(self, section)
972 local lfile=self.map:get(ns.section, "logdir") .. "/" .. self.map:get(ns.section, "logfile")
973 if NXFS.access(lfile) then
974 return lfile .. "\n" .. translate("Please press [Read] button")
976 return lfile .. "\n" .. translate("File not found or empty")