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