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