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