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