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