Merge pull request #389 from hnyman/timezone2015d
[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                 if fvalue ~= self.default or (not self.optional and not self.rmempty) then
1537                         self:write(section, fvalue)
1538                 else
1539                         self:remove(section)
1540                 end
1541         else
1542                 self:remove(section)
1543         end
1544 end
1545
1546 function Flag.cfgvalue(self, section)
1547         return AbstractValue.cfgvalue(self, section) or self.default
1548 end
1549
1550
1551 --[[
1552 ListValue - A one-line value predefined in a list
1553         widget: The widget that will be used (select, radio)
1554 ]]--
1555 ListValue = class(AbstractValue)
1556
1557 function ListValue.__init__(self, ...)
1558         AbstractValue.__init__(self, ...)
1559         self.template  = "cbi/lvalue"
1560
1561         self.keylist = {}
1562         self.vallist = {}
1563         self.size   = 1
1564         self.widget = "select"
1565 end
1566
1567 function ListValue.reset_values(self)
1568         self.keylist = {}
1569         self.vallist = {}
1570 end
1571
1572 function ListValue.value(self, key, val, ...)
1573         if luci.util.contains(self.keylist, key) then
1574                 return
1575         end
1576
1577         val = val or key
1578         table.insert(self.keylist, tostring(key))
1579         table.insert(self.vallist, tostring(val))
1580
1581         for i, deps in ipairs({...}) do
1582                 self.subdeps[#self.subdeps + 1] = {add = "-"..key, deps=deps}
1583         end
1584 end
1585
1586 function ListValue.validate(self, val)
1587         if luci.util.contains(self.keylist, val) then
1588                 return val
1589         else
1590                 return nil
1591         end
1592 end
1593
1594
1595
1596 --[[
1597 MultiValue - Multiple delimited values
1598         widget: The widget that will be used (select, checkbox)
1599         delimiter: The delimiter that will separate the values (default: " ")
1600 ]]--
1601 MultiValue = class(AbstractValue)
1602
1603 function MultiValue.__init__(self, ...)
1604         AbstractValue.__init__(self, ...)
1605         self.template = "cbi/mvalue"
1606
1607         self.keylist = {}
1608         self.vallist = {}
1609
1610         self.widget = "checkbox"
1611         self.delimiter = " "
1612 end
1613
1614 function MultiValue.render(self, ...)
1615         if self.widget == "select" and not self.size then
1616                 self.size = #self.vallist
1617         end
1618
1619         AbstractValue.render(self, ...)
1620 end
1621
1622 function MultiValue.reset_values(self)
1623         self.keylist = {}
1624         self.vallist = {}
1625 end
1626
1627 function MultiValue.value(self, key, val)
1628         if luci.util.contains(self.keylist, key) then
1629                 return
1630         end
1631
1632         val = val or key
1633         table.insert(self.keylist, tostring(key))
1634         table.insert(self.vallist, tostring(val))
1635 end
1636
1637 function MultiValue.valuelist(self, section)
1638         local val = self:cfgvalue(section)
1639
1640         if not(type(val) == "string") then
1641                 return {}
1642         end
1643
1644         return luci.util.split(val, self.delimiter)
1645 end
1646
1647 function MultiValue.validate(self, val)
1648         val = (type(val) == "table") and val or {val}
1649
1650         local result
1651
1652         for i, value in ipairs(val) do
1653                 if luci.util.contains(self.keylist, value) then
1654                         result = result and (result .. self.delimiter .. value) or value
1655                 end
1656         end
1657
1658         return result
1659 end
1660
1661
1662 StaticList = class(MultiValue)
1663
1664 function StaticList.__init__(self, ...)
1665         MultiValue.__init__(self, ...)
1666         self.cast = "table"
1667         self.valuelist = self.cfgvalue
1668
1669         if not self.override_scheme
1670          and self.map:get_scheme(self.section.sectiontype, self.option) then
1671                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1672                 if self.value and vs.values and not self.override_values then
1673                         for k, v in pairs(vs.values) do
1674                                 self:value(k, v)
1675                         end
1676                 end
1677         end
1678 end
1679
1680 function StaticList.validate(self, value)
1681         value = (type(value) == "table") and value or {value}
1682
1683         local valid = {}
1684         for i, v in ipairs(value) do
1685                 if luci.util.contains(self.keylist, v) then
1686                         table.insert(valid, v)
1687                 end
1688         end
1689         return valid
1690 end
1691
1692
1693 DynamicList = class(AbstractValue)
1694
1695 function DynamicList.__init__(self, ...)
1696         AbstractValue.__init__(self, ...)
1697         self.template  = "cbi/dynlist"
1698         self.cast = "table"
1699         self.keylist = {}
1700         self.vallist = {}
1701 end
1702
1703 function DynamicList.reset_values(self)
1704         self.keylist = {}
1705         self.vallist = {}
1706 end
1707
1708 function DynamicList.value(self, key, val)
1709         val = val or key
1710         table.insert(self.keylist, tostring(key))
1711         table.insert(self.vallist, tostring(val))
1712 end
1713
1714 function DynamicList.write(self, section, value)
1715         local t = { }
1716
1717         if type(value) == "table" then
1718                 local x
1719                 for _, x in ipairs(value) do
1720                         if x and #x > 0 then
1721                                 t[#t+1] = x
1722                         end
1723                 end
1724         else
1725                 t = { value }
1726         end
1727
1728         if self.cast == "string" then
1729                 value = table.concat(t, " ")
1730         else
1731                 value = t
1732         end
1733
1734         return AbstractValue.write(self, section, value)
1735 end
1736
1737 function DynamicList.cfgvalue(self, section)
1738         local value = AbstractValue.cfgvalue(self, section)
1739
1740         if type(value) == "string" then
1741                 local x
1742                 local t = { }
1743                 for x in value:gmatch("%S+") do
1744                         if #x > 0 then
1745                                 t[#t+1] = x
1746                         end
1747                 end
1748                 value = t
1749         end
1750
1751         return value
1752 end
1753
1754 function DynamicList.formvalue(self, section)
1755         local value = AbstractValue.formvalue(self, section)
1756
1757         if type(value) == "string" then
1758                 if self.cast == "string" then
1759                         local x
1760                         local t = { }
1761                         for x in value:gmatch("%S+") do
1762                                 t[#t+1] = x
1763                         end
1764                         value = t
1765                 else
1766                         value = { value }
1767                 end
1768         end
1769
1770         return value
1771 end
1772
1773
1774 --[[
1775 TextValue - A multi-line value
1776         rows:   Rows
1777 ]]--
1778 TextValue = class(AbstractValue)
1779
1780 function TextValue.__init__(self, ...)
1781         AbstractValue.__init__(self, ...)
1782         self.template  = "cbi/tvalue"
1783 end
1784
1785 --[[
1786 Button
1787 ]]--
1788 Button = class(AbstractValue)
1789
1790 function Button.__init__(self, ...)
1791         AbstractValue.__init__(self, ...)
1792         self.template  = "cbi/button"
1793         self.inputstyle = nil
1794         self.rmempty = true
1795 end
1796
1797
1798 FileUpload = class(AbstractValue)
1799
1800 function FileUpload.__init__(self, ...)
1801         AbstractValue.__init__(self, ...)
1802         self.template = "cbi/upload"
1803         if not self.map.upload_fields then
1804                 self.map.upload_fields = { self }
1805         else
1806                 self.map.upload_fields[#self.map.upload_fields+1] = self
1807         end
1808 end
1809
1810 function FileUpload.formcreated(self, section)
1811         return AbstractValue.formcreated(self, section) or
1812                 self.map:formvalue("cbi.rlf."..section.."."..self.option) or
1813                 self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1814 end
1815
1816 function FileUpload.cfgvalue(self, section)
1817         local val = AbstractValue.cfgvalue(self, section)
1818         if val and fs.access(val) then
1819                 return val
1820         end
1821         return nil
1822 end
1823
1824 function FileUpload.formvalue(self, section)
1825         local val = AbstractValue.formvalue(self, section)
1826         if val then
1827                 if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
1828                    not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1829                 then
1830                         return val
1831                 end
1832                 fs.unlink(val)
1833                 self.value = nil
1834         end
1835         return nil
1836 end
1837
1838 function FileUpload.remove(self, section)
1839         local val = AbstractValue.formvalue(self, section)
1840         if val and fs.access(val) then fs.unlink(val) end
1841         return AbstractValue.remove(self, section)
1842 end
1843
1844
1845 FileBrowser = class(AbstractValue)
1846
1847 function FileBrowser.__init__(self, ...)
1848         AbstractValue.__init__(self, ...)
1849         self.template = "cbi/browser"
1850 end