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