luci-base: increase max size of network dropdowns
[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                                         self.err_invalid = true
1204                                 else
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                 end
1220
1221                 if created then
1222                         AbstractSection.parse_optionals(self, created)
1223                 end
1224         end
1225
1226         if self.sortable then
1227                 local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype
1228                 local order = self.map:formvalue(stval)
1229                 if order and #order > 0 then
1230                         local sids, sid = { }, nil
1231                         for sid in util.imatch(order) do
1232                                 sids[#sids+1] = sid
1233                         end
1234                         if #sids > 0 then
1235                                 self.map.uci:reorder(self.config, sids)
1236                                 self.changed = true
1237                         end
1238                 end
1239         end
1240
1241         if created or self.changed then
1242                 self:push_events()
1243         end
1244 end
1245
1246 -- Verifies scope of sections
1247 function TypedSection.checkscope(self, section)
1248         -- Check if we are not excluded
1249         if self.filter and not self:filter(section) then
1250                 return nil
1251         end
1252
1253         -- Check if at least one dependency is met
1254         if #self.deps > 0 and self:cfgvalue(section) then
1255                 local stat = false
1256
1257                 for k, v in ipairs(self.deps) do
1258                         if self:cfgvalue(section)[v.option] == v.value then
1259                                 stat = true
1260                         end
1261                 end
1262
1263                 if not stat then
1264                         return nil
1265                 end
1266         end
1267
1268         return self:validate(section)
1269 end
1270
1271
1272 -- Dummy validate function
1273 function TypedSection.validate(self, section)
1274         return section
1275 end
1276
1277
1278 --[[
1279 AbstractValue - An abstract Value Type
1280         null:           Value can be empty
1281         valid:          A function returning the value if it is valid otherwise nil
1282         depends:        A table of option => value pairs of which one must be true
1283         default:        The default value
1284         size:           The size of the input fields
1285         rmempty:        Unset value if empty
1286         optional:       This value is optional (see AbstractSection.optionals)
1287 ]]--
1288 AbstractValue = class(Node)
1289
1290 function AbstractValue.__init__(self, map, section, option, ...)
1291         Node.__init__(self, ...)
1292         self.section = section
1293         self.option  = option
1294         self.map     = map
1295         self.config  = map.config
1296         self.tag_invalid = {}
1297         self.tag_missing = {}
1298         self.tag_reqerror = {}
1299         self.tag_error = {}
1300         self.deps = {}
1301         --self.cast = "string"
1302
1303         self.track_missing = false
1304         self.rmempty   = true
1305         self.default   = nil
1306         self.size      = nil
1307         self.optional  = false
1308 end
1309
1310 function AbstractValue.prepare(self)
1311         self.cast = self.cast or "string"
1312 end
1313
1314 -- Add a dependencie to another section field
1315 function AbstractValue.depends(self, field, value)
1316         local deps
1317         if type(field) == "string" then
1318                 deps = {}
1319                 deps[field] = value
1320         else
1321                 deps = field
1322         end
1323
1324         table.insert(self.deps, deps)
1325 end
1326
1327 -- Serialize dependencies
1328 function AbstractValue.deplist2json(self, section, deplist)
1329         local deps, i, d = { }
1330
1331         if type(self.deps) == "table" then
1332                 for i, d in ipairs(deplist or self.deps) do
1333                         local a, k, v = { }
1334                         for k, v in pairs(d) do
1335                                 if k:find("!", 1, true) then
1336                                         a[k] = v
1337                                 elseif k:find(".", 1, true) then
1338                                         a['cbid.%s' % k] = v
1339                                 else
1340                                         a['cbid.%s.%s.%s' %{ self.config, section, k }] = v
1341                                 end
1342                         end
1343                         deps[#deps+1] = a
1344                 end
1345         end
1346
1347         return util.serialize_json(deps)
1348 end
1349
1350 -- Generates the unique CBID
1351 function AbstractValue.cbid(self, section)
1352         return "cbid."..self.map.config.."."..section.."."..self.option
1353 end
1354
1355 -- Return whether this object should be created
1356 function AbstractValue.formcreated(self, section)
1357         local key = "cbi.opt."..self.config.."."..section
1358         return (self.map:formvalue(key) == self.option)
1359 end
1360
1361 -- Returns the formvalue for this object
1362 function AbstractValue.formvalue(self, section)
1363         return self.map:formvalue(self:cbid(section))
1364 end
1365
1366 function AbstractValue.additional(self, value)
1367         self.optional = value
1368 end
1369
1370 function AbstractValue.mandatory(self, value)
1371         self.rmempty = not value
1372 end
1373
1374 function AbstractValue.add_error(self, section, type, msg)
1375         self.error = self.error or { }
1376         self.error[section] = msg or type
1377
1378         self.section.error = self.section.error or { }
1379         self.section.error[section] = self.section.error[section] or { }
1380         table.insert(self.section.error[section], msg or type)
1381
1382         if type == "invalid" then
1383                 self.tag_invalid[section] = true
1384         elseif type == "missing" then
1385                 self.tag_missing[section] = true
1386         end
1387
1388         self.tag_error[section] = true
1389         self.map.save = false
1390 end
1391
1392 function AbstractValue.parse(self, section, novld)
1393         local fvalue = self:formvalue(section)
1394         local cvalue = self:cfgvalue(section)
1395
1396         -- If favlue and cvalue are both tables and have the same content
1397         -- make them identical
1398         if type(fvalue) == "table" and type(cvalue) == "table" then
1399                 local equal = #fvalue == #cvalue
1400                 if equal then
1401                         for i=1, #fvalue do
1402                                 if cvalue[i] ~= fvalue[i] then
1403                                         equal = false
1404                                 end
1405                         end
1406                 end
1407                 if equal then
1408                         fvalue = cvalue
1409                 end
1410         end
1411
1412         if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
1413                 local val_err
1414                 fvalue, val_err = self:validate(fvalue, section)
1415                 fvalue = self:transform(fvalue)
1416
1417                 if not fvalue and not novld then
1418                         self:add_error(section, "invalid", val_err)
1419                 end
1420
1421                 if self.alias then
1422                         self.section.aliased = self.section.aliased or {}
1423                         self.section.aliased[section] = self.section.aliased[section] or {}
1424                         self.section.aliased[section][self.alias] = true
1425                 end
1426
1427                 if fvalue and (self.forcewrite or not (fvalue == cvalue)) then
1428                         if self:write(section, fvalue) then
1429                                 -- Push events
1430                                 self.section.changed = true
1431                                 --luci.util.append(self.map.events, self.events)
1432                         end
1433                 end
1434         else                                                    -- Unset the UCI or error
1435                 if self.rmempty or self.optional then
1436                         if not self.alias or
1437                            not self.section.aliased or
1438                            not self.section.aliased[section] or
1439                            not self.section.aliased[section][self.alias]
1440                         then
1441                                 if self:remove(section) then
1442                                         -- Push events
1443                                         self.section.changed = true
1444                                         --luci.util.append(self.map.events, self.events)
1445                                 end
1446                         end
1447                 elseif cvalue ~= fvalue and not novld then
1448                         -- trigger validator with nil value to get custom user error msg.
1449                         local _, val_err = self:validate(nil, section)
1450                         self:add_error(section, "missing", val_err)
1451                 end
1452         end
1453 end
1454
1455 -- Render if this value exists or if it is mandatory
1456 function AbstractValue.render(self, s, scope)
1457         if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then
1458                 scope = scope or {}
1459                 scope.section = s
1460                 scope.cbid    = self:cbid(s)
1461                 Node.render(self, scope)
1462         end
1463 end
1464
1465 -- Return the UCI value of this object
1466 function AbstractValue.cfgvalue(self, section)
1467         local value
1468         if self.tag_error[section] then
1469                 value = self:formvalue(section)
1470         else
1471                 value = self.map:get(section, self.alias or self.option)
1472         end
1473
1474         if not value then
1475                 return nil
1476         elseif not self.cast or self.cast == type(value) then
1477                 return value
1478         elseif self.cast == "string" then
1479                 if type(value) == "table" then
1480                         return value[1]
1481                 end
1482         elseif self.cast == "table" then
1483                 return { value }
1484         end
1485 end
1486
1487 -- Validate the form value
1488 function AbstractValue.validate(self, value)
1489         if self.datatype and value then
1490                 if type(value) == "table" then
1491                         local v
1492                         for _, v in ipairs(value) do
1493                                 if v and #v > 0 and not verify_datatype(self.datatype, v) then
1494                                         return nil
1495                                 end
1496                         end
1497                 else
1498                         if not verify_datatype(self.datatype, value) then
1499                                 return nil
1500                         end
1501                 end
1502         end
1503
1504         return value
1505 end
1506
1507 AbstractValue.transform = AbstractValue.validate
1508
1509
1510 -- Write to UCI
1511 function AbstractValue.write(self, section, value)
1512         return self.map:set(section, self.alias or self.option, value)
1513 end
1514
1515 -- Remove from UCI
1516 function AbstractValue.remove(self, section)
1517         return self.map:del(section, self.alias or self.option)
1518 end
1519
1520
1521
1522
1523 --[[
1524 Value - A one-line value
1525         maxlength:      The maximum length
1526 ]]--
1527 Value = class(AbstractValue)
1528
1529 function Value.__init__(self, ...)
1530         AbstractValue.__init__(self, ...)
1531         self.template  = "cbi/value"
1532         self.keylist = {}
1533         self.vallist = {}
1534         self.readonly = nil
1535 end
1536
1537 function Value.reset_values(self)
1538         self.keylist = {}
1539         self.vallist = {}
1540 end
1541
1542 function Value.value(self, key, val)
1543         val = val or key
1544         table.insert(self.keylist, tostring(key))
1545         table.insert(self.vallist, tostring(val))
1546 end
1547
1548 function Value.parse(self, section, novld)
1549         if self.readonly then return end
1550         AbstractValue.parse(self, section, novld)
1551 end
1552
1553 -- DummyValue - This does nothing except being there
1554 DummyValue = class(AbstractValue)
1555
1556 function DummyValue.__init__(self, ...)
1557         AbstractValue.__init__(self, ...)
1558         self.template = "cbi/dvalue"
1559         self.value = nil
1560 end
1561
1562 function DummyValue.cfgvalue(self, section)
1563         local value
1564         if self.value then
1565                 if type(self.value) == "function" then
1566                         value = self:value(section)
1567                 else
1568                         value = self.value
1569                 end
1570         else
1571                 value = AbstractValue.cfgvalue(self, section)
1572         end
1573         return value
1574 end
1575
1576 function DummyValue.parse(self)
1577
1578 end
1579
1580
1581 --[[
1582 Flag - A flag being enabled or disabled
1583 ]]--
1584 Flag = class(AbstractValue)
1585
1586 function Flag.__init__(self, ...)
1587         AbstractValue.__init__(self, ...)
1588         self.template  = "cbi/fvalue"
1589
1590         self.enabled  = "1"
1591         self.disabled = "0"
1592         self.default  = self.disabled
1593 end
1594
1595 -- A flag can only have two states: set or unset
1596 function Flag.parse(self, section, novld)
1597         local fexists = self.map:formvalue(
1598                 FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
1599
1600         if fexists then
1601                 local fvalue = self:formvalue(section) and self.enabled or self.disabled
1602                 local cvalue = self:cfgvalue(section)
1603                 local val_err
1604                 fvalue, val_err = self:validate(fvalue, section)
1605                 if not fvalue then
1606                         if not novld then
1607                                 self:add_error(section, "invalid", val_err)
1608                         end
1609                         return
1610                 end
1611                 if fvalue == self.default and (self.optional or self.rmempty) then
1612                         self:remove(section)
1613                 else
1614                         self:write(section, fvalue)
1615                 end
1616                 if (fvalue ~= cvalue) then self.section.changed = true end
1617         else
1618                 self:remove(section)
1619                 self.section.changed = true
1620         end
1621 end
1622
1623 function Flag.cfgvalue(self, section)
1624         return AbstractValue.cfgvalue(self, section) or self.default
1625 end
1626 function Flag.validate(self, value)
1627         return value
1628 end
1629
1630 --[[
1631 ListValue - A one-line value predefined in a list
1632         widget: The widget that will be used (select, radio)
1633 ]]--
1634 ListValue = class(AbstractValue)
1635
1636 function ListValue.__init__(self, ...)
1637         AbstractValue.__init__(self, ...)
1638         self.template  = "cbi/lvalue"
1639
1640         self.size   = 1
1641         self.widget = "select"
1642
1643         self:reset_values()
1644 end
1645
1646 function ListValue.reset_values(self)
1647         self.keylist = {}
1648         self.vallist = {}
1649         self.deplist = {}
1650 end
1651
1652 function ListValue.value(self, key, val, ...)
1653         if luci.util.contains(self.keylist, key) then
1654                 return
1655         end
1656
1657         val = val or key
1658         table.insert(self.keylist, tostring(key))
1659         table.insert(self.vallist, tostring(val))
1660         table.insert(self.deplist, {...})
1661 end
1662
1663 function ListValue.validate(self, val)
1664         if luci.util.contains(self.keylist, val) then
1665                 return val
1666         else
1667                 return nil
1668         end
1669 end
1670
1671
1672
1673 --[[
1674 MultiValue - Multiple delimited values
1675         widget: The widget that will be used (select, checkbox)
1676         delimiter: The delimiter that will separate the values (default: " ")
1677 ]]--
1678 MultiValue = class(AbstractValue)
1679
1680 function MultiValue.__init__(self, ...)
1681         AbstractValue.__init__(self, ...)
1682         self.template = "cbi/mvalue"
1683
1684         self.widget = "checkbox"
1685         self.delimiter = " "
1686
1687         self:reset_values()
1688 end
1689
1690 function MultiValue.render(self, ...)
1691         if self.widget == "select" and not self.size then
1692                 self.size = #self.vallist
1693         end
1694
1695         AbstractValue.render(self, ...)
1696 end
1697
1698 function MultiValue.reset_values(self)
1699         self.keylist = {}
1700         self.vallist = {}
1701         self.deplist = {}
1702 end
1703
1704 function MultiValue.value(self, key, val)
1705         if luci.util.contains(self.keylist, key) then
1706                 return
1707         end
1708
1709         val = val or key
1710         table.insert(self.keylist, tostring(key))
1711         table.insert(self.vallist, tostring(val))
1712 end
1713
1714 function MultiValue.valuelist(self, section)
1715         local val = self:cfgvalue(section)
1716
1717         if not(type(val) == "string") then
1718                 return {}
1719         end
1720
1721         return luci.util.split(val, self.delimiter)
1722 end
1723
1724 function MultiValue.validate(self, val)
1725         val = (type(val) == "table") and val or {val}
1726
1727         local result
1728
1729         for i, value in ipairs(val) do
1730                 if luci.util.contains(self.keylist, value) then
1731                         result = result and (result .. self.delimiter .. value) or value
1732                 end
1733         end
1734
1735         return result
1736 end
1737
1738
1739 StaticList = class(MultiValue)
1740
1741 function StaticList.__init__(self, ...)
1742         MultiValue.__init__(self, ...)
1743         self.cast = "table"
1744         self.valuelist = self.cfgvalue
1745
1746         if not self.override_scheme
1747          and self.map:get_scheme(self.section.sectiontype, self.option) then
1748                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1749                 if self.value and vs.values and not self.override_values then
1750                         for k, v in pairs(vs.values) do
1751                                 self:value(k, v)
1752                         end
1753                 end
1754         end
1755 end
1756
1757 function StaticList.validate(self, value)
1758         value = (type(value) == "table") and value or {value}
1759
1760         local valid = {}
1761         for i, v in ipairs(value) do
1762                 if luci.util.contains(self.keylist, v) then
1763                         table.insert(valid, v)
1764                 end
1765         end
1766         return valid
1767 end
1768
1769
1770 DynamicList = class(AbstractValue)
1771
1772 function DynamicList.__init__(self, ...)
1773         AbstractValue.__init__(self, ...)
1774         self.template  = "cbi/dynlist"
1775         self.cast = "table"
1776         self:reset_values()
1777 end
1778
1779 function DynamicList.reset_values(self)
1780         self.keylist = {}
1781         self.vallist = {}
1782 end
1783
1784 function DynamicList.value(self, key, val)
1785         val = val or key
1786         table.insert(self.keylist, tostring(key))
1787         table.insert(self.vallist, tostring(val))
1788 end
1789
1790 function DynamicList.write(self, section, value)
1791         local t = { }
1792
1793         if type(value) == "table" then
1794                 local x
1795                 for _, x in ipairs(value) do
1796                         if x and #x > 0 then
1797                                 t[#t+1] = x
1798                         end
1799                 end
1800         else
1801                 t = { value }
1802         end
1803
1804         if self.cast == "string" then
1805                 value = table.concat(t, " ")
1806         else
1807                 value = t
1808         end
1809
1810         return AbstractValue.write(self, section, value)
1811 end
1812
1813 function DynamicList.cfgvalue(self, section)
1814         local value = AbstractValue.cfgvalue(self, section)
1815
1816         if type(value) == "string" then
1817                 local x
1818                 local t = { }
1819                 for x in value:gmatch("%S+") do
1820                         if #x > 0 then
1821                                 t[#t+1] = x
1822                         end
1823                 end
1824                 value = t
1825         end
1826
1827         return value
1828 end
1829
1830 function DynamicList.formvalue(self, section)
1831         local value = AbstractValue.formvalue(self, section)
1832
1833         if type(value) == "string" then
1834                 if self.cast == "string" then
1835                         local x
1836                         local t = { }
1837                         for x in value:gmatch("%S+") do
1838                                 t[#t+1] = x
1839                         end
1840                         value = t
1841                 else
1842                         value = { value }
1843                 end
1844         end
1845
1846         return value
1847 end
1848
1849
1850 DropDown = class(MultiValue)
1851
1852 function DropDown.__init__(self, ...)
1853         ListValue.__init__(self, ...)
1854         self.template = "cbi/dropdown"
1855         self.delimiter = " "
1856 end
1857
1858
1859 --[[
1860 TextValue - A multi-line value
1861         rows:   Rows
1862 ]]--
1863 TextValue = class(AbstractValue)
1864
1865 function TextValue.__init__(self, ...)
1866         AbstractValue.__init__(self, ...)
1867         self.template  = "cbi/tvalue"
1868 end
1869
1870 --[[
1871 Button
1872 ]]--
1873 Button = class(AbstractValue)
1874
1875 function Button.__init__(self, ...)
1876         AbstractValue.__init__(self, ...)
1877         self.template  = "cbi/button"
1878         self.inputstyle = nil
1879         self.rmempty = true
1880         self.unsafeupload = false
1881 end
1882
1883
1884 FileUpload = class(AbstractValue)
1885
1886 function FileUpload.__init__(self, ...)
1887         AbstractValue.__init__(self, ...)
1888         self.template = "cbi/upload"
1889         if not self.map.upload_fields then
1890                 self.map.upload_fields = { self }
1891         else
1892                 self.map.upload_fields[#self.map.upload_fields+1] = self
1893         end
1894 end
1895
1896 function FileUpload.formcreated(self, section)
1897         if self.unsafeupload then
1898                 return AbstractValue.formcreated(self, section) or
1899                         self.map:formvalue("cbi.rlf."..section.."."..self.option) or
1900                         self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or
1901                         self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1902         else
1903                 return AbstractValue.formcreated(self, section) or
1904                         self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1905         end
1906 end
1907
1908 function FileUpload.cfgvalue(self, section)
1909         local val = AbstractValue.cfgvalue(self, section)
1910         if val and fs.access(val) then
1911                 return val
1912         end
1913         return nil
1914 end
1915
1916 -- If we have a new value, use it
1917 -- otherwise use old value
1918 -- deletion should be managed by a separate button object
1919 -- unless self.unsafeupload is set in which case if the user
1920 -- choose to remove the old file we do so.
1921 -- Also, allow to specify (via textbox) a file already on router
1922 function FileUpload.formvalue(self, section)
1923         local val = AbstractValue.formvalue(self, section)
1924         if val then
1925                 if self.unsafeupload then
1926                         if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
1927                             not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1928                         then
1929                                 return val
1930                         end
1931                         fs.unlink(val)
1932                         self.value = nil
1933                         return nil
1934                 elseif val ~= "" then
1935                         return val
1936                 end
1937         end
1938         val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1939         if val == "" then
1940                 val = nil
1941         end
1942         if not self.unsafeupload then
1943                 if not val then
1944                         val = self.map:formvalue("cbi.rlf."..section.."."..self.option)
1945                 end
1946         end
1947         return val
1948 end
1949
1950 function FileUpload.remove(self, section)
1951         if self.unsafeupload then
1952                 local val = AbstractValue.formvalue(self, section)
1953                 if val and fs.access(val) then fs.unlink(val) end
1954                 return AbstractValue.remove(self, section)
1955         else
1956                 return nil
1957         end
1958 end
1959
1960 FileBrowser = class(AbstractValue)
1961
1962 function FileBrowser.__init__(self, ...)
1963         AbstractValue.__init__(self, ...)
1964         self.template = "cbi/browser"
1965 end