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