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