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