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