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