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