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