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