libs/cbi: Disable strict mode for now
[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
34 local uci        = require("luci.model.uci")
35 local class      = luci.util.class
36 local instanceof = luci.util.instanceof
37
38 FORM_NODATA  =  0
39 FORM_VALID   =  1
40 FORM_INVALID = -1
41
42 AUTO = true
43
44 CREATE_PREFIX = "cbi.cts."
45 REMOVE_PREFIX = "cbi.rts."
46
47 -- Loads a CBI map from given file, creating an environment and returns it
48 function load(cbimap, ...)
49         require("luci.fs")
50         require("luci.i18n")
51         require("luci.config")
52         require("luci.util")
53
54         local cbidir = luci.util.libpath() .. "/model/cbi/"
55         local func, err = loadfile(cbidir..cbimap..".lua")
56
57         if not func then
58                 return nil
59         end
60
61         luci.i18n.loadc("cbi")
62
63         luci.util.resfenv(func)
64         luci.util.updfenv(func, luci.cbi)
65         luci.util.extfenv(func, "translate", luci.i18n.translate)
66         luci.util.extfenv(func, "translatef", luci.i18n.translatef)
67         luci.util.extfenv(func, "arg", {...})
68
69         local maps = {func()}
70
71         for i, map in ipairs(maps) do
72                 if not instanceof(map, Node) then
73                         error("CBI map returns no valid map object!")
74                         return nil
75                 end
76         end
77
78         return maps
79 end
80
81 local function _uvl_validate_section(node, name)
82         local co = node.map:get()
83
84         luci.uvl.STRICT_UNKNOWN_OPTIONS = false
85         luci.uvl.STRICT_UNKNOWN_SECTIONS = false
86
87         local stat, err = node.map.validator:validate_section(node.config, name, co)
88         if err then
89                 node.map.save = false
90                 if err.code == luci.uvl.errors.ERR_DEPENDENCY then
91                         node.tag_deperror[name] = true
92                 else
93                         node.tag_invalid[name] = true
94                 end
95                 for i, v in ipairs(err.childs) do
96                         if v.option and node.fields[v.option] then
97                                 if v.code == luci.uvl.errors.ERR_OPTION then
98                                         local subcode = v.childs and v.childs[1] and v.childs[1].code
99                                         if subcode == luci.uvl.errors.ERR_DEPENDENCY then
100                                                 node.fields[v.option].tag_reqerror[name] = true
101                                         elseif subcode == luci.uvl.errors.ERR_OPT_REQUIRED then
102                                                 node.fields[v.option].tag_missing[name] = true
103                                                 node.tag_deperror[name] = true
104                                         else
105                                                 node.fields[v.option].tag_invalid[name] = true
106                                         end
107                                 end
108                         end
109                 end
110         end
111
112 end
113
114 local function _uvl_strip_remote_dependencies(deps)
115         local clean = {}
116
117         for k, v in pairs(deps) do
118                 k = k:gsub("%$config%.%$section%.", "")
119                 if k:match("^[%w_]+$") and type(v) == "string" then
120                         clean[k] = v
121                 end
122         end
123
124         return clean
125 end
126
127
128 -- Node pseudo abstract class
129 Node = class()
130
131 function Node.__init__(self, title, description)
132         self.children = {}
133         self.title = title or ""
134         self.description = description or ""
135         self.template = "cbi/node"
136 end
137
138 -- i18n helper
139 function Node._i18n(self, config, section, option, title, description)
140
141         -- i18n loaded?
142         if type(luci.i18n) == "table" then
143
144                 local key = config and config:gsub("[^%w]+", "") or ""
145
146                 if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
147                 if option  then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "")  end
148
149                 self.title = title or luci.i18n.translate( key, option or section or config )
150                 self.description = description or luci.i18n.translate( key .. "_desc", "" )
151         end
152 end
153
154 -- Append child nodes
155 function Node.append(self, obj)
156         table.insert(self.children, obj)
157 end
158
159 -- Parse this node and its children
160 function Node.parse(self, ...)
161         for k, child in ipairs(self.children) do
162                 child:parse(...)
163         end
164 end
165
166 -- Render this node
167 function Node.render(self, scope)
168         scope = scope or {}
169         scope.self = self
170
171         luci.template.render(self.template, scope)
172 end
173
174 -- Render the children
175 function Node.render_children(self, ...)
176         for k, node in ipairs(self.children) do
177                 node:render(...)
178         end
179 end
180
181
182 --[[
183 A simple template element
184 ]]--
185 Template = class(Node)
186
187 function Template.__init__(self, template)
188         Node.__init__(self)
189         self.template = template
190 end
191
192 function Template.render(self)
193         luci.template.render(self.template, {self=self})
194 end
195
196
197 --[[
198 Map - A map describing a configuration file
199 ]]--
200 Map = class(Node)
201
202 function Map.__init__(self, config, ...)
203         Node.__init__(self, ...)
204         Node._i18n(self, config, nil, nil, ...)
205
206         self.config = config
207         self.parsechain = {self.config}
208         self.template = "cbi/map"
209         self.uci = uci.cursor()
210         self.save = true
211         if not self.uci:load(self.config) then
212                 error("Unable to read UCI data: " .. self.config)
213         end
214
215         self.validator = luci.uvl.UVL()
216         self.scheme = self.validator:get_scheme(self.config)
217         
218 end
219
220 function Map.get_scheme(self, sectiontype, option)
221         if not option then
222                 return self.scheme and self.scheme.sections[sectiontype]
223         else
224                 return self.scheme and self.scheme.variables[sectiontype]
225                  and self.scheme.variables[sectiontype][option]
226         end
227 end
228
229
230 -- Chain foreign config
231 function Map.chain(self, config)
232         table.insert(self.parsechain, config)
233 end
234
235 -- Use optimized UCI writing
236 function Map.parse(self, ...)
237         Node.parse(self, ...)
238
239         if self.save then
240                 for i, config in ipairs(self.parsechain) do
241                         self.uci:save(config)
242                 end
243                 if luci.http.formvalue("cbi.apply") then
244                         for i, config in ipairs(self.parsechain) do
245                                 self.uci:commit(config)
246                                 self.uci:apply(config)
247         
248                                 -- Refresh data because commit changes section names
249                                 self.uci:load(config)
250                         end
251         
252                         -- Reparse sections
253                         Node.parse(self, ...)
254         
255                 end
256                 for i, config in ipairs(self.parsechain) do
257                         self.uci:unload(config)
258                 end
259         end
260 end
261
262 -- Creates a child section
263 function Map.section(self, class, ...)
264         if instanceof(class, AbstractSection) then
265                 local obj  = class(self, ...)
266                 self:append(obj)
267                 return obj
268         else
269                 error("class must be a descendent of AbstractSection")
270         end
271 end
272
273 -- UCI add
274 function Map.add(self, sectiontype)
275         return self.uci:add(self.config, sectiontype)
276 end
277
278 -- UCI set
279 function Map.set(self, section, option, value)
280         if option then
281                 return self.uci:set(self.config, section, option, value)
282         else
283                 return self.uci:set(self.config, section, value)
284         end
285 end
286
287 -- UCI del
288 function Map.del(self, section, option)
289         if option then
290                 return self.uci:delete(self.config, section, option)
291         else
292                 return self.uci:delete(self.config, section)
293         end
294 end
295
296 -- UCI get
297 function Map.get(self, section, option)
298         if not section then
299                 return self.uci:get_all(self.config)
300         elseif option then
301                 return self.uci:get(self.config, section, option)
302         else
303                 return self.uci:get_all(self.config, section)
304         end
305 end
306
307
308 --[[
309 Page - A simple node
310 ]]--
311
312 Page = class(Node)
313 Page.__init__ = Node.__init__
314 Page.parse    = function() end
315
316
317 --[[
318 SimpleForm - A Simple non-UCI form
319 ]]--
320 SimpleForm = class(Node)
321
322 function SimpleForm.__init__(self, config, title, description, data)
323         Node.__init__(self, title, description)
324         self.config = config
325         self.data = data or {}
326         self.template = "cbi/simpleform"
327         self.dorender = true
328 end
329
330 function SimpleForm.parse(self, ...)
331         if luci.http.formvalue("cbi.submit") then
332                 Node.parse(self, 1, ...)
333         end
334
335         local valid = true
336         for k, j in ipairs(self.children) do
337                 for i, v in ipairs(j.children) do
338                         valid = valid
339                          and (not v.tag_missing or not v.tag_missing[1])
340                          and (not v.tag_invalid or not v.tag_invalid[1])
341                 end
342         end
343
344         local state =
345                 not luci.http.formvalue("cbi.submit") and 0
346                 or valid and 1
347                 or -1
348
349         self.dorender = not self.handle or self:handle(state, self.data) ~= false
350 end
351
352 function SimpleForm.render(self, ...)
353         if self.dorender then
354                 Node.render(self, ...)
355         end
356 end
357
358 function SimpleForm.section(self, class, ...)
359         if instanceof(class, AbstractSection) then
360                 local obj  = class(self, ...)
361                 self:append(obj)
362                 return obj
363         else
364                 error("class must be a descendent of AbstractSection")
365         end
366 end
367
368 -- Creates a child field
369 function SimpleForm.field(self, class, ...)
370         local section
371         for k, v in ipairs(self.children) do
372                 if instanceof(v, SimpleSection) then
373                         section = v
374                         break
375                 end
376         end
377         if not section then
378                 section = self:section(SimpleSection)
379         end
380
381         if instanceof(class, AbstractValue) then
382                 local obj  = class(self, section, ...)
383                 obj.track_missing = true
384                 section:append(obj)
385                 return obj
386         else
387                 error("class must be a descendent of AbstractValue")
388         end
389 end
390
391 function SimpleForm.set(self, section, option, value)
392         self.data[option] = value
393 end
394
395
396 function SimpleForm.del(self, section, option)
397         self.data[option] = nil
398 end
399
400
401 function SimpleForm.get(self, section, option)
402         return self.data[option]
403 end
404
405
406 function SimpleForm.get_scheme()
407         return nil
408 end
409
410
411
412 --[[
413 AbstractSection
414 ]]--
415 AbstractSection = class(Node)
416
417 function AbstractSection.__init__(self, map, sectiontype, ...)
418         Node.__init__(self, ...)
419         self.sectiontype = sectiontype
420         self.map = map
421         self.config = map.config
422         self.optionals = {}
423         self.defaults = {}
424         self.fields = {}
425         self.tag_error = {}
426         self.tag_invalid = {}
427         self.tag_deperror = {}
428
429         self.optional = true
430         self.addremove = false
431         self.dynamic = false
432 end
433
434 -- Appends a new option
435 function AbstractSection.option(self, class, option, ...)
436         -- Autodetect from UVL
437         if class == true and self.map:get_scheme(self.sectiontype, option) then
438                 local vs = self.map:get_scheme(self.sectiontype, option)
439                 if vs.type == "boolean" then
440                         class = Flag
441                 elseif vs.type == "list" then
442                         class = DynamicList
443                 elseif vs.type == "enum" or vs.type == "reference" then
444                         class = ListValue
445                 else
446                         class = Value
447                 end
448         end
449
450         if instanceof(class, AbstractValue) then
451                 local obj  = class(self.map, self, option, ...)
452
453                 Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...)
454
455                 self:append(obj)
456                 self.fields[option] = obj
457                 return obj
458         elseif class == true then
459                 error("No valid class was given and autodetection failed.")
460         else
461                 error("class must be a descendant of AbstractValue")
462         end
463 end
464
465 -- Parse optional options
466 function AbstractSection.parse_optionals(self, section)
467         if not self.optional then
468                 return
469         end
470
471         self.optionals[section] = {}
472
473         local field = luci.http.formvalue("cbi.opt."..self.config.."."..section)
474         for k,v in ipairs(self.children) do
475                 if v.optional and not v:cfgvalue(section) then
476                         if field == v.option then
477                                 field = nil
478                         else
479                                 table.insert(self.optionals[section], v)
480                         end
481                 end
482         end
483
484         if field and #field > 0 and self.dynamic then
485                 self:add_dynamic(field)
486         end
487 end
488
489 -- Add a dynamic option
490 function AbstractSection.add_dynamic(self, field, optional)
491         local o = self:option(Value, field, field)
492         o.optional = optional
493 end
494
495 -- Parse all dynamic options
496 function AbstractSection.parse_dynamic(self, section)
497         if not self.dynamic then
498                 return
499         end
500
501         local arr  = luci.util.clone(self:cfgvalue(section))
502         local form = luci.http.formvaluetable("cbid."..self.config.."."..section)
503         for k, v in pairs(form) do
504                 arr[k] = v
505         end
506
507         for key,val in pairs(arr) do
508                 local create = true
509
510                 for i,c in ipairs(self.children) do
511                         if c.option == key then
512                                 create = false
513                         end
514                 end
515
516                 if create and key:sub(1, 1) ~= "." then
517                         self:add_dynamic(key, true)
518                 end
519         end
520 end
521
522 -- Returns the section's UCI table
523 function AbstractSection.cfgvalue(self, section)
524         return self.map:get(section)
525 end
526
527 -- Removes the section
528 function AbstractSection.remove(self, section)
529         return self.map:del(section)
530 end
531
532 -- Creates the section
533 function AbstractSection.create(self, section)
534         local stat
535
536         if section then
537                 stat = self.map:set(section, nil, self.sectiontype)
538         else
539                 section = self.map:add(self.sectiontype)
540                 stat = section
541         end
542
543         if stat then
544                 for k,v in pairs(self.children) do
545                         if v.default then
546                                 self.map:set(section, v.option, v.default)
547                         end
548                 end
549
550                 for k,v in pairs(self.defaults) do
551                         self.map:set(section, k, v)
552                 end
553         end
554
555         return stat
556 end
557
558
559 SimpleSection = class(AbstractSection)
560
561 function SimpleSection.__init__(self, form, ...)
562         AbstractSection.__init__(self, form, nil, ...)
563         self.template = "cbi/nullsection"
564 end
565
566
567 Table = class(AbstractSection)
568
569 function Table.__init__(self, form, data, ...)
570         local datasource = {}
571         datasource.config = "table"
572         self.data = data
573
574         function datasource.get(self, section, option)
575                 return data[section] and data[section][option]
576         end
577
578         function datasource.del(...)
579                 return true
580         end
581
582         function datasource.get_scheme()
583                 return nil
584         end
585
586         AbstractSection.__init__(self, datasource, "table", ...)
587         self.template = "cbi/tblsection"
588         self.rowcolors = true
589         self.anonymous = true
590 end
591
592 function Table.parse(self)
593         for i, k in ipairs(self:cfgsections()) do
594                 if luci.http.formvalue("cbi.submit") then
595                         Node.parse(self, k)
596                 end
597         end
598 end
599
600 function Table.cfgsections(self)
601         local sections = {}
602
603         for i, v in luci.util.kspairs(self.data) do
604                 table.insert(sections, i)
605         end
606
607         return sections
608 end
609
610
611
612 --[[
613 NamedSection - A fixed configuration section defined by its name
614 ]]--
615 NamedSection = class(AbstractSection)
616
617 function NamedSection.__init__(self, map, section, stype, ...)
618         AbstractSection.__init__(self, map, stype, ...)
619         Node._i18n(self, map.config, section, nil, ...)
620         
621         -- Defaults
622         self.addremove = false
623
624         -- Use defaults from UVL
625         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
626                 local vs = self.map:get_scheme(self.sectiontype)
627                 self.addremove = not vs.unique and not vs.required
628                 self.dynamic   = vs.dynamic
629                 self.title       = self.title or vs.title
630                 self.description = self.description or vs.descr
631         end
632
633         self.template = "cbi/nsection"
634         self.section = section
635 end
636
637 function NamedSection.parse(self)
638         local s = self.section
639         local active = self:cfgvalue(s)
640
641         if self.addremove then
642                 local path = self.config.."."..s
643                 if active then -- Remove the section
644                         if luci.http.formvalue("cbi.rns."..path) and self:remove(s) then
645                                 return
646                         end
647                 else           -- Create and apply default values
648                         if luci.http.formvalue("cbi.cns."..path) then
649                                 self:create(s)
650                                 return
651                         end
652                 end
653         end
654
655         if active then
656                 AbstractSection.parse_dynamic(self, s)
657                 if luci.http.formvalue("cbi.submit") then
658                         Node.parse(self, s)
659                         
660                         if not self.override_scheme and self.map.scheme then
661                                 _uvl_validate_section(self, s)
662                         end
663                 end
664                 AbstractSection.parse_optionals(self, s)
665         end
666 end
667
668
669 --[[
670 TypedSection - A (set of) configuration section(s) defined by the type
671         addremove:      Defines whether the user can add/remove sections of this type
672         anonymous:  Allow creating anonymous sections
673         validate:       a validation function returning nil if the section is invalid
674 ]]--
675 TypedSection = class(AbstractSection)
676
677 function TypedSection.__init__(self, map, type, ...)
678         AbstractSection.__init__(self, map, type, ...)
679         Node._i18n(self, map.config, type, nil, ...)
680
681         self.template  = "cbi/tsection"
682         self.deps = {}
683         self.anonymous = false
684
685         -- Use defaults from UVL
686         if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
687                 local vs = self.map:get_scheme(self.sectiontype)
688                 self.addremove = not vs.unique and not vs.required
689                 self.dynamic   = vs.dynamic
690                 self.anonymous = not vs.named
691                 self.title       = self.title or vs.title
692                 self.description = self.description or vs.descr
693         end
694 end
695
696 -- Return all matching UCI sections for this TypedSection
697 function TypedSection.cfgsections(self)
698         local sections = {}
699         self.map.uci:foreach(self.map.config, self.sectiontype,
700                 function (section)
701                         if self:checkscope(section[".name"]) then
702                                 table.insert(sections, section[".name"])
703                         end
704                 end)
705
706         return sections
707 end
708
709 -- Limits scope to sections that have certain option => value pairs
710 function TypedSection.depends(self, option, value)
711         table.insert(self.deps, {option=option, value=value})
712 end
713
714 function TypedSection.parse(self)
715         if self.addremove then
716                 -- Remove
717                 local crval = REMOVE_PREFIX .. self.config
718                 local name = luci.http.formvaluetable(crval)
719                 for k,v in pairs(name) do
720                         if self:cfgvalue(k) and self:checkscope(k) then
721                                 self:remove(k)
722                         end
723                 end
724         end
725
726         local co
727         for i, k in ipairs(self:cfgsections()) do
728                 AbstractSection.parse_dynamic(self, k)
729                 if luci.http.formvalue("cbi.submit") then
730                         Node.parse(self, k)
731                         
732                         if not self.override_scheme and self.map.scheme then
733                                 _uvl_validate_section(self, k)
734                         end
735                 end
736                 AbstractSection.parse_optionals(self, k)
737         end
738
739         if self.addremove then
740                 -- Create
741                 local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
742                 local name  = luci.http.formvalue(crval)
743                 if self.anonymous then
744                         if name then
745                                 self:create()
746                         end
747                 else
748                         if name then
749                                 -- Ignore if it already exists
750                                 if self:cfgvalue(name) then
751                                         name = nil;
752                                 end
753
754                                 name = self:checkscope(name)
755
756                                 if not name then
757                                         self.err_invalid = true
758                                 end
759
760                                 if name and #name > 0 then
761                                         self:create(name)
762                                 end
763                         end
764                 end
765         end
766 end
767
768 -- Verifies scope of sections
769 function TypedSection.checkscope(self, section)
770         -- Check if we are not excluded
771         if self.filter and not self:filter(section) then
772                 return nil
773         end
774
775         -- Check if at least one dependency is met
776         if #self.deps > 0 and self:cfgvalue(section) then
777                 local stat = false
778
779                 for k, v in ipairs(self.deps) do
780                         if self:cfgvalue(section)[v.option] == v.value then
781                                 stat = true
782                         end
783                 end
784
785                 if not stat then
786                         return nil
787                 end
788         end
789
790         return self:validate(section)
791 end
792
793
794 -- Dummy validate function
795 function TypedSection.validate(self, section)
796         return section
797 end
798
799
800 --[[
801 AbstractValue - An abstract Value Type
802         null:           Value can be empty
803         valid:          A function returning the value if it is valid otherwise nil
804         depends:        A table of option => value pairs of which one must be true
805         default:        The default value
806         size:           The size of the input fields
807         rmempty:        Unset value if empty
808         optional:       This value is optional (see AbstractSection.optionals)
809 ]]--
810 AbstractValue = class(Node)
811
812 function AbstractValue.__init__(self, map, section, option, ...)
813         Node.__init__(self, ...)
814         self.section = section
815         self.option  = option
816         self.map     = map
817         self.config  = map.config
818         self.tag_invalid = {}
819         self.tag_missing = {}
820         self.tag_reqerror = {}
821         self.tag_error = {}
822         self.deps = {}
823         self.cast = "string"
824
825         self.track_missing = false
826         self.rmempty   = false
827         self.default   = nil
828         self.size      = nil
829         self.optional  = false
830
831         -- Use defaults from UVL
832         if not self.override_scheme
833          and self.map:get_scheme(self.section.sectiontype, self.option) then
834                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
835                 self.rmempty     = not vs.required
836                 self.cast        = (vs.type == "list") and "list" or "string"
837                 self.title       = self.title or vs.title
838                 self.description = self.description or vs.descr
839
840                 if vs.depends and not self.override_dependencies then
841                         for i, deps in ipairs(vs.depends) do
842                                 deps = _uvl_strip_remote_dependencies(deps)
843                                 if next(deps) then
844                                         self:depends(deps)
845                                 end
846                         end
847                 end
848         end
849 end
850
851 -- Add a dependencie to another section field
852 function AbstractValue.depends(self, field, value)
853         local deps
854         if type(field) == "string" then
855                 deps = {}
856                 deps[field] = value
857         else
858                 deps = field
859         end
860
861         table.insert(self.deps, {deps=deps, add=""})
862 end
863
864 -- Generates the unique CBID
865 function AbstractValue.cbid(self, section)
866         return "cbid."..self.map.config.."."..section.."."..self.option
867 end
868
869 -- Return whether this object should be created
870 function AbstractValue.formcreated(self, section)
871         local key = "cbi.opt."..self.config.."."..section
872         return (luci.http.formvalue(key) == self.option)
873 end
874
875 -- Returns the formvalue for this object
876 function AbstractValue.formvalue(self, section)
877         return luci.http.formvalue(self:cbid(section))
878 end
879
880 function AbstractValue.additional(self, value)
881         self.optional = value
882 end
883
884 function AbstractValue.mandatory(self, value)
885         self.rmempty = not value
886 end
887
888 function AbstractValue.parse(self, section)
889         local fvalue = self:formvalue(section)
890         local cvalue = self:cfgvalue(section)
891
892         if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI
893                 fvalue = self:transform(self:validate(fvalue, section))
894                 if not fvalue then
895                         self.tag_invalid[section] = true
896                 end
897                 if fvalue and not (fvalue == cvalue) then
898                         self:write(section, fvalue)
899                 end
900         else                                                    -- Unset the UCI or error
901                 if self.rmempty or self.optional then
902                         self:remove(section)
903                 elseif self.track_missing and (not fvalue or fvalue ~= cvalue) then
904                         self.tag_missing[section] = true
905                 end
906         end
907 end
908
909 -- Render if this value exists or if it is mandatory
910 function AbstractValue.render(self, s, scope)
911         if not self.optional or self:cfgvalue(s) or self:formcreated(s) then
912                 scope = scope or {}
913                 scope.section   = s
914                 scope.cbid      = self:cbid(s)
915                 scope.striptags = luci.util.striptags
916
917                 scope.ifattr = function(cond,key,val)
918                         if cond then
919                                 return string.format(
920                                         ' %s="%s"', tostring(key),
921                                         luci.util.pcdata(tostring( val
922                                          or scope[key]
923                                          or (type(self[key]) ~= "function" and self[key])
924                                          or "" ))
925                                 )
926                         else
927                                 return ''
928                         end
929                 end
930
931                 scope.attr = function(...)
932                         return scope.ifattr( true, ... )
933                 end
934
935                 Node.render(self, scope)
936         end
937 end
938
939 -- Return the UCI value of this object
940 function AbstractValue.cfgvalue(self, section)
941         local value = self.map:get(section, self.option)
942         if not self.cast or self.cast == type(value) then
943                 return value
944         elseif self.cast == "string" then
945                 if type(value) == "table" then
946                         return value[1]
947                 end
948         elseif self.cast == "table" then
949                 return {value}
950         end
951 end
952
953 -- Validate the form value
954 function AbstractValue.validate(self, value)
955         return value
956 end
957
958 AbstractValue.transform = AbstractValue.validate
959
960
961 -- Write to UCI
962 function AbstractValue.write(self, section, value)
963         return self.map:set(section, self.option, value)
964 end
965
966 -- Remove from UCI
967 function AbstractValue.remove(self, section)
968         return self.map:del(section, self.option)
969 end
970
971
972
973
974 --[[
975 Value - A one-line value
976         maxlength:      The maximum length
977 ]]--
978 Value = class(AbstractValue)
979
980 function Value.__init__(self, ...)
981         AbstractValue.__init__(self, ...)
982         self.template  = "cbi/value"
983         self.keylist = {}
984         self.vallist = {}
985 end
986
987 function Value.value(self, key, val)
988         val = val or key
989         table.insert(self.keylist, tostring(key))
990         table.insert(self.vallist, tostring(val))
991 end
992
993
994 -- DummyValue - This does nothing except being there
995 DummyValue = class(AbstractValue)
996
997 function DummyValue.__init__(self, ...)
998         AbstractValue.__init__(self, ...)
999         self.template = "cbi/dvalue"
1000         self.value = nil
1001 end
1002
1003 function DummyValue.parse(self)
1004
1005 end
1006
1007
1008 --[[
1009 Flag - A flag being enabled or disabled
1010 ]]--
1011 Flag = class(AbstractValue)
1012
1013 function Flag.__init__(self, ...)
1014         AbstractValue.__init__(self, ...)
1015         self.template  = "cbi/fvalue"
1016
1017         self.enabled = "1"
1018         self.disabled = "0"
1019 end
1020
1021 -- A flag can only have two states: set or unset
1022 function Flag.parse(self, section)
1023         local fvalue = self:formvalue(section)
1024
1025         if fvalue then
1026                 fvalue = self.enabled
1027         else
1028                 fvalue = self.disabled
1029         end
1030
1031         if fvalue == self.enabled or (not self.optional and not self.rmempty) then
1032                 if not(fvalue == self:cfgvalue(section)) then
1033                         self:write(section, fvalue)
1034                 end
1035         else
1036                 self:remove(section)
1037         end
1038 end
1039
1040
1041
1042 --[[
1043 ListValue - A one-line value predefined in a list
1044         widget: The widget that will be used (select, radio)
1045 ]]--
1046 ListValue = class(AbstractValue)
1047
1048 function ListValue.__init__(self, ...)
1049         AbstractValue.__init__(self, ...)
1050         self.template  = "cbi/lvalue"
1051
1052         self.keylist = {}
1053         self.vallist = {}
1054         self.size   = 1
1055         self.widget = "select"
1056
1057         if not self.override_scheme
1058          and self.map:get_scheme(self.section.sectiontype, self.option) then
1059                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1060                 if self.value and vs.values and not self.override_values then
1061                         if self.rmempty or self.optional then
1062                                 self:value("")
1063                         end
1064                         for k, v in pairs(vs.values) do
1065                                 local deps = {}
1066                                 if not self.override_dependencies
1067                                  and vs.enum_depends and vs.enum_depends[k] then
1068                                         for i, dep in ipairs(vs.enum_depends[k]) do
1069                                                 table.insert(deps, _uvl_strip_remote_dependencies(dep))
1070                                         end
1071                                 end
1072                                 self:value(k, v, unpack(deps))
1073                         end
1074                 end
1075         end
1076 end
1077
1078 function ListValue.value(self, key, val, ...)
1079         if luci.util.contains(self.keylist, key) then
1080                 return
1081         end
1082
1083         val = val or key
1084         table.insert(self.keylist, tostring(key))
1085         table.insert(self.vallist, tostring(val))
1086
1087         for i, deps in ipairs({...}) do
1088                 table.insert(self.deps, {add = "-"..key, deps=deps})
1089         end
1090 end
1091
1092 function ListValue.validate(self, val)
1093         if luci.util.contains(self.keylist, val) then
1094                 return val
1095         else
1096                 return nil
1097         end
1098 end
1099
1100
1101
1102 --[[
1103 MultiValue - Multiple delimited values
1104         widget: The widget that will be used (select, checkbox)
1105         delimiter: The delimiter that will separate the values (default: " ")
1106 ]]--
1107 MultiValue = class(AbstractValue)
1108
1109 function MultiValue.__init__(self, ...)
1110         AbstractValue.__init__(self, ...)
1111         self.template = "cbi/mvalue"
1112
1113         self.keylist = {}
1114         self.vallist = {}
1115
1116         self.widget = "checkbox"
1117         self.delimiter = " "
1118 end
1119
1120 function MultiValue.render(self, ...)
1121         if self.widget == "select" and not self.size then
1122                 self.size = #self.vallist
1123         end
1124
1125         AbstractValue.render(self, ...)
1126 end
1127
1128 function MultiValue.value(self, key, val)
1129         if luci.util.contains(self.keylist, key) then
1130                 return
1131         end
1132
1133         val = val or key
1134         table.insert(self.keylist, tostring(key))
1135         table.insert(self.vallist, tostring(val))
1136 end
1137
1138 function MultiValue.valuelist(self, section)
1139         local val = self:cfgvalue(section)
1140
1141         if not(type(val) == "string") then
1142                 return {}
1143         end
1144
1145         return luci.util.split(val, self.delimiter)
1146 end
1147
1148 function MultiValue.validate(self, val)
1149         val = (type(val) == "table") and val or {val}
1150
1151         local result
1152
1153         for i, value in ipairs(val) do
1154                 if luci.util.contains(self.keylist, value) then
1155                         result = result and (result .. self.delimiter .. value) or value
1156                 end
1157         end
1158
1159         return result
1160 end
1161
1162
1163 StaticList = class(MultiValue)
1164
1165 function StaticList.__init__(self, ...)
1166         MultiValue.__init__(self, ...)
1167         self.cast = "table"
1168         self.valuelist = self.cfgvalue
1169
1170         if not self.override_scheme
1171          and self.map:get_scheme(self.section.sectiontype, self.option) then
1172                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1173                 if self.value and vs.values and not self.override_values then
1174                         for k, v in pairs(vs.values) do
1175                                 self:value(k, v)
1176                         end
1177                 end
1178         end
1179 end
1180
1181 function StaticList.validate(self, value)
1182         value = (type(value) == "table") and value or {value}
1183
1184         local valid = {}
1185         for i, v in ipairs(value) do
1186                 if luci.util.contains(self.valuelist, v) then
1187                         table.insert(valid, v)
1188                 end
1189         end
1190         return valid
1191 end
1192
1193
1194 DynamicList = class(AbstractValue)
1195
1196 function DynamicList.__init__(self, ...)
1197         AbstractValue.__init__(self, ...)
1198         self.template  = "cbi/dynlist"
1199         self.cast = "table"
1200         self.keylist = {}
1201         self.vallist = {}
1202 end
1203
1204 function DynamicList.value(self, key, val)
1205         val = val or key
1206         table.insert(self.keylist, tostring(key))
1207         table.insert(self.vallist, tostring(val))
1208 end
1209
1210 function DynamicList.validate(self, value, section)
1211         value = (type(value) == "table") and value or {value}
1212
1213         local valid = {}
1214         for i, v in ipairs(value) do
1215                 if v and #v > 0 and
1216                  not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) then
1217                         table.insert(valid, v)
1218                 end
1219         end
1220
1221         return valid
1222 end
1223
1224
1225 --[[
1226 TextValue - A multi-line value
1227         rows:   Rows
1228 ]]--
1229 TextValue = class(AbstractValue)
1230
1231 function TextValue.__init__(self, ...)
1232         AbstractValue.__init__(self, ...)
1233         self.template  = "cbi/tvalue"
1234 end
1235
1236 --[[
1237 Button
1238 ]]--
1239 Button = class(AbstractValue)
1240
1241 function Button.__init__(self, ...)
1242         AbstractValue.__init__(self, ...)
1243         self.template  = "cbi/button"
1244         self.inputstyle = nil
1245         self.rmempty = true
1246 end