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