luci-base: cbi: atomically reorder uci sections
[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 fvalue and (self.forcewrite or not (fvalue == cvalue)) then
1421                         if self:write(section, fvalue) then
1422                                 -- Push events
1423                                 self.section.changed = true
1424                                 --luci.util.append(self.map.events, self.events)
1425                         end
1426                 end
1427         else                                                    -- Unset the UCI or error
1428                 if self.rmempty or self.optional then
1429                         if self:remove(section) then
1430                                 -- Push events
1431                                 self.section.changed = true
1432                                 --luci.util.append(self.map.events, self.events)
1433                         end
1434                 elseif cvalue ~= fvalue and not novld then
1435                         -- trigger validator with nil value to get custom user error msg.
1436                         local _, val_err = self:validate(nil, section)
1437                         self:add_error(section, "missing", val_err)
1438                 end
1439         end
1440 end
1441
1442 -- Render if this value exists or if it is mandatory
1443 function AbstractValue.render(self, s, scope)
1444         if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then
1445                 scope = scope or {}
1446                 scope.section = s
1447                 scope.cbid    = self:cbid(s)
1448                 Node.render(self, scope)
1449         end
1450 end
1451
1452 -- Return the UCI value of this object
1453 function AbstractValue.cfgvalue(self, section)
1454         local value
1455         if self.tag_error[section] then
1456                 value = self:formvalue(section)
1457         else
1458                 value = self.map:get(section, self.option)
1459         end
1460
1461         if not value then
1462                 return nil
1463         elseif not self.cast or self.cast == type(value) then
1464                 return value
1465         elseif self.cast == "string" then
1466                 if type(value) == "table" then
1467                         return value[1]
1468                 end
1469         elseif self.cast == "table" then
1470                 return { value }
1471         end
1472 end
1473
1474 -- Validate the form value
1475 function AbstractValue.validate(self, value)
1476         if self.datatype and value then
1477                 if type(value) == "table" then
1478                         local v
1479                         for _, v in ipairs(value) do
1480                                 if v and #v > 0 and not verify_datatype(self.datatype, v) then
1481                                         return nil
1482                                 end
1483                         end
1484                 else
1485                         if not verify_datatype(self.datatype, value) then
1486                                 return nil
1487                         end
1488                 end
1489         end
1490
1491         return value
1492 end
1493
1494 AbstractValue.transform = AbstractValue.validate
1495
1496
1497 -- Write to UCI
1498 function AbstractValue.write(self, section, value)
1499         return self.map:set(section, self.option, value)
1500 end
1501
1502 -- Remove from UCI
1503 function AbstractValue.remove(self, section)
1504         return self.map:del(section, self.option)
1505 end
1506
1507
1508
1509
1510 --[[
1511 Value - A one-line value
1512         maxlength:      The maximum length
1513 ]]--
1514 Value = class(AbstractValue)
1515
1516 function Value.__init__(self, ...)
1517         AbstractValue.__init__(self, ...)
1518         self.template  = "cbi/value"
1519         self.keylist = {}
1520         self.vallist = {}
1521         self.readonly = nil
1522 end
1523
1524 function Value.reset_values(self)
1525         self.keylist = {}
1526         self.vallist = {}
1527 end
1528
1529 function Value.value(self, key, val)
1530         val = val or key
1531         table.insert(self.keylist, tostring(key))
1532         table.insert(self.vallist, tostring(val))
1533 end
1534
1535 function Value.parse(self, section, novld)
1536         if self.readonly then return end
1537         AbstractValue.parse(self, section, novld)
1538 end
1539
1540 -- DummyValue - This does nothing except being there
1541 DummyValue = class(AbstractValue)
1542
1543 function DummyValue.__init__(self, ...)
1544         AbstractValue.__init__(self, ...)
1545         self.template = "cbi/dvalue"
1546         self.value = nil
1547 end
1548
1549 function DummyValue.cfgvalue(self, section)
1550         local value
1551         if self.value then
1552                 if type(self.value) == "function" then
1553                         value = self:value(section)
1554                 else
1555                         value = self.value
1556                 end
1557         else
1558                 value = AbstractValue.cfgvalue(self, section)
1559         end
1560         return value
1561 end
1562
1563 function DummyValue.parse(self)
1564
1565 end
1566
1567
1568 --[[
1569 Flag - A flag being enabled or disabled
1570 ]]--
1571 Flag = class(AbstractValue)
1572
1573 function Flag.__init__(self, ...)
1574         AbstractValue.__init__(self, ...)
1575         self.template  = "cbi/fvalue"
1576
1577         self.enabled  = "1"
1578         self.disabled = "0"
1579         self.default  = self.disabled
1580 end
1581
1582 -- A flag can only have two states: set or unset
1583 function Flag.parse(self, section, novld)
1584         local fexists = self.map:formvalue(
1585                 FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
1586
1587         if fexists then
1588                 local fvalue = self:formvalue(section) and self.enabled or self.disabled
1589                 local cvalue = self:cfgvalue(section)
1590                 local val_err
1591                 fvalue, val_err = self:validate(fvalue, section)
1592                 if not fvalue then
1593                         if not novld then
1594                                 self:add_error(section, "invalid", val_err)
1595                         end
1596                         return
1597                 end
1598                 if fvalue == self.default and (self.optional or self.rmempty) then
1599                         self:remove(section)
1600                 else
1601                         self:write(section, fvalue)
1602                 end
1603                 if (fvalue ~= cvalue) then self.section.changed = true end
1604         else
1605                 self:remove(section)
1606                 self.section.changed = true
1607         end
1608 end
1609
1610 function Flag.cfgvalue(self, section)
1611         return AbstractValue.cfgvalue(self, section) or self.default
1612 end
1613 function Flag.validate(self, value)
1614         return value
1615 end
1616
1617 --[[
1618 ListValue - A one-line value predefined in a list
1619         widget: The widget that will be used (select, radio)
1620 ]]--
1621 ListValue = class(AbstractValue)
1622
1623 function ListValue.__init__(self, ...)
1624         AbstractValue.__init__(self, ...)
1625         self.template  = "cbi/lvalue"
1626
1627         self.size   = 1
1628         self.widget = "select"
1629
1630         self:reset_values()
1631 end
1632
1633 function ListValue.reset_values(self)
1634         self.keylist = {}
1635         self.vallist = {}
1636         self.deplist = {}
1637 end
1638
1639 function ListValue.value(self, key, val, ...)
1640         if luci.util.contains(self.keylist, key) then
1641                 return
1642         end
1643
1644         val = val or key
1645         table.insert(self.keylist, tostring(key))
1646         table.insert(self.vallist, tostring(val))
1647         table.insert(self.deplist, {...})
1648 end
1649
1650 function ListValue.validate(self, val)
1651         if luci.util.contains(self.keylist, val) then
1652                 return val
1653         else
1654                 return nil
1655         end
1656 end
1657
1658
1659
1660 --[[
1661 MultiValue - Multiple delimited values
1662         widget: The widget that will be used (select, checkbox)
1663         delimiter: The delimiter that will separate the values (default: " ")
1664 ]]--
1665 MultiValue = class(AbstractValue)
1666
1667 function MultiValue.__init__(self, ...)
1668         AbstractValue.__init__(self, ...)
1669         self.template = "cbi/mvalue"
1670
1671         self.widget = "checkbox"
1672         self.delimiter = " "
1673
1674         self:reset_values()
1675 end
1676
1677 function MultiValue.render(self, ...)
1678         if self.widget == "select" and not self.size then
1679                 self.size = #self.vallist
1680         end
1681
1682         AbstractValue.render(self, ...)
1683 end
1684
1685 function MultiValue.reset_values(self)
1686         self.keylist = {}
1687         self.vallist = {}
1688         self.deplist = {}
1689 end
1690
1691 function MultiValue.value(self, key, val)
1692         if luci.util.contains(self.keylist, key) then
1693                 return
1694         end
1695
1696         val = val or key
1697         table.insert(self.keylist, tostring(key))
1698         table.insert(self.vallist, tostring(val))
1699 end
1700
1701 function MultiValue.valuelist(self, section)
1702         local val = self:cfgvalue(section)
1703
1704         if not(type(val) == "string") then
1705                 return {}
1706         end
1707
1708         return luci.util.split(val, self.delimiter)
1709 end
1710
1711 function MultiValue.validate(self, val)
1712         val = (type(val) == "table") and val or {val}
1713
1714         local result
1715
1716         for i, value in ipairs(val) do
1717                 if luci.util.contains(self.keylist, value) then
1718                         result = result and (result .. self.delimiter .. value) or value
1719                 end
1720         end
1721
1722         return result
1723 end
1724
1725
1726 StaticList = class(MultiValue)
1727
1728 function StaticList.__init__(self, ...)
1729         MultiValue.__init__(self, ...)
1730         self.cast = "table"
1731         self.valuelist = self.cfgvalue
1732
1733         if not self.override_scheme
1734          and self.map:get_scheme(self.section.sectiontype, self.option) then
1735                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1736                 if self.value and vs.values and not self.override_values then
1737                         for k, v in pairs(vs.values) do
1738                                 self:value(k, v)
1739                         end
1740                 end
1741         end
1742 end
1743
1744 function StaticList.validate(self, value)
1745         value = (type(value) == "table") and value or {value}
1746
1747         local valid = {}
1748         for i, v in ipairs(value) do
1749                 if luci.util.contains(self.keylist, v) then
1750                         table.insert(valid, v)
1751                 end
1752         end
1753         return valid
1754 end
1755
1756
1757 DynamicList = class(AbstractValue)
1758
1759 function DynamicList.__init__(self, ...)
1760         AbstractValue.__init__(self, ...)
1761         self.template  = "cbi/dynlist"
1762         self.cast = "table"
1763         self:reset_values()
1764 end
1765
1766 function DynamicList.reset_values(self)
1767         self.keylist = {}
1768         self.vallist = {}
1769 end
1770
1771 function DynamicList.value(self, key, val)
1772         val = val or key
1773         table.insert(self.keylist, tostring(key))
1774         table.insert(self.vallist, tostring(val))
1775 end
1776
1777 function DynamicList.write(self, section, value)
1778         local t = { }
1779
1780         if type(value) == "table" then
1781                 local x
1782                 for _, x in ipairs(value) do
1783                         if x and #x > 0 then
1784                                 t[#t+1] = x
1785                         end
1786                 end
1787         else
1788                 t = { value }
1789         end
1790
1791         if self.cast == "string" then
1792                 value = table.concat(t, " ")
1793         else
1794                 value = t
1795         end
1796
1797         return AbstractValue.write(self, section, value)
1798 end
1799
1800 function DynamicList.cfgvalue(self, section)
1801         local value = AbstractValue.cfgvalue(self, section)
1802
1803         if type(value) == "string" then
1804                 local x
1805                 local t = { }
1806                 for x in value:gmatch("%S+") do
1807                         if #x > 0 then
1808                                 t[#t+1] = x
1809                         end
1810                 end
1811                 value = t
1812         end
1813
1814         return value
1815 end
1816
1817 function DynamicList.formvalue(self, section)
1818         local value = AbstractValue.formvalue(self, section)
1819
1820         if type(value) == "string" then
1821                 if self.cast == "string" then
1822                         local x
1823                         local t = { }
1824                         for x in value:gmatch("%S+") do
1825                                 t[#t+1] = x
1826                         end
1827                         value = t
1828                 else
1829                         value = { value }
1830                 end
1831         end
1832
1833         return value
1834 end
1835
1836
1837 --[[
1838 TextValue - A multi-line value
1839         rows:   Rows
1840 ]]--
1841 TextValue = class(AbstractValue)
1842
1843 function TextValue.__init__(self, ...)
1844         AbstractValue.__init__(self, ...)
1845         self.template  = "cbi/tvalue"
1846 end
1847
1848 --[[
1849 Button
1850 ]]--
1851 Button = class(AbstractValue)
1852
1853 function Button.__init__(self, ...)
1854         AbstractValue.__init__(self, ...)
1855         self.template  = "cbi/button"
1856         self.inputstyle = nil
1857         self.rmempty = true
1858         self.unsafeupload = false
1859 end
1860
1861
1862 FileUpload = class(AbstractValue)
1863
1864 function FileUpload.__init__(self, ...)
1865         AbstractValue.__init__(self, ...)
1866         self.template = "cbi/upload"
1867         if not self.map.upload_fields then
1868                 self.map.upload_fields = { self }
1869         else
1870                 self.map.upload_fields[#self.map.upload_fields+1] = self
1871         end
1872 end
1873
1874 function FileUpload.formcreated(self, section)
1875         if self.unsafeupload then
1876                 return AbstractValue.formcreated(self, section) or
1877                         self.map:formvalue("cbi.rlf."..section.."."..self.option) or
1878                         self.map:formvalue("cbi.rlf."..section.."."..self.option..".x") or
1879                         self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1880         else
1881                 return AbstractValue.formcreated(self, section) or
1882                         self.map:formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1883         end
1884 end
1885
1886 function FileUpload.cfgvalue(self, section)
1887         local val = AbstractValue.cfgvalue(self, section)
1888         if val and fs.access(val) then
1889                 return val
1890         end
1891         return nil
1892 end
1893
1894 -- If we have a new value, use it
1895 -- otherwise use old value
1896 -- deletion should be managed by a separate button object
1897 -- unless self.unsafeupload is set in which case if the user
1898 -- choose to remove the old file we do so.
1899 -- Also, allow to specify (via textbox) a file already on router
1900 function FileUpload.formvalue(self, section)
1901         local val = AbstractValue.formvalue(self, section)
1902         if val then
1903                 if self.unsafeupload then
1904                         if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
1905                             not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1906                         then
1907                                 return val
1908                         end
1909                         fs.unlink(val)
1910                         self.value = nil
1911                         return nil
1912                 elseif val ~= "" then
1913                         return val
1914                 end
1915         end
1916         val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox")
1917         if val == "" then
1918                 val = nil
1919         end
1920         if not self.unsafeupload then
1921                 if not val then
1922                         val = self.map:formvalue("cbi.rlf."..section.."."..self.option)
1923                 end
1924         end
1925         return val
1926 end
1927
1928 function FileUpload.remove(self, section)
1929         if self.unsafeupload then
1930                 local val = AbstractValue.formvalue(self, section)
1931                 if val and fs.access(val) then fs.unlink(val) end
1932                 return AbstractValue.remove(self, section)
1933         else
1934                 return nil
1935         end
1936 end
1937
1938 FileBrowser = class(AbstractValue)
1939
1940 function FileBrowser.__init__(self, ...)
1941         AbstractValue.__init__(self, ...)
1942         self.template = "cbi/browser"
1943 end