Merge pull request #579 from cshore/pull-request-protocol-vpnc
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 17 Dec 2015 01:38:41 +0000 (02:38 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 17 Dec 2015 01:38:41 +0000 (02:38 +0100)
protocols: vpnc: Add vpnc as a network protocol

25 files changed:
applications/luci-app-ahcp/po/sv/ahcp.po
applications/luci-app-openvpn/luasrc/model/cbi/openvpn-advanced.lua
applications/luci-app-openvpn/luasrc/model/cbi/openvpn-basic.lua
applications/luci-app-pbx-voicemail/luasrc/model/cbi/pbx-voicemail.lua
applications/luci-app-pbx/luasrc/model/cbi/pbx-advanced.lua
applications/luci-app-pbx/luasrc/model/cbi/pbx-voip.lua
applications/luci-app-statistics/luasrc/model/cbi/luci_statistics/olsrd.lua
applications/luci-app-tinyproxy/luasrc/model/cbi/tinyproxy.lua
applications/luci-app-watchcat/luasrc/model/cbi/watchcat/watchcat.lua
applications/luci-app-wshaper/po/sv/wshaper.po
documentation/api/modules/luci.jsonc.parser.html
libs/luci-lib-jsonc/src/jsonc.c
libs/luci-lib-jsonc/src/jsonc.luadoc
modules/luci-base/htdocs/luci-static/resources/cbi.js
modules/luci-base/luasrc/cbi.lua
modules/luci-base/luasrc/cbi/datatypes.lua
modules/luci-base/luasrc/view/cbi/upload.htm
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
modules/luci-mod-admin-full/luasrc/model/cbi/admin_system/system.lua
protocols/luci-proto-ipv6/luasrc/model/cbi/admin_network/proto_aiccu.lua
protocols/luci-proto-openconnect/luasrc/model/cbi/admin_network/proto_openconnect.lua
protocols/luci-proto-ppp/luasrc/model/cbi/admin_network/proto_l2tp.lua
protocols/luci-proto-ppp/luasrc/model/cbi/admin_network/proto_pppossh.lua
protocols/luci-proto-ppp/luasrc/model/cbi/admin_network/proto_pptp.lua

index b5f0b7d..a7c7a38 100644 (file)
@@ -22,7 +22,7 @@ msgid ""
 msgstr ""
 
 msgid "Active AHCP Leases"
-msgstr ""
+msgstr "Aktiva AHCP-hyror"
 
 msgid "Address"
 msgstr "Adress"
@@ -40,13 +40,13 @@ msgid "Announced NTP servers"
 msgstr "Aviserade NTP-servrar"
 
 msgid "Announced prefixes"
-msgstr ""
+msgstr "Aviserade prefix"
 
 msgid "Collecting data..."
 msgstr "Samlar in data..."
 
 msgid "Forwarder"
-msgstr ""
+msgstr "Vidarebefordrare"
 
 msgid "General Setup"
 msgstr "Allmän inställning"
@@ -61,16 +61,16 @@ msgid "IPv6 only"
 msgstr "Endast IPv6"
 
 msgid "Lease directory"
-msgstr ""
+msgstr "Hyr mappen"
 
 msgid "Lease validity time"
-msgstr ""
+msgstr "Giltighetstid för hyran"
 
 msgid "Log file"
 msgstr "Logg-fil"
 
 msgid "Multicast address"
-msgstr ""
+msgstr "Multicast-adress"
 
 msgid "Operation mode"
 msgstr "Driftsläge"
@@ -82,7 +82,7 @@ msgid "Protocol family"
 msgstr "Protokoll-familj"
 
 msgid "Served interfaces"
-msgstr ""
+msgstr "Betjänade gränssnitt"
 
 msgid "Server"
 msgstr "Server"
@@ -94,16 +94,16 @@ msgid "Specifies the announced IPv4 and IPv6 name servers"
 msgstr "Specificerar de aviserade IPv4 och IPv6 namn-servrarna"
 
 msgid "Specifies the announced IPv4 and IPv6 network prefixes in CIDR notation"
-msgstr ""
+msgstr "Specificerar de aviserade IPv4 och IPv6 nätverksprefixen i CIDR-noteringen"
 
 msgid "The AHCP Service is not running."
 msgstr "AHCP-tjänsten körs inte."
 
 msgid "The AHCP Service is running with ID %s."
-msgstr ""
+msgstr "AHCP-tjänsten körs med ID %s."
 
 msgid "There are no active leases."
-msgstr ""
+msgstr "Det finns inga aktiva hyror."
 
 msgid "Unique ID file"
 msgstr "Unik ID-fil"
index 1508493..af515fc 100644 (file)
@@ -154,7 +154,7 @@ local knownParams = {
        } },
 
        { "Cryptography", {
-               { Value,                "secret",                                               "/etc/openvpn/secret.key 1",                                                                    translate("Enable Static Key encryption mode (non-TLS)") },
+               { FileUpload,   "secret",                                               "/etc/openvpn/secret.key",                                                                      translate("Enable Static Key encryption mode (non-TLS)") },
                { Value,                "auth",                                                 "SHA1",                                                                                                                 translate("HMAC authentication for packets") }, -- parse
                { Value,                "cipher",                                               "BF-CBC",                                                                                                               translate("Encryption cipher for packets") }, -- parse
                { Value,                "keysize",                                              1024,                                                                                                                   translate("Size of cipher key") }, -- parse
@@ -182,13 +182,16 @@ local knownParams = {
                { Value,                "tran_window",                                  3600,                                                                                                                   translate("Key transition window") },
                { Flag,                 "single_session",                               0,                                                                                                                              translate("Allow only one session") },
                { Flag,                 "tls_exit",                                             0,                                                                                                                              translate("Exit on TLS negotiation failure") },
-               { Value,                "tls_auth",                                             "/etc/openvpn/tlsauth.key 1",                                                                   translate("Additional authentication over TLS") },
+               { Value,                "tls_auth",                                             "/etc/openvpn/tlsauth.key",                                                                     translate("Additional authentication over TLS") },
                --{ Value,              "askpass",                                              "[file]",                                                                                                               translate("Get PEM password from controlling tty before we daemonize") },
                { Flag,                 "auth_nocache",                                 0,                                                                                                                              translate("Don't cache --askpass or --auth-user-pass passwords") },
                { Value,                "tls_remote",                                   "remote_x509_name",                                                                                             translate("Only accept connections from given X509 name") },
                { ListValue,    "ns_cert_type",                                 { "client", "server" },                                                                                 translate("Require explicit designation on certificate") },
                { ListValue,    "remote_cert_tls",                              { "client", "server" },                                                                                 translate("Require explicit key usage on certificate") },
                { Value,                "crl_verify",                                   "/etc/easy-rsa/keys/crl.pem",                                                                   translate("Check peer certificate against a CRL") },
+               { Value,        "tls_version_min",              "1.0",                                                                                                                  translate("The lowest supported TLS version") },
+               { Value,        "tls_version_max",              "1.2",                                                                                                                  translate("The highest supported TLS version") },
+               { Value,        "key_direction",                "1",                                                                                                                    translate("The key direction for 'tls-auth' and 'secret' options") },
        } }
 }
 
