libs/cbi: allow underscores in AbstractSection.create()
[project/luci.git] / libs / cbi / luasrc / cbi.lua
1 --[[
2 LuCI - Configuration Bind Interface
3
4 Description:
5 Offers an interface for binding configuration values to certain
6 data types. Supports value and range validation and basic dependencies.
7
8 FileId:
9 $Id$
10
11 License:
12 Copyright 2008 Steven Barth <steven@midlink.org>
13
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at
17
18         http://www.apache.org/licenses/LICENSE-2.0
19
20 Unless required by applicable law or agreed to in writing, software
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
25
26 ]]--
27 module("luci.cbi", package.seeall)
28
29 require("luci.template")
30 local util = require("luci.util")
31 require("luci.http")
32 require("luci.uvl")
33
34
35 --local event      = require "luci.sys.event"
36 local fs         = require("nixio.fs")
37 local uci        = require("luci.model.uci")
38 local class      = util.class
39 local instanceof = util.instanceof
40
41 FORM_NODATA  =  0
42 FORM_PROCEED =  0
43 FORM_VALID   =  1
44 FORM_DONE        =  1
45 FORM_INVALID = -1
46 FORM_CHANGED =  2
47 FORM_SKIP    =  4
48
49 AUTO = true
50
51 CREATE_PREFIX = "cbi.cts."
52 REMOVE_PREFIX = "cbi.rts."
53
54 -- Loads a CBI map from given file, creating an environment and returns it
55 function load(cbimap, ...)
56         local fs   = require "nixio.fs"
57         local i18n = require "luci.i18n"
58         require("luci.config")
59         require("luci.util")
60
61         local upldir = "/lib/uci/upload/"
62         local cbidir = luci.util.libpath() .. "/model/cbi/"
63         local func, err
64
65         if fs.access(cbimap) then
66                 func, err = loadfile(cbimap)
67         elseif fs.access(cbidir..cbimap..".lua") then
68                 func, err = loadfile(cbidir..cbimap..".lua")
69         elseif fs.access(cbidir..cbimap..".lua.gz") then
70                 func, err = loadfile(cbidir..cbimap..".lua.gz")
71         else
72                 func, err = nil, "Model '" .. cbimap .. "' not found!"
73         end
74
75         assert(func, err)
76
77         luci.i18n.loadc("cbi")
78         luci.i18n.loadc("uvl")
79
80         local env = {
81                 translate=i18n.translate,
82                 translatef=i18n.translatef,
83                 arg={...}
84         }
85
86         setfenv(func, setmetatable(env, {__index =
87                 function(tbl, key)
88                         return rawget(tbl, key) or _M[key] or _G[key]
89                 end}))
90
91         local maps       = { func() }
92         local uploads    = { }
93         local has_upload = false
94
95         for i, map in ipairs(maps) do
96                 if not instanceof(map, Node) then
97                         error("CBI map returns no valid map object!")
98                         return nil
99                 else
100                         map:prepare()
101                         if map.upload_fields then
102                                 has_upload = true
103                                 for _, field in ipairs(map.upload_fields) do
104                                         uploads[
105                                                 field.config .. '.' ..
106                                                 field.section.sectiontype .. '.' ..
107                                                 field.option
108                                         ] = true
109                                 end
110                         end
111                 end
112         end
113
114         if has_upload then
115                 local uci = luci.model.uci.cursor()
116                 local prm = luci.http.context.request.message.params
117                 local fd, cbid
118
119                 luci.http.setfilehandler(
120                         function( field, chunk, eof )
121                                 if not field then return end
122                                 if field.name and not cbid then
123                                         local c, s, o = field.name:gmatch(
124                                                 "cbid%.([^%.]+)%.([^%.]+)%.([^%.]+)"
125                                         )()
126
127                                         if c and s and o then
128                                                 local t = uci:get( c, s )
129                                                 if t and uploads[c.."."..t.."."..o] then
130                                                         local path = upldir .. field.name
131                                                         fd = io.open(path, "w")
132                                                         if fd then
133                                                                 cbid = field.name
134                                                                 prm[cbid] = path
135                                                         end
136                                                 end
137                                         end
138                                 end
139
140                                 if field.name == cbid and fd then
141                                         fd:write(chunk)
142                                 end
143
144                                 if eof and fd then
145                                         fd:close()
146                                         fd   = nil
147                                         cbid = nil
148                                 end
149                         end
150                 )
151         end
152
153         return maps
154 end
155
156 local function _uvl_validate_section(node, name)
157         local co = node.map:get()
158
159         luci.uvl.STRICT_UNKNOWN_OPTIONS = false
160         luci.uvl.STRICT_UNKNOWN_SECTIONS = false
161
162         local function tag_fields(e)
163                 if e.option and node.fields[e.option] then
164                         if node.fields[e.option].error then
165                                 node.fields[e.option].error[name] = e
166                         else
167                                 node.fields[e.option].error = { [name] = e }
168                         end
169                 elseif e.childs then
170                         for _, c in ipairs(e.childs) do tag_fields(c) end
171                 end
172         end
173
174         local function tag_section(e)
175                 local s = { }
176                 for _, c in ipairs(e.childs or { e }) do
177                         if c.childs and not c:is(luci.uvl.errors.ERR_DEPENDENCY) then
178                                 table.insert( s, c.childs[1]:string() )
179                         else
180                                 table.insert( s, c:string() )
181                         end
182                 end
183                 if #s > 0 then
184                         if node.error then
185                                 node.error[name] = s
186                         else
187                                 node.error = { [name] = s }
188                         end
189                 end
190         end
191
192         local stat, err = node.map.validator:validate_section(node.config, name, co)
193         if err then
194                 node.map.save = false
195                 tag_fields(err)
196                 tag_section(err)
197         end
198
199 end
200
201 local function _uvl_strip_remote_dependencies(deps)
202         local clean = {}
203
204         for k, v in pairs(deps) do
205                 k = k:gsub("%$config%.%$section%.", "")
206                 if k:match("^[%w_]+$") and type(v) == "string" then
207                         clean[k] = v
208                 end
209         end
210
211         return clean
212 end
213
214
215 -- Node pseudo abstract class
216 Node = class()
217
218 function Node.__init__(self, title, description)
219         self.children = {}
220         self.title = title or ""
221         self.description = description or ""
222         self.template = "cbi/node"
223 end
224
225 -- i18n helper
226 function Node._i18n(self, config, section, option, title, description)
227
228         -- i18n loaded?
229         if type(luci.i18n) == "table" then
230
231                 local key = config and config:gsub("[^%w]+", "") or ""
232
233                 if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
234                 if option  then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "")  end
235
236                 self.title = title or luci.i18n.translate( key, option or section or config )
237                 self.description = description or luci.i18n.translate( key .. "_desc", "" )
238         end
239 end
240
241 -- Prepare nodes
242 function Node.prepare(self, ...)
243         for k, child in ipairs(self.children) do
244                 child:prepare(...)
245         end
246 end
247
248 -- Append child nodes
249 function Node.append(self, obj)
250         table.insert(self.children, obj)
251 end
252
253 -- Parse this node and its children
254 function Node.parse(self, ...)
255         for k, child in ipairs(self.children) do
256                 child:parse(...)
257         end
258 end
259
260 -- Render this node
261 function Node.render(self, scope)
262         scope = scope or {}
263         scope.self = self
264
265         luci.template.render(self.template, scope)
266 end
267
268 -- Render the children
269 function Node.render_children(self, ...)
270         for k, node in ipairs(self.children) do
271                 node:render(...)
272         end
273 end
274
275
276 --[[
277 A simple template element
278 ]]--
279 Template = class(Node)
280
281 function Template.__init__(self, template)
282         Node.__init__(self)
283         self.template = template
284 end
285
286 function Template.render(self)
287         luci.template.render(self.template, {self=self})
288 end
289
290 function Template.parse(self, readinput)
291         self.readinput = (readinput ~= false)
292         return Map.formvalue(self, "cbi.submit") and FORM_DONE or FORM_NODATA
293 end
294
295
296 --[[
297 Map - A map describing a configuration file
298 ]]--
299 Map = class(Node)
300
301 function Map.__init__(self, config, ...)
302         Node.__init__(self, ...)
303         Node._i18n(self, config, nil, nil, ...)
304
305         self.config = config
306         self.parsechain = {self.config}
307         self.template = "cbi/map"
308         self.apply_on_parse = nil
309         self.readinput = true
310         self.proceed = false
311         self.flow = {}
312
313         self.uci = uci.cursor()
314         self.save = true
315
316         self.changed = false
317
318         if not self.uci:load(self.config) then
319                 error("Unable to read UCI data: " .. self.config)
320         end
321
322         self.validator = luci.uvl.UVL()
323         self.scheme = self.validator:get_scheme(self.config)
324
325 end
326
327 function Map.formvalue(self, key)
328         return self.readinput and luci.http.formvalue(key)
329 end
330
331 function Map.formvaluetable(self, key)
332         return self.readinput and luci.http.formvaluetable(key) or {}
333 end
334
335 function Map.get_scheme(self, sectiontype, option)
336         if not option then
337                 return self.scheme and self.scheme.sections[sectiontype]
338         else
339                 return self.scheme and self.scheme.variables[sectiontype]
340                  and self.scheme.variables[sectiontype][option]
341         end
342 end
343
344 function Map.submitstate(self)
345         return self:formvalue("cbi.submit")
346 end
347
348 -- Chain foreign config
349 function Map.chain(self, config)
350         table.insert(self.parsechain, config)
351 end
352
353 function Map.state_handler(self, state)
354         return state
355 end
356
357 -- Use optimized UCI writing
358 function Map.parse(self, readinput, ...)
359         self.readinput = (readinput ~= false)
360
361         if self:formvalue("cbi.skip") then
362                 self.state = FORM_SKIP
363                 return self:state_handler(self.state)
364         end
365
366         Node.parse(self, ...)
367
368         if self.save then
369                 for i, config in ipairs(self.parsechain) do
370                         self.uci:save(config)
371                 end
372                 if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then
373                         for i, config in ipairs(self.parsechain) do
374                                 self.uci:commit(config)
375
376                                 -- Refresh data because commit changes section names
377                                 self.uci:load(config)
378                         end
379                         if self.apply_on_parse then
380                                 self.uci:apply(self.parsechain)
381                         else
382                                 self._apply = function()
383                                         local cmd = self.uci:apply(self.parsechain, true)
384                                         return io.popen(cmd)
385                                 end
386                         end
387
388                         -- Reparse sections
389                         Node.parse(self, true)
390
391                 end
392                 for i, config in ipairs(self.parsechain) do
393                         self.uci:unload(config)
394                 end
395                 if type(self.commit_handler) == "function" then
396                         self:commit_handler(self:submitstate())
397                 end
398         end
399
400         if self:submitstate() then
401                 if not self.save then
402                         self.state = FORM_INVALID
403                 elseif self.proceed then
404                         self.state = FORM_PROCEED
405                 else
406                         self.state = self.changed and FORM_CHANGED or FORM_VALID
407                 end
408         else
409                 self.state = FORM_NODATA
410         end
411
412         return self:state_handler(self.state)
413 end
414
415 function Map.render(self, ...)
416         Node.render(self, ...)
417         if self._apply then
418                 local fp = self._apply()
419                 fp:read("*a")
420                 fp:close()
421         end
422 end
423
424 -- Creates a child section
425 function Map.section(self, class, ...)
426         if instanceof(class, AbstractSection) then
427                 local obj  = class(self, ...)
428                 self:append(obj)
429                 return obj
430         else
431                 error("class must be a descendent of AbstractSection")
432         end
433 end
434
435 -- UCI add
436 function Map.add(self, sectiontype)
437         return self.uci:add(self.config, sectiontype)
438 end
439
440 -- UCI set
441 function Map.set(self, section, option, value)
442         if option then
443                 return self.uci:set(self.config, section, option, value)
444         else
445                 return self.uci:set(self.config, section, value)
446         end
447 end
448
449 -- UCI del
450 function Map.del(self, section, option)
451         if option then
452                 return self.uci:delete(self.config, section, option)
453         else
454                 return self.uci:delete(self.config, section)
455         end
456 end
457
458 -- UCI get
459 function Map.get(self, section, option)
460         if not section then
461                 return self.uci:get_all(self.config)
462         elseif option then
463                 return self.uci:get(self.config, section, option)
464         else
465                 return self.uci:get_all(self.config, section)
466         end
467 end
468
469 --[[
470 Compound - Container
471 ]]--
472 Compound = class(Node)
473
474 function Compound.__init__(self, ...)
475         Node.__init__(self)
476         self.template = "cbi/compound"
477         self.children = {...}
478 end
479
480 function Compound.populate_delegator(self, delegator)
481         for _, v in ipairs(self.children) do
482                 v.delegator = delegator
483         end
484 end
485
486 function Compound.parse(self, ...)
487         local cstate, state = 0
488
489         for k, child in ipairs(self.children) do
490                 cstate = child:parse(...)
491                 state = (not state or cstate < state) and cstate or state
492         end
493
494         return state
495 end
496
497
498 --[[
499 Delegator - Node controller
500 ]]--
501 Delegator = class(Node)
502 function Delegator.__init__(self, ...)
503         Node.__init__(self, ...)
504         self.nodes = {}
505         self.defaultpath = {}
506         self.pageaction = false
507         self.readinput = true
508         self.allow_reset = false
509         self.allow_back = false
510         self.allow_finish = false
511         self.template = "cbi/delegator"
512 end
513
514 function Delegator.set(self, name, node)
515         if type(node) == "table" and getmetatable(node) == nil then
516                 node = Compound(unpack(node))
517         end
518         assert(type(node) == "function" or instanceof(node, Compound), "Invalid")
519         assert(not self.nodes[name], "Duplicate entry")
520
521         self.nodes[name] = node
522 end
523
524 function Delegator.add(self, name, node)
525         node = self:set(name, node)
526         self.defaultpath[#self.defaultpath+1] = name
527 end
528
529 function Delegator.insert_after(self, name, after)
530         local n = #self.chain
531         for k, v in ipairs(self.chain) do
532                 if v == state then
533                         n = k + 1
534                         break
535                 end
536         end
537         table.insert(self.chain, n, name)
538 end
539
540 function Delegator.set_route(self, ...)
541         local n, chain, route = 0, self.chain, {...}
542         for i = 1, #chain do
543                 if chain[i] == self.current then
544                         n = i
545                         break
546                 end
547         end
548         for i = 1, #route do
549                 n = n + 1
550                 chain[n] = route[i]
551         end
552         for i = n + 1, #chain do
553                 chain[i] = nil
554         end
555 end
556
557 function Delegator.get(self, name)
558         return self.nodes[name]
559 end
560
561 function Delegator.parse(self, ...)
562         local newcurrent
563         self.chain = self.chain or self:get_chain()
564         self.current = self.current or self:get_active()
565         self.active = self.active or self:get(self.current)
566         assert(self.active, "Invalid state")
567         
568         local stat = FORM_DONE
569         if type(self.active) ~= "function" then
570                 self.active:populate_delegator(self)
571                 stat = self.active:parse() 
572         else
573                 self:active()
574         end
575
576         if stat > FORM_PROCEED then
577                 if Map.formvalue(self, "cbi.delg.back") then
578                         newcurrent = self:get_prev(self.current)
579                 else
580                         newcurrent = self:get_next(self.current)
581                 end
582         elseif stat < FORM_PROCEED then
583                 return stat
584         end
585         
586
587         if not Map.formvalue(self, "cbi.submit") then
588                 return FORM_NODATA
589         elseif not newcurrent or not self:get(newcurrent) then
590                 return FORM_DONE
591         else
592                 self.current = newcurrent
593                 self.active = self:get(self.current)
594                 if type(self.active) ~= "function" then
595                         self.active:parse(false)
596                         return FROM_PROCEED
597                 else
598                         return self:parse(...)
599                 end
600         end
601 end
602
603 function Delegator.get_next(self, state)
604         for k, v in ipairs(self.chain) do
605                 if v == state then
606                         return self.chain[k+1]
607                 end
608         end
609 end
610
611 function Delegator.get_prev(self, state)
612         for k, v in ipairs(self.chain) do
613                 if v == state then
614                         return self.chain[k-1]
615                 end
616         end
617 end
618
619 function Delegator.get_chain(self)
620         local x = Map.formvalue(self, "cbi.delg.path") or self.defaultpath
621         return type(x) == "table" and x or {x}
622 end
623
624 function Delegator.get_active(self)
625         return Map.formvalue(self, "cbi.delg.current") or self.chain[1]
626 end
627
628 --[[
629 Page - A simple node
630 ]]--
631
632 Page = class(Node)
633 Page.__init__ = Node.__init__
634 Page.parse    = function() end
635
636
637 --[[
638 SimpleForm - A Simple non-UCI form
639 ]]--
640 SimpleForm = class(Node)
641
642 function SimpleForm.__init__(self, config, title, description, data)
643         Node.__init__(self, title, description)
644         self.config = config
645         self.data = data or {}
646         self.template = "cbi/simpleform"
647         self.dorender = true
648         self.pageaction = false
649         self.readinput = true
650 end
651
652 SimpleForm.formvalue = Map.formvalue
653 SimpleForm.formvaluetable = Map.formvaluetable
654
655 function SimpleForm.parse(self, readinput, ...)
656         self.readinput = (readinput ~= false)
657
658         if self:formvalue("cbi.skip") then
659                 return FORM_SKIP
660         end
661
662         if self:submitstate() then
663                 Node.parse(self, 1, ...)
664         end
665
666         local valid = true
667         for k, j in ipairs(self.children) do
668                 for i, v in ipairs(j.children) do
669                         valid = valid
670                          and (not v.tag_missing or not v.tag_missing[1])
671                          and (not v.tag_invalid or not v.tag_invalid[1])
672                          and (not v.error)
673                 end
674         end
675
676         local state =
677                 not self:submitstate() and FORM_NODATA
678                 or valid and FORM_VALID
679                 or FORM_INVALID
680
681         self.dorender = not self.handle
682         if self.handle then
683                 local nrender, nstate = self:handle(state, self.data)
684                 self.dorender = self.dorender or (nrender ~= false)
685                 state = nstate or state
686         end
687         return state
688 end
689
690 function SimpleForm.render(self, ...)
691         if self.dorender then
692                 Node.render(self, ...)
693         end
694 end
695
696 function SimpleForm.submitstate(self)
697         return self:formvalue("cbi.submit")
698 end
699
700 function SimpleForm.section(self, class, ...)
701         if instanceof(class, AbstractSection) then
702                 local obj  = class(self, ...)
703                 self:append(obj)
704                 return obj
705         else
706                 error("class must be a descendent of AbstractSection")
707         end
708 end
709
710 -- Creates a child field
711 function SimpleForm.field(self, class, ...)
712         local section
713         for k, v in ipairs(self.children) do
714                 if instanceof(v, SimpleSection) then
715                         section = v
716                         break
717                 end
718         end
719         if not section then
720                 section = self:section(SimpleSection)
721         end
722
723         if instanceof(class, AbstractValue) then
724                 local obj  = class(self, section, ...)
725                 obj.track_missing = true
726                 section:append(obj)
727                 return obj
728         else
729                 error("class must be a descendent of AbstractValue")
730         end
731 end
732
733 function SimpleForm.set(self, section, option, value)
734         self.data[option] = value
735 end
736
737
738 function SimpleForm.del(self, section, option)
739         self.data[option] = nil
740 end
741
742
743 function SimpleForm.get(self, section, option)
744         return self.data[option]
745 end
746
747
748 function SimpleForm.get_scheme()
749         return nil
750 end
751
752
753 Form = class(SimpleForm)
754
755 function Form.__init__(self, ...)
756         SimpleForm.__init__(self, ...)
757         self.embedded = true
758 end
759
760
761 --[[
762 AbstractSection
763 ]]--
764 AbstractSection = class(Node)
765
766 function AbstractSection.__init__(self, map, sectiontype, ...)
767         Node.__init__(self, ...)
768         self.sectiontype = sectiontype
769         self.map = map
770         self.config = map.config
771         self.optionals = {}
772         self.defaults = {}
773         self.fields = {}
774         self.tag_error = {}
775         self.tag_invalid = {}
776         self.tag_deperror = {}
777         self.changed = false
778
779         self.optional = true
780         self.addremove = false
781         self.dynamic = false
782 end
783
784 -- Define a tab for the section
785 function AbstractSection.tab(self, tab, title, desc)
786         self.tabs      = self.tabs      or { }
787         self.tab_names = self.tab_names or { }
788
789         self.tab_names[#self.tab_names+1] = tab
790         self.tabs[tab] = {
791                 title       = title,
792                 description = desc,
793                 childs      = { }
794         }
795 end
796
797 -- Appends a new option
798 function AbstractSection.option(self, class, option, ...)
799         -- Autodetect from UVL
800         if class == true and self.map:get_scheme(self.sectiontype, option) then
801                 local vs = self.map:get_scheme(self.sectiontype, option)
802                 if vs.type == "boolean" then
803                         class = Flag
804                 elseif vs.type == "list" then
805                         class = DynamicList
806                 elseif vs.type == "enum" or vs.type == "reference" then
807                         class = ListValue
808                 else
809                         class = Value
810                 end
811         end
812
813         if instanceof(class, AbstractValue) then
814                 local obj  = class(self.map, self, option, ...)
815
816                 Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...)
817
818                 self:append(obj)
819                 self.fields[option] = obj
820                 return obj
821         elseif class == true then
822                 error("No valid class was given and autodetection failed.")
823         else
824                 error("class must be a descendant of AbstractValue")
825         end
826 end
827
828 -- Appends a new tabbed option
829 function AbstractSection.taboption(self, tab, ...)
830
831         assert(tab and self.tabs and self.tabs[tab],
832                 "Cannot assign option to not existing tab %q" % tostring(tab))
833
834         local l = self.tabs[tab].childs
835         local o = AbstractSection.option(self, ...)
836
837         if o then l[#l+1] = o end
838
839         return o
840 end
841
842 -- Render a single tab
843 function AbstractSection.render_tab(self, tab, ...)
844
845         assert(tab and self.tabs and self.tabs[tab],
846                 "Cannot render not existing tab %q" % tostring(tab))
847
848         for _, node in ipairs(self.tabs[tab].childs) do
849                 node:render(...)
850         end
851 end
852
853 -- Parse optional options
854 function AbstractSection.parse_optionals(self, section)
855         if not self.optional then
856                 return
857         end
858
859         self.optionals[section] = {}
860
861         local field = self.map:formvalue("cbi.opt."..self.config.."."..section)
862         for k,v in ipairs(self.children) do
863                 if v.optional and not v:cfgvalue(section) then
864                         if field == v.option then
865                                 field = nil
866                                 self.map.proceed = true
867                         else
868                                 table.insert(self.optionals[section], v)
869                         end
870                 end
871         end
872
873         if field and #field > 0 and self.dynamic then
874                 self:add_dynamic(field)
875         end
876 end
877
878 -- Add a dynamic option
879 function AbstractSection.add_dynamic(self, field, optional)
880         local o = self:option(Value, field, field)
881         o.optional = optional
882 end
883
884 -- Parse all dynamic options
885 function AbstractSection.parse_dynamic(self, section)
886         if not self.dynamic then
887                 return
888         end
889
890         local arr  = luci.util.clone(self:cfgvalue(section))
891         local form = self.map:formvaluetable("cbid."..self.config.."."..section)
892         for k, v in pairs(form) do
893                 arr[k] = v
894         end
895
896         for key,val in pairs(arr) do
897                 local create = true
898
899                 for i,c in ipairs(self.children) do
900                         if c.option == key then
901                                 create = false
902                         end
903                 end
904
905                 if create and key:sub(1, 1) ~= "." then
906                         self.map.proceed = true
907                         self:add_dynamic(key, true)
908                 end
909         end
910 end
911
912 -- Returns the section's UCI table
913 function AbstractSection.cfgvalue(self, section)
914         return self.map:get(section)
915 end
916
917 -- Push events
918 function AbstractSection.push_events(self)
919         --luci.util.append(self.map.events, self.events)
920         self.map.changed = true
921 end
922
923 -- Removes the section
924 function AbstractSection.remove(self, section)
925         self.map.proceed = true
926         return self.map:del(section)
927 end
928
929 -- Creates the section
930 function AbstractSection.create(self, section)
931         local stat
932
933         if section then
934                 stat = section:match("^[%w_]+$") and self.map:set(section, nil, self.sectiontype)
935         else
936                 section = self.map:add(self.sectiontype)
937                 stat = section
938         end
939
940         if stat then
941                 for k,v in pairs(self.children) do
942                         if v.default then
943                                 self.map:set(section, v.option, v.default)
944                         end
945                 end
946
947                 for k,v in pairs(self.defaults) do
948                         self.map:set(section, k, v)
949                 end
950         end
951
952         self.map.proceed = true
953
954         return stat
955 end
956
957
958 SimpleSection = class(AbstractSection)
959
960 function SimpleSection.__init__(self, form, ...)
961         AbstractSection.__init__(self, form, nil, ...)
962         self.template = "cbi/nullsection"
963 end
964
965
966 Table = class(AbstractSection)
967
968 function Table.__init__(self, form, data, ...)
969         local datasource = {}
970         local tself = self
971         datasource.config = "table"
972         self.data = data or {}
973
974         datasource.formvalue = Map.formvalue
975         datasource.formvaluetable = Map.formvaluetable
976         datasource.readinput = true
977
978         function datasource.get(self, section, option)
979                 return tself.data[section] and tself.data[section][option]
980         end
981
982         function datasource.submitstate(self)
983                 return Map.formvalue(self, "cbi.submit")
984         end
985
986         function datasource.del(...)
987                 return true
988         end
989
990         function datasource.get_scheme()
991                 return nil
992         end
993
994         AbstractSection.__init__(self, datasource, "table", ...)
995         self.template = "cbi/tblsection"
996         self.rowcolors = true
997         self.anonymous = true
998 end
999
1000 function Table.parse(self, readinput)
1001         self.map.readinput = (readinput ~= false)
1002         for i, k in ipairs(self:cfgsections()) do
1003                 if self.map:submitstate() then
1004                         Node.parse(self, k)
1005                 end
1006         end
1007 end
1008
1009 function Table.cfgsections(self)
1010         local sections = {}
1011
1012         for i, v in luci.util.kspairs(self.data) do
1013                 table.insert(sections, i)
1014         end
1015
1016         return sections
1017 end
1018
1019 function Table.update(self, data)
1020         self.data = data
1021 end
1022
1023
1024
1025 --[[
1026 NamedSection - A fixed configuration section defined by its name
1027 ]]--
1028 NamedSection = class(AbstractSection)
1029
1030 function NamedSection.__init__(self, map, section, stype, ...)
1031         AbstractSection.__init__(self, map, stype, ...)
1032         Node._i18n(self, map.config, section, nil, ...)
1033
1034         -- Defaults
1035         self.addremove = false
1036
1037         -- Use defaults from UVL
1038         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
1039                 local vs = self.map:get_scheme(self.sectiontype)
1040                 self.addremove = not vs.unique and not vs.required
1041                 self.dynamic   = vs.dynamic
1042                 self.title       = self.title or vs.title
1043                 self.description = self.description or vs.descr
1044         end
1045
1046         self.template = "cbi/nsection"
1047         self.section = section
1048 end
1049
1050 function NamedSection.parse(self, novld)
1051         local s = self.section
1052         local active = self:cfgvalue(s)
1053
1054         if self.addremove then
1055                 local path = self.config.."."..s
1056                 if active then -- Remove the section
1057                         if self.map:formvalue("cbi.rns."..path) and self:remove(s) then
1058                                 self:push_events()
1059                                 return
1060                         end
1061                 else           -- Create and apply default values
1062                         if self.map:formvalue("cbi.cns."..path) then
1063                                 self:create(s)
1064                                 return
1065                         end
1066                 end
1067         end
1068
1069         if active then
1070                 AbstractSection.parse_dynamic(self, s)
1071                 if self.map:submitstate() then
1072                         Node.parse(self, s)
1073
1074                         if not novld and not self.override_scheme and self.map.scheme then
1075                                 _uvl_validate_section(self, s)
1076                         end
1077                 end
1078                 AbstractSection.parse_optionals(self, s)
1079
1080                 if self.changed then
1081                         self:push_events()
1082                 end
1083         end
1084 end
1085
1086
1087 --[[
1088 TypedSection - A (set of) configuration section(s) defined by the type
1089         addremove:      Defines whether the user can add/remove sections of this type
1090         anonymous:  Allow creating anonymous sections
1091         validate:       a validation function returning nil if the section is invalid
1092 ]]--
1093 TypedSection = class(AbstractSection)
1094
1095 function TypedSection.__init__(self, map, type, ...)
1096         AbstractSection.__init__(self, map, type, ...)
1097         Node._i18n(self, map.config, type, nil, ...)
1098
1099         self.template  = "cbi/tsection"
1100         self.deps = {}
1101         self.anonymous = false
1102
1103         -- Use defaults from UVL
1104         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
1105                 local vs = self.map:get_scheme(self.sectiontype)
1106                 self.addremove = not vs.unique and not vs.required
1107                 self.dynamic   = vs.dynamic
1108                 self.anonymous = not vs.named
1109                 self.title       = self.title or vs.title
1110                 self.description = self.description or vs.descr
1111         end
1112 end
1113
1114 -- Return all matching UCI sections for this TypedSection
1115 function TypedSection.cfgsections(self)
1116         local sections = {}
1117         self.map.uci:foreach(self.map.config, self.sectiontype,
1118                 function (section)
1119                         if self:checkscope(section[".name"]) then
1120                                 table.insert(sections, section[".name"])
1121                         end
1122                 end)
1123
1124         return sections
1125 end
1126
1127 -- Limits scope to sections that have certain option => value pairs
1128 function TypedSection.depends(self, option, value)
1129         table.insert(self.deps, {option=option, value=value})
1130 end
1131
1132 function TypedSection.parse(self, novld)
1133         if self.addremove then
1134                 -- Remove
1135                 local crval = REMOVE_PREFIX .. self.config
1136                 local name = self.map:formvaluetable(crval)
1137                 for k,v in pairs(name) do
1138                         if k:sub(-2) == ".x" then
1139                                 k = k:sub(1, #k - 2)
1140                         end
1141                         if self:cfgvalue(k) and self:checkscope(k) then
1142                                 self:remove(k)
1143                         end
1144                 end
1145         end
1146
1147         local co
1148         for i, k in ipairs(self:cfgsections()) do
1149                 AbstractSection.parse_dynamic(self, k)
1150                 if self.map:submitstate() then
1151                         Node.parse(self, k, novld)
1152
1153                         if not novld and not self.override_scheme and self.map.scheme then
1154                                 _uvl_validate_section(self, k)
1155                         end
1156                 end
1157                 AbstractSection.parse_optionals(self, k)
1158         end
1159
1160         if self.addremove then
1161                 -- Create
1162                 local created
1163                 local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
1164                 local name  = self.map:formvalue(crval)
1165                 if self.anonymous then
1166                         if name then
1167                                 created = self:create()
1168                         end
1169                 else
1170                         if name then
1171                                 -- Ignore if it already exists
1172                                 if self:cfgvalue(name) then
1173                                         name = nil;
1174                                 end
1175
1176                                 name = self:checkscope(name)
1177
1178                                 if not name then
1179                                         self.err_invalid = true
1180                                 end
1181
1182                                 if name and #name > 0 then
1183                                         created = self:create(name) and name
1184                                         if not created then
1185                                                 self.invalid_cts = true
1186                                         end
1187                                 end
1188                         end
1189                 end
1190
1191                 if created then
1192                         AbstractSection.parse_optionals(self, created)
1193                 end
1194         end
1195
1196         if created or self.changed then
1197                 self:push_events()
1198         end
1199 end
1200
1201 -- Verifies scope of sections
1202 function TypedSection.checkscope(self, section)
1203         -- Check if we are not excluded
1204         if self.filter and not self:filter(section) then
1205                 return nil
1206         end
1207
1208         -- Check if at least one dependency is met
1209         if #self.deps > 0 and self:cfgvalue(section) then
1210                 local stat = false
1211
1212                 for k, v in ipairs(self.deps) do
1213                         if self:cfgvalue(section)[v.option] == v.value then
1214                                 stat = true
1215                         end
1216                 end
1217
1218                 if not stat then
1219                         return nil
1220                 end
1221         end
1222
1223         return self:validate(section)
1224 end
1225
1226
1227 -- Dummy validate function
1228 function TypedSection.validate(self, section)
1229         return section
1230 end
1231
1232
1233 --[[
1234 AbstractValue - An abstract Value Type
1235         null:           Value can be empty
1236         valid:          A function returning the value if it is valid otherwise nil
1237         depends:        A table of option => value pairs of which one must be true
1238         default:        The default value
1239         size:           The size of the input fields
1240         rmempty:        Unset value if empty
1241         optional:       This value is optional (see AbstractSection.optionals)
1242 ]]--
1243 AbstractValue = class(Node)
1244
1245 function AbstractValue.__init__(self, map, section, option, ...)
1246         Node.__init__(self, ...)
1247         self.section = section
1248         self.option  = option
1249         self.map     = map
1250         self.config  = map.config
1251         self.tag_invalid = {}
1252         self.tag_missing = {}
1253         self.tag_reqerror = {}
1254         self.tag_error = {}
1255         self.deps = {}
1256         --self.cast = "string"
1257
1258         self.track_missing = false
1259         self.rmempty   = true
1260         self.default   = nil
1261         self.size      = nil
1262         self.optional  = false
1263 end
1264
1265 function AbstractValue.prepare(self)
1266         -- Use defaults from UVL
1267         if not self.override_scheme
1268          and self.map:get_scheme(self.section.sectiontype, self.option) then
1269                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1270                 if self.cast == nil then
1271                         self.cast = (vs.type == "list") and "list" or "string"
1272                 end
1273                 self.title       = self.title or vs.title
1274                 self.description = self.description or vs.descr
1275                 if self.default == nil then
1276                         self.default = vs.default
1277                 end
1278
1279                 if vs.depends and not self.override_dependencies then
1280                         for i, deps in ipairs(vs.depends) do
1281                                 deps = _uvl_strip_remote_dependencies(deps)
1282                                 if next(deps) then
1283                                         self:depends(deps)
1284                                 end
1285                         end
1286                 end
1287         end
1288
1289         self.cast = self.cast or "string"
1290 end
1291
1292 -- Add a dependencie to another section field
1293 function AbstractValue.depends(self, field, value)
1294         local deps
1295         if type(field) == "string" then
1296                 deps = {}
1297                 deps[field] = value
1298         else
1299                 deps = field
1300         end
1301
1302         table.insert(self.deps, {deps=deps, add=""})
1303 end
1304
1305 -- Generates the unique CBID
1306 function AbstractValue.cbid(self, section)
1307         return "cbid."..self.map.config.."."..section.."."..self.option
1308 end
1309
1310 -- Return whether this object should be created
1311 function AbstractValue.formcreated(self, section)
1312         local key = "cbi.opt."..self.config.."."..section
1313         return (self.map:formvalue(key) == self.option)
1314 end
1315
1316 -- Returns the formvalue for this object
1317 function AbstractValue.formvalue(self, section)
1318         return self.map:formvalue(self:cbid(section))
1319 end
1320
1321 function AbstractValue.additional(self, value)
1322         self.optional = value
1323 end
1324
1325 function AbstractValue.mandatory(self, value)
1326         self.rmempty = not value
1327 end
1328
1329 function AbstractValue.parse(self, section, novld)
1330         local fvalue = self:formvalue(section)
1331         local cvalue = self:cfgvalue(section)
1332
1333         -- If favlue and cvalue are both tables and have the same content
1334         -- make them identical
1335         if type(fvalue) == "table" and type(cvalue) == "table" then
1336                 local equal = #fvalue == #cvalue
1337                 if equal then
1338                         for i=1, #fvalue do
1339                                 if cvalue[i] ~= fvalue[i] then
1340                                         equal = false
1341                                 end
1342                         end
1343                 end
1344                 if equal then
1345                         fvalue = cvalue
1346                 end
1347         end
1348
1349         if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
1350                 fvalue = self:transform(self:validate(fvalue, section))
1351                 if not fvalue and not novld then
1352                         if self.error then
1353                                 self.error[section] = "invalid"
1354                         else
1355                                 self.error = { [section] = "invalid" }
1356                         end
1357                         if self.section.error then
1358                                 table.insert(self.section.error[section], "invalid")
1359                         else
1360                                 self.section.error = {[section] = {"invalid"}}
1361                         end 
1362                         self.map.save = false
1363                 end
1364                 if fvalue and not (fvalue == cvalue) then
1365                         if self:write(section, fvalue) then
1366                                 -- Push events
1367                                 self.section.changed = true
1368                                 --luci.util.append(self.map.events, self.events)
1369                         end
1370                 end
1371         else                                                    -- Unset the UCI or error
1372                 if self.rmempty or self.optional then
1373                         if self:remove(section) then
1374                                 -- Push events
1375                                 self.section.changed = true
1376                                 --luci.util.append(self.map.events, self.events)
1377                         end
1378                 elseif cvalue ~= fvalue and not novld then
1379                         self:write(section, fvalue or "")
1380                         if self.error then
1381                                 self.error[section] = "missing"
1382                         else
1383                                 self.error = { [section] = "missing" }
1384                         end
1385                         self.map.save = false
1386                 end
1387         end
1388 end
1389
1390 -- Render if this value exists or if it is mandatory
1391 function AbstractValue.render(self, s, scope)
1392         if not self.optional or self:cfgvalue(s) or self:formcreated(s) then
1393                 scope = scope or {}
1394                 scope.section   = s
1395                 scope.cbid      = self:cbid(s)
1396                 scope.striptags = luci.util.striptags
1397                 scope.pcdata    = luci.util.pcdata
1398
1399                 scope.ifattr = function(cond,key,val)
1400                         if cond then
1401                                 return string.format(
1402                                         ' %s="%s"', tostring(key),
1403                                         luci.util.pcdata(tostring( val
1404                                          or scope[key]
1405                                          or (type(self[key]) ~= "function" and self[key])
1406                                          or "" ))
1407                                 )
1408                         else
1409                                 return ''
1410                         end
1411                 end
1412
1413                 scope.attr = function(...)
1414                         return scope.ifattr( true, ... )
1415                 end
1416
1417                 Node.render(self, scope)
1418         end
1419 end
1420
1421 -- Return the UCI value of this object
1422 function AbstractValue.cfgvalue(self, section)
1423         local value = self.map:get(section, self.option)
1424         if not value then
1425                 return nil
1426         elseif not self.cast or self.cast == type(value) then
1427                 return value
1428         elseif self.cast == "string" then
1429                 if type(value) == "table" then
1430                         return value[1]
1431                 end
1432         elseif self.cast == "table" then
1433                 return luci.util.split(value, "%s+", nil, true)
1434         end
1435 end
1436
1437 -- Validate the form value
1438 function AbstractValue.validate(self, value)
1439         return value
1440 end
1441
1442 AbstractValue.transform = AbstractValue.validate
1443
1444
1445 -- Write to UCI
1446 function AbstractValue.write(self, section, value)
1447         return self.map:set(section, self.option, value)
1448 end
1449
1450 -- Remove from UCI
1451 function AbstractValue.remove(self, section)
1452         return self.map:del(section, self.option)
1453 end
1454
1455
1456
1457
1458 --[[
1459 Value - A one-line value
1460         maxlength:      The maximum length
1461 ]]--
1462 Value = class(AbstractValue)
1463
1464 function Value.__init__(self, ...)
1465         AbstractValue.__init__(self, ...)
1466         self.template  = "cbi/value"
1467         self.keylist = {}
1468         self.vallist = {}
1469 end
1470
1471 function Value.value(self, key, val)
1472         val = val or key
1473         table.insert(self.keylist, tostring(key))
1474         table.insert(self.vallist, tostring(val))
1475 end
1476
1477
1478 -- DummyValue - This does nothing except being there
1479 DummyValue = class(AbstractValue)
1480
1481 function DummyValue.__init__(self, ...)
1482         AbstractValue.__init__(self, ...)
1483         self.template = "cbi/dvalue"
1484         self.value = nil
1485 end
1486
1487 function DummyValue.cfgvalue(self, section)
1488         local value
1489         if self.value then
1490                 if type(self.value) == "function" then
1491                         value = self:value(section)
1492                 else
1493                         value = self.value
1494                 end
1495         else
1496                 value = AbstractValue.cfgvalue(self, section)
1497         end
1498         return value
1499 end
1500
1501 function DummyValue.parse(self)
1502
1503 end
1504
1505
1506 --[[
1507 Flag - A flag being enabled or disabled
1508 ]]--
1509 Flag = class(AbstractValue)
1510
1511 function Flag.__init__(self, ...)
1512         AbstractValue.__init__(self, ...)
1513         self.template  = "cbi/fvalue"
1514
1515         self.enabled = "1"
1516         self.disabled = "0"
1517 end
1518
1519 -- A flag can only have two states: set or unset
1520 function Flag.parse(self, section)
1521         local fvalue = self:formvalue(section)
1522
1523         if fvalue then
1524                 fvalue = self.enabled
1525         else
1526                 fvalue = self.disabled
1527         end
1528
1529         if fvalue == self.enabled or (not self.optional and not self.rmempty) then
1530                 if not(fvalue == self:cfgvalue(section)) then
1531                         self:write(section, fvalue)
1532                 end
1533         else
1534                 self:remove(section)
1535         end
1536 end
1537
1538
1539
1540 --[[
1541 ListValue - A one-line value predefined in a list
1542         widget: The widget that will be used (select, radio)
1543 ]]--
1544 ListValue = class(AbstractValue)
1545
1546 function ListValue.__init__(self, ...)
1547         AbstractValue.__init__(self, ...)
1548         self.template  = "cbi/lvalue"
1549
1550         self.keylist = {}
1551         self.vallist = {}
1552         self.size   = 1
1553         self.widget = "select"
1554 end
1555
1556 function ListValue.prepare(self, ...)
1557         AbstractValue.prepare(self, ...)
1558         if not self.override_scheme
1559          and self.map:get_scheme(self.section.sectiontype, self.option) then
1560                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1561                 if self.value and vs.valuelist and not self.override_values then
1562                         for k, v in ipairs(vs.valuelist) do
1563                                 local deps = {}
1564                                 if not self.override_dependencies
1565                                  and vs.enum_depends and vs.enum_depends[v.value] then
1566                                         for i, dep in ipairs(vs.enum_depends[v.value]) do
1567                                                 table.insert(deps, _uvl_strip_remote_dependencies(dep))
1568                                         end
1569                                 end
1570                                 self:value(v.value, v.title or v.value, unpack(deps))
1571                         end
1572                 end
1573         end
1574 end
1575
1576 function ListValue.value(self, key, val, ...)
1577         if luci.util.contains(self.keylist, key) then
1578                 return
1579         end
1580
1581         val = val or key
1582         table.insert(self.keylist, tostring(key))
1583         table.insert(self.vallist, tostring(val))
1584
1585         for i, deps in ipairs({...}) do
1586                 table.insert(self.deps, {add = "-"..key, deps=deps})
1587         end
1588 end
1589
1590 function ListValue.validate(self, val)
1591         if luci.util.contains(self.keylist, val) then
1592                 return val
1593         else
1594                 return nil
1595         end
1596 end
1597
1598
1599
1600 --[[
1601 MultiValue - Multiple delimited values
1602         widget: The widget that will be used (select, checkbox)
1603         delimiter: The delimiter that will separate the values (default: " ")
1604 ]]--
1605 MultiValue = class(AbstractValue)
1606
1607 function MultiValue.__init__(self, ...)
1608         AbstractValue.__init__(self, ...)
1609         self.template = "cbi/mvalue"
1610
1611         self.keylist = {}
1612         self.vallist = {}
1613
1614         self.widget = "checkbox"
1615         self.delimiter = " "
1616 end
1617
1618 function MultiValue.render(self, ...)
1619         if self.widget == "select" and not self.size then
1620                 self.size = #self.vallist
1621         end
1622
1623         AbstractValue.render(self, ...)
1624 end
1625
1626 function MultiValue.value(self, key, val)
1627         if luci.util.contains(self.keylist, key) then
1628                 return
1629         end
1630
1631         val = val or key
1632         table.insert(self.keylist, tostring(key))
1633         table.insert(self.vallist, tostring(val))
1634 end
1635
1636 function MultiValue.valuelist(self, section)
1637         local val = self:cfgvalue(section)
1638
1639         if not(type(val) == "string") then
1640                 return {}
1641         end
1642
1643         return luci.util.split(val, self.delimiter)
1644 end
1645
1646 function MultiValue.validate(self, val)
1647         val = (type(val) == "table") and val or {val}
1648
1649         local result
1650
1651         for i, value in ipairs(val) do
1652                 if luci.util.contains(self.keylist, value) then
1653                         result = result and (result .. self.delimiter .. value) or value
1654                 end
1655         end
1656
1657         return result
1658 end
1659
1660
1661 StaticList = class(MultiValue)
1662
1663 function StaticList.__init__(self, ...)
1664         MultiValue.__init__(self, ...)
1665         self.cast = "table"
1666         self.valuelist = self.cfgvalue
1667
1668         if not self.override_scheme
1669          and self.map:get_scheme(self.section.sectiontype, self.option) then
1670                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1671                 if self.value and vs.values and not self.override_values then
1672                         for k, v in pairs(vs.values) do
1673                                 self:value(k, v)
1674                         end
1675                 end
1676         end
1677 end
1678
1679 function StaticList.validate(self, value)
1680         value = (type(value) == "table") and value or {value}
1681
1682         local valid = {}
1683         for i, v in ipairs(value) do
1684                 if luci.util.contains(self.keylist, v) then
1685                         table.insert(valid, v)
1686                 end
1687         end
1688         return valid
1689 end
1690
1691
1692 DynamicList = class(AbstractValue)
1693
1694 function DynamicList.__init__(self, ...)
1695         AbstractValue.__init__(self, ...)
1696         self.template  = "cbi/dynlist"
1697         self.cast = "table"
1698         self.keylist = {}
1699         self.vallist = {}
1700 end
1701
1702 function DynamicList.value(self, key, val)
1703         val = val or key
1704         table.insert(self.keylist, tostring(key))
1705         table.insert(self.vallist, tostring(val))
1706 end
1707
1708 function DynamicList.write(self, ...)
1709         self.map.proceed = true
1710         return AbstractValue.write(self, ...)
1711 end
1712
1713 function DynamicList.formvalue(self, section)
1714         local value = AbstractValue.formvalue(self, section)
1715         value = (type(value) == "table") and value or {value}
1716
1717         local valid = {}
1718         for i, v in ipairs(value) do
1719                 if v and #v > 0
1720                  and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i)
1721                  and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
1722                         table.insert(valid, v)
1723                 end
1724         end
1725
1726         return valid
1727 end
1728
1729
1730 --[[
1731 TextValue - A multi-line value
1732         rows:   Rows
1733 ]]--
1734 TextValue = class(AbstractValue)
1735
1736 function TextValue.__init__(self, ...)
1737         AbstractValue.__init__(self, ...)
1738         self.template  = "cbi/tvalue"
1739 end
1740
1741 --[[
1742 Button
1743 ]]--
1744 Button = class(AbstractValue)
1745
1746 function Button.__init__(self, ...)
1747         AbstractValue.__init__(self, ...)
1748         self.template  = "cbi/button"
1749         self.inputstyle = nil
1750         self.rmempty = true
1751 end
1752
1753
1754 FileUpload = class(AbstractValue)
1755
1756 function FileUpload.__init__(self, ...)
1757         AbstractValue.__init__(self, ...)
1758         self.template = "cbi/upload"
1759         if not self.map.upload_fields then
1760                 self.map.upload_fields = { self }
1761         else
1762                 self.map.upload_fields[#self.map.upload_fields+1] = self
1763         end
1764 end
1765
1766 function FileUpload.formcreated(self, section)
1767         return AbstractValue.formcreated(self, section) or
1768                 self.map:formvalue("cbi.rlf."..section.."."..self.option) or
1769                 self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1770 end
1771
1772 function FileUpload.cfgvalue(self, section)
1773         local val = AbstractValue.cfgvalue(self, section)
1774         if val and fs.access(val) then
1775                 return val
1776         end
1777         return nil
1778 end
1779
1780 function FileUpload.formvalue(self, section)
1781         local val = AbstractValue.formvalue(self, section)
1782         if val then
1783                 if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
1784                    not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1785                 then
1786                         return val
1787                 end
1788                 fs.unlink(val)
1789                 self.value = nil
1790         end
1791         return nil
1792 end
1793
1794 function FileUpload.remove(self, section)
1795         local val = AbstractValue.formvalue(self, section)
1796         if val and fs.access(val) then fs.unlink(val) end
1797         return AbstractValue.remove(self, section)
1798 end
1799
1800
1801 FileBrowser = class(AbstractValue)
1802
1803 function FileBrowser.__init__(self, ...)
1804         AbstractValue.__init__(self, ...)
1805         self.template = "cbi/browser"
1806 end