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