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