index e75203d..8385839 100644 (file)
@@ -30,7 +30,8 @@ local basicParams = {
        { Flag,"client_to_client",0, translate("Allow client-to-client traffic") },
        { DynamicList,"remote","vpnserver.example.org", translate("Remote host name or ip address") },
 
-       { FileUpload,"secret","/etc/openvpn/secret.key 1", translate("Enable Static Key encryption mode (non-TLS)") },
+       { FileUpload,"secret","/etc/openvpn/secret.key", translate("Enable Static Key encryption mode (non-TLS)") },
+       { Value,"key_direction","1", translate("The key direction for 'tls-auth' and 'secret' options") },
        { FileUpload,"pkcs12","/etc/easy-rsa/keys/some-client.pk12", translate("PKCS#12 file containing keys") },
        { FileUpload,"ca","/etc/easy-rsa/keys/ca.crt", translate("Certificate authority") },
        { FileUpload,"dh","/etc/easy-rsa/keys/dh1024.pem", translate("Diffie Hellman parameters") },
index 9ff2ed9..a6087e9 100644 (file)
@@ -92,7 +92,7 @@ s = m:section(NamedSection, "voicemail_smtp", "voicemail", translate("Outgoing m
 s.anonymous = true
 
 serv = s:option(Value, "smtp_server", translate("SMTP Server Hostname or IP Address"))
-serv.datatype = "host"
+serv.datatype = "host(0)"
 
 port = s:option(Value, "smtp_port", translate("SMTP Port Number"))
 port.datatype = "port"
index 5d4f135..34288c6 100644 (file)
@@ -264,7 +264,7 @@ h = s:taboption("remote_usage", Value, "externhost", translate("Domain/IP Addres
                 The best thing to input is a static IP address. If your IP address is dynamic and it changes, \
                 your configuration will become invalid. Hence, it's recommended to set up Dynamic DNS in this case. \
                 and enter your Dynamic DNS hostname here. You can configure Dynamic DNS with the luci-app-ddns package."))
-h.datatype = "host"
+h.datatype = "host(0)"
 
 p = s:taboption("remote_usage", Value, "bindport", translate("External SIP Port"),
                 translate("Pick a random port number between 6500 and 9500 for the service to listen on. \
index ed1ed1e..9b46202 100644 (file)
@@ -84,7 +84,7 @@ function pwd.write(self, section, value)
 end
 
 h = s:option(Value, "host", translate("SIP Server/Registrar"))
-h.datatype = "host"
+h.datatype = "host(0)"
 
 p = s:option(ListValue, "register", translate("Enable Incoming Calls (Register via SIP)"),
              translate("This option should be set to \"Yes\" if you have a DID \(real telephone number\) \
@@ -103,7 +103,7 @@ p.default = "yes"
 from = s:option(Value, "fromdomain",
                 translate("SIP Realm (needed by some providers)"))
 from.optional = true
-from.datatype = "host"
+from.datatype = "host(0)"
 
 port = s:option(Value, "port", translate("SIP Server/Registrar Port"))
 port.optional = true
@@ -111,6 +111,6 @@ port.datatype = "port"
 
 op = s:option(Value, "outboundproxy", translate("Outbound Proxy"))
 op.optional = true
-op.datatype = "host"
+op.datatype = "host(0)"
 
 return m
index 59266e5..950d7a7 100644 (file)
@@ -12,7 +12,7 @@ enable.default = 0
 
 host = s:option(Value, "Host", translate("Host"), translate("IP or hostname where to get the txtinfo output from"))
 host.placeholder = "127.0.0.1"
-host.datatype = "host"
+host.datatype = "host(1)"
 host.rmempty = true
 
 port = s:option(Value, "Port", translate("Port"))
index 19bdd9a..11f34fb 100644 (file)
@@ -227,7 +227,7 @@ ta = s:option(Value, "target", translate("Target host"),
 
 ta.rmempty = true
 ta.placeholder = "0.0.0.0/0"
-ta.datatype = "host"
+ta.datatype = "host(1)"
 
 
 v = s:option(Value, "via", translate("Via proxy"),
@@ -235,5 +235,6 @@ v = s:option(Value, "via", translate("Via proxy"),
 
 v:depends({type="proxy"})
 v.placeholder = "10.0.0.1:8080"
+v.datatype = "ip4addrport"
 
 return m
index 883416b..f64370b 100644 (file)
@@ -38,7 +38,7 @@ period = s:option(Value, "period",
 pinghost = s:option(Value, "pinghosts", 
                    translate("Ping host"),
                    translate("Host address to ping"))
-pinghost.datatype = "host"
+pinghost.datatype = "host(1)"
 pinghost.default = "8.8.8.8"
 pinghost:depends({mode="ping"})
 
index b85651a..84c5ce1 100644 (file)
@@ -10,40 +10,40 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 msgid "Downlink"
-msgstr ""
+msgstr "Ner-länk"
 
 msgid "Downstream bandwidth in kbit/s"
-msgstr ""
+msgstr "Nerströms bandbredd i kbit/s"
 
 msgid "Host or Network in CIDR notation."
 msgstr ""
 
 msgid "Interface"
-msgstr ""
+msgstr "Gränssnitt"
 
 msgid "Low priority destination ports"
-msgstr ""
+msgstr "Destinations-portar med låg prioritet"
 
 msgid "Low priority hosts (Destination)"
-msgstr ""
+msgstr "Värdar med låg prioritet (Destination)"
 
 msgid "Low priority hosts (Source)"
-msgstr ""
+msgstr "Värdar med låg prioritet (Källa)"
 
 msgid "Low priority source ports"
-msgstr ""
+msgstr "Käll-portar med låg prioritet"
 
 msgid "Uplink"
-msgstr ""
+msgstr "Upplänk"
 
 msgid "Upstream bandwidth in kbit/s"
-msgstr ""
+msgstr "Bandbredd uppströms i kbit/s"
 
 msgid "Wondershaper"
-msgstr ""
+msgstr "Wondershaper"
 
 msgid "Wondershaper settings"
-msgstr ""
+msgstr "Inställningar för Wondershaper"
 
 msgid ""
 "Wondershaper shapes traffic to ensure low latencies for interactive traffic "
index 4c19cf0..e8e145f 100644 (file)
@@ -234,6 +234,13 @@ Put Lua data into the parser.</td>
        </tr>
 
        <tr>
+       <td class="name" nowrap><a href="#parser.sink">parser:sink</a>&nbsp;()</td>
+       <td class="summary">
+Generate an ltn12-compatible sink.</td>
+       </tr>
+
+       <tr>
        <td class="name" nowrap><a href="#parser.stringify">parser:stringify</a>&nbsp;(pretty)</td>
        <td class="summary">
  
@@ -406,6 +413,34 @@ Nothing is returned.
 
 
 
+<dt><a name="parser.sink"></a><strong>parser:sink</strong>&nbsp;()</dt>
+<dd>
+
+Generate an ltn12-compatible sink. 
+
+
+
+
+
+
+<h3>Usage:</h3>
+<pre>parser = luci.jsonc.new() 
+ltn12.pump.all(ltn12.source.file(io.input()), parser:sink()) 
+print(parser:get())</pre>
+
+
+
+<h3>Return value:</h3>
+Returns a function that can be used as an ltn12 sink.
+
+
+
+</dd>
+
+
+
+
 <dt><a name="parser.stringify"></a><strong>parser:stringify</strong>&nbsp;(pretty)</dt>
 <dd>
 
index b857c97..ef11101 100644 (file)
@@ -328,6 +328,76 @@ static int json_parse_set(lua_State *L)
        return 0;
 }
 
+static int json_parse_sink_closure(lua_State *L)
+{
+       bool finished = lua_toboolean(L, lua_upvalueindex(2));
+       if (lua_isnil(L, 1))
+       {
+               // no more data available
+               if (finished)
+               {
+                       // we were finished parsing
+                       lua_pushboolean(L, true);
+                       return 1;
+               }
+               else
+               {
+                       lua_pushnil(L);
+                       lua_pushstring(L, "Incomplete JSON data");
+                       return 2;
+               }
+       }
+       else
+       {
+               if (finished)
+               {
+                       lua_pushnil(L);
+                       lua_pushstring(L, "Unexpected data after complete JSON object");
+                       return 2;
+               }
+               else
+               {
+                       // luci.jsonc.parser.chunk()
+                       lua_pushcfunction(L, json_parse_chunk);
+                       // parser object from closure
+                       lua_pushvalue(L, lua_upvalueindex(1));
+                       // chunk
+                       lua_pushvalue(L, 1);
+                       lua_call(L, 2, 2);
+
+                       if (lua_isnil(L, -2))
+                       {
+                               // an error occurred, leave (nil, errmsg) on the stack and return it
+                               return 2;
+                       }
+                       else if (lua_toboolean(L, -2))
+                       {
+                               // finished reading, set finished=true and return nil to prevent further input
+                               lua_pop(L, 2);
+                               lua_pushboolean(L, true);
+                               lua_replace(L, lua_upvalueindex(2));
+                               lua_pushnil(L);
+                               return 1;
+                       }
+                       else
+                       {
+                               // not finished reading, return true
+                               lua_pop(L, 2);
+                               lua_pushboolean(L, true);
+                               return 1;
+                       }
+               }
+       }
+}
+
+static int json_parse_sink(lua_State *L)
+{
+       luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
+       lua_pushboolean(L, false);
+       lua_pushcclosure(L, json_parse_sink_closure, 2);
+       return 1;
+}
+
 static int json_tostring(lua_State *L)
 {
        struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);
@@ -367,6 +437,7 @@ static const luaL_reg jsonc_parser_methods[] = {
        { "parse",                      json_parse_chunk  },
        { "get",                        json_parse_get    },
        { "set",                        json_parse_set    },
+       { "sink",                       json_parse_sink   },
        { "stringify",          json_tostring     },
 
        { "__gc",                       json_gc           },
index 2ee9ceb..720b17d 100644 (file)
@@ -121,10 +121,22 @@ parser:set({ "some", "data" })`
 ]]
 
 ---[[
-Serialize current parser state as JSON.
+Generate an ltn12-compatible sink.
 
 @class function
 @sort 4
+@name parser.sink
+@return Returns a function that can be used as an ltn12 sink.
+@usage `parser = luci.jsonc.new()
+ltn12.pump.all(ltn12.source.file(io.input()), parser:sink())
+print(parser:get())`
+]]
+
+---[[
+Serialize current parser state as JSON.
+
+@class function
+@sort 5
 @name parser.stringify
 @param pretty A boolean value indicating whether the resulting JSON should be pretty printed.
 @return Returns the serialized JSON data of this parser instance.
index 4b7227f..1c4123b 100644 (file)
@@ -139,10 +139,11 @@ var cbi_validators = {
                return (this.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null);
        },
 
-       'host': function()
+       'host': function(ipv4only)
        {
                return cbi_validators.hostname.apply(this) ||
-                       cbi_validators.ipaddr.apply(this);
+                       ((ipv4only != 1) && cbi_validators.ipaddr.apply(this)) ||
+                       ((ipv4only == 1) && cb_validators.ip4addr.apply(this));
        },
 
        'hostname': function()
@@ -161,28 +162,49 @@ var cbi_validators = {
                        cbi_validators.host.apply(this);
        },
 
-       'hostport': function()
+       'hostport': function(ipv4only)
        {
                var hp = this.split(/:/);
 
                if (hp.length == 2)
-                       return (cbi_validators.host.apply(hp[0]) &&
+                       return (cbi_validators.host.apply(hp[0], ipv4only) &&
                                cbi_validators.port.apply(hp[1]));
 
                return false;
        },
 
-       'ipaddrport': function()
+       'ip4addrport': function()
        {
                var hp = this.split(/:/);
 
                if (hp.length == 2)
                        return (cbi_validators.ipaddr.apply(hp[0]) &&
                                cbi_validators.port.apply(hp[1]));
-
                return false;
        },
 
+       'ipaddrport': function(bracket)
+       {
+               if (this.match(/^([^\[\]:]+):([^:]+)$/)) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip4addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+                } else if ((bracket == 1) && (this.match(/^\[(.+)\]:([^:]+)$/))) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip6addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+                } else if ((bracket != 1) && (this.match(/^([^\[\]]+):([^:]+)$/))) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip6addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+               } else {
+                       return false;
+               }
+       },
+
        'wpakey': function()
        {
                var v = this;
index 8fd0a33..2c1bb4d 100644 (file)
@@ -1811,6 +1811,7 @@ function Button.__init__(self, ...)
        self.template  = "cbi/button"
        self.inputstyle = nil
        self.rmempty = true
+        self.unsafeupload = false
 end
 
 
@@ -1827,9 +1828,15 @@ function FileUpload.__init__(self, ...)
 end
 
 function FileUpload.formcreated(self, section)
-       return AbstractValue.formcreated(self, section) or
-               self.map:formvalue("cbi.rlf."..section.."."..self.option) or
-               self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
+       if self.unsafeupload then
+               return AbstractValue.formcreated(self, section) or
+                       self.map:formvalue("cbi.rlf."..section.."."..self.option) or
+                       self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or
+                       self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+       else
+               return AbstractValue.formcreated(self, section) or
+                       self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+       end
 end
 
 function FileUpload.cfgvalue(self, section)
@@ -1840,27 +1847,50 @@ function FileUpload.cfgvalue(self, section)
        return nil
 end
 
+-- If we have a new value, use it
+-- otherwise use old value
+-- deletion should be managed by a separate button object
+-- unless self.unsafeupload is set in which case if the user
+-- choose to remove the old file we do so.
+-- Also, allow to specify (via textbox) a file already on router
 function FileUpload.formvalue(self, section)
        local val = AbstractValue.formvalue(self, section)
        if val then
-               if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
-                  not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
-               then
+               if self.unsafeupload then
+                       if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
+                           not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
+                       then
+                               return val
+                       end
+                       fs.unlink(val)
+                       self.value = nil
+                       return nil
+                elseif val ~= "" then
                        return val
-               end
-               fs.unlink(val)
-               self.value = nil
+                end
        end
-       return nil
+       val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
+       if val == "" then
+               val = nil
+       end
+        if not self.unsafeupload then
+               if not val then
+                       val = self.map:formvalue("cbi.rlf."..section.."."..self.option)
+               end
+        end
+       return val
 end
 
 function FileUpload.remove(self, section)
-       local val = AbstractValue.formvalue(self, section)
-       if val and fs.access(val) then fs.unlink(val) end
-       return AbstractValue.remove(self, section)
+       if self.unsafeupload then
+               local val = AbstractValue.formvalue(self, section)
+               if val and fs.access(val) then fs.unlink(val) end
+               return AbstractValue.remove(self, section)
+       else
+               return nil
+       end
 end
 
-
 FileBrowser = class(AbstractValue)
 
 function FileBrowser.__init__(self, ...)
index 4c003be..626ad91 100644 (file)
@@ -176,22 +176,41 @@ function hostname(val)
        return false
 end
 
-function host(val)
-       return hostname(val) or ipaddr(val)
+function host(val, ipv4only)
+       return hostname(val) or ((ipv4only == 1) and ip4addr(val)) or ((not (ipv4only == 1)) and ipaddr(val))
 end
 
 function network(val)
        return uciname(val) or host(val)
 end
 
-function hostport(val)
+function hostport(val, ipv4only)
        local h, p = val:match("^([^:]+):([^:]+)$")
-       return not not (h and p and host(h) and port(p))
+       return not not (h and p and host(h, ipv4only) and port(p))
 end
 
-function ipaddrport(val)
+function ip4addrport(val, bracket)
        local h, p = val:match("^([^:]+):([^:]+)$")
-       return not not (h and p and ipaddr(h) and port(p))
+       return (h and p and ip4addr(h) and port(p))
+end
+
+function ip4addrport(val)
+       local h, p = val:match("^([^:]+):([^:]+)$")
+       return (h and p and ip4addr(h) and port(p))
+end
+
+function ipaddrport(val, bracket)
+       local h, p = val:match("^([^%[%]:]+):([^:]+)$")
+       if (h and p and ip4addr(h) and port(p)) then
+               return true
+       elseif (bracket == 1) then
+               h, p = val:match("^%[(.+)%]:([^:]+)$")
+               if  (h and p and ip6addr(h) and port(p)) then
+                       return true
+               end
+       end
+       h, p = val:match("^([^%[%]]+):([^:]+)$")
+       return (h and p and ip6addr(h) and port(p))
 end
 
 function wpakey(val)
index 7770934..157f3b3 100644 (file)
@@ -6,9 +6,19 @@
 <%+cbi/valueheader%>
        <% if s then %>
                <%:Uploaded File%> (<%=t.byte_format(s.size)%>)
-               <input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
-               <input class="cbi-button cbi-input-image" type="image" value="<%:Replace entry%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:Replace entry%>" title="<%:Replace entry%>" src="<%=resource%>/cbi/reload.gif" />
-       <% else %>
+                <% if self.unsafeupload then %>
+                   <input type="hidden"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
+                   <input class="cbi-button cbi-input-image" type="image" value="<%:Replace entry%>" name="cbi.rlf.<%=section .. "." .. self.option%>" alt="<%:Replace entry%>" title="<%:Replace entry%>" src="<%=resource%>/cbi/reload.gif" />
+                <% end %>
+       <% end %>
+
+        <% if not self.unsafeupload then %>
+               <input type="hidden"<%= attr("value", v) .. attr("name", "cbi.rlf." .. section .. "." .. self.option) .. attr("id", "cbi.rlf." .. section .. "." .. self.option) %> />
+       <% end %>
+               
+       <% if (not s) or (s and not self.unsafeupload) then %>
                <input class="cbi-input-file" type="file"<%= attr("name", cbid) .. attr("id", cbid) %> />
        <% end %>
+       <input type="text" class="cbi-input-text" onchange="cbi_d_update(this.id)"<%=
+               attr("name", cbid .. ".textbox") .. attr("id", cbid .. ".textbox") .. attr("value", luci.cbi.AbstractValue.cfgvalue(self, section) or self.default) .. ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder") .. ifattr(self.readonly, "readonly") .. ifattr(self.maxlength, "maxlength") %> />
 <%+cbi/valuefooter%>
index 4dc52ad..572446f 100644 (file)
@@ -135,7 +135,7 @@ rd = s:taboption("general", DynamicList, "rebind_domain",
        translate("List of domains to allow RFC1918 responses for"))
 
 rd:depends("rebind_protection", "1")
-rd.datatype = "host"
+rd.datatype = "host(1)"
 rd.placeholder = "ihost.netflix.com"
 
 
index b91c29b..4452892 100644 (file)
@@ -749,7 +749,7 @@ auth_server:depends({mode="ap", encryption="wpa2"})
 auth_server:depends({mode="ap-wds", encryption="wpa"})
 auth_server:depends({mode="ap-wds", encryption="wpa2"})
 auth_server.rmempty = true
-auth_server.datatype = "host"
+auth_server.datatype = "host(0)"
 
 auth_port = s:taboption("encryption", Value, "auth_port", translate("Radius-Authentication-Port"), translatef("Default %d", 1812))
 auth_port:depends({mode="ap", encryption="wpa"})
@@ -773,7 +773,7 @@ acct_server:depends({mode="ap", encryption="wpa2"})
 acct_server:depends({mode="ap-wds", encryption="wpa"})
 acct_server:depends({mode="ap-wds", encryption="wpa2"})
 acct_server.rmempty = true
-acct_server.datatype = "host"
+acct_server.datatype = "host(0)"
 
 acct_port = s:taboption("encryption", Value, "acct_port", translate("Radius-Accounting-Port"), translatef("Default %d", 1813))
 acct_port:depends({mode="ap", encryption="wpa"})
index 94ba805..2874b56 100644 (file)
@@ -204,7 +204,7 @@ if has_ntpd then
 
 
                o = s:option(DynamicList, "server", translate("NTP server candidates"))
-               o.datatype = "host"
+               o.datatype = "host(0)"
                o:depends("enable", "1")
 
                -- retain server list even if disabled
index 9315dc2..7b5e604 100644 (file)
@@ -39,7 +39,7 @@ protocol.optional = true
 server = section:taboption("general", Value, "server",
        translate("Tunnel setup server"),
        translate("Optional, specify to override default server (tic.sixxs.net)"))
-server.datatype = "host"
+server.datatype = "host(0)"
 server.optional = true
 
 
index 4ed34ae..ad3f2ed 100644 (file)
@@ -13,7 +13,7 @@ oc_key_file = "/etc/openconnect/user-key-" .. ifc .. ".pem"
 oc_ca_file = "/etc/openconnect/ca-" .. ifc .. ".pem"
 
 server = section:taboption("general", Value, "server", translate("VPN Server"))
-server.datatype = "host"
+server.datatype = "host(0)"
 
 port = section:taboption("general", Value, "port", translate("VPN Server port"))
 port.placeholder = "443"
index 5e8b3fc..506170c 100644 (file)
@@ -8,7 +8,7 @@ local ipv6, defaultroute, metric, peerdns, dns, mtu
 
 
 server = section:taboption("general", Value, "server", translate("L2TP Server"))
-server.datatype = "or(host, hostport)"
+server.datatype = "or(host(1), hostport(1))"
 
 
 username = section:taboption("general", Value, "username", translate("PAP/CHAP username"))
index c93353a..eca7bdd 100644 (file)
@@ -8,7 +8,7 @@ local sshuser, server, port, ssh_options, identity, ipaddr, peeraddr
 sshuser = section:taboption("general", Value, "sshuser", translate("SSH username"))
 
 server = section:taboption("general", Value, "server", translate("SSH server address"))
-server.datatype = "host"
+server.datatype = "host(0)"
 
 port = section:taboption("general", Value, "port", translate("SSH server port"))
 port.datatype = "port"
index d81db1f..462d701 100644 (file)
@@ -9,7 +9,7 @@ local defaultroute, metric, peerdns, dns,
 
 
 server = section:taboption("general", Value, "server", translate("VPN Server"))
-server.datatype = "host"
+server.datatype = "host(0)"
 
 
 username = section:taboption("general", Value, "username", translate("PAP/CHAP username"))