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