5dd57e2e969aa17dd8a39b01389409d66877e5c6
[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 RESORT_PREFIX = "cbi.sts."
54 FEXIST_PREFIX = "cbi.cbe."
55
56 -- Loads a CBI map from given file, creating an environment and returns it
57 function load(cbimap, ...)
58         local fs   = require "nixio.fs"
59         local i18n = require "luci.i18n"
60         require("luci.config")
61         require("luci.util")
62
63         local upldir = "/lib/uci/upload/"
64         local cbidir = luci.util.libpath() .. "/model/cbi/"
65         local func, err
66
67         if fs.access(cbidir..cbimap..".lua") then
68                 func, err = loadfile(cbidir..cbimap..".lua")
69         elseif fs.access(cbimap) then
70                 func, err = loadfile(cbimap)
71         else
72                 func, err = nil, "Model '" .. cbimap .. "' not found!"
73         end
74
75         assert(func, err)
76
77         luci.i18n.loadc("base")
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
156 -- Node pseudo abstract class
157 Node = class()
158
159 function Node.__init__(self, title, description)
160         self.children = {}
161         self.title = title or ""
162         self.description = description or ""
163         self.template = "cbi/node"
164 end
165
166 -- hook helper
167 function Node._run_hook(self, hook)
168         if type(self[hook]) == "function" then
169                 return self[hook](self)
170         end
171 end
172
173 function Node._run_hooks(self, ...)
174         local f
175         local r = false
176         for _, f in ipairs(arg) do
177                 if type(self[f]) == "function" then
178                         self[f](self)
179                         r = true
180                 end
181         end
182         return r
183 end
184
185 -- Prepare nodes
186 function Node.prepare(self, ...)
187         for k, child in ipairs(self.children) do
188                 child:prepare(...)
189         end
190 end
191
192 -- Append child nodes
193 function Node.append(self, obj)
194         table.insert(self.children, obj)
195 end
196
197 -- Parse this node and its children
198 function Node.parse(self, ...)
199         for k, child in ipairs(self.children) do
200                 child:parse(...)
201         end
202 end
203
204 -- Render this node
205 function Node.render(self, scope)
206         scope = scope or {}
207         scope.self = self
208
209         luci.template.render(self.template, scope)
210 end
211
212 -- Render the children
213 function Node.render_children(self, ...)
214         for k, node in ipairs(self.children) do
215                 node:render(...)
216         end
217 end
218
219
220 --[[
221 A simple template element
222 ]]--
223 Template = class(Node)
224
225 function Template.__init__(self, template)
226         Node.__init__(self)
227         self.template = template
228 end
229
230 function Template.render(self)
231         luci.template.render(self.template, {self=self})
232 end
233
234 function Template.parse(self, readinput)
235         self.readinput = (readinput ~= false)
236         return Map.formvalue(self, "cbi.submit") and FORM_DONE or FORM_NODATA
237 end
238
239
240 --[[
241 Map - A map describing a configuration file
242 ]]--
243 Map = class(Node)
244
245 function Map.__init__(self, config, ...)
246         Node.__init__(self, ...)
247
248         self.config = config
249         self.parsechain = {self.config}
250         self.template = "cbi/map"
251         self.apply_on_parse = nil
252         self.readinput = true
253         self.proceed = false
254         self.flow = {}
255
256         self.uci = uci.cursor()
257         self.save = true
258
259         self.changed = false
260
261         if not self.uci:load(self.config) then
262                 error("Unable to read UCI data: " .. self.config)
263         end
264 end
265
266 function Map.formvalue(self, key)
267         return self.readinput and luci.http.formvalue(key)
268 end
269
270 function Map.formvaluetable(self, key)
271         return self.readinput and luci.http.formvaluetable(key) or {}
272 end
273
274 function Map.get_scheme(self, sectiontype, option)
275         if not option then
276                 return self.scheme and self.scheme.sections[sectiontype]
277         else
278                 return self.scheme and self.scheme.variables[sectiontype]
279                  and self.scheme.variables[sectiontype][option]
280         end
281 end
282
283 function Map.submitstate(self)
284         return self:formvalue("cbi.submit")
285 end
286
287 -- Chain foreign config
288 function Map.chain(self, config)
289         table.insert(self.parsechain, config)
290 end
291
292 function Map.state_handler(self, state)
293         return state
294 end
295
296 -- Use optimized UCI writing
297 function Map.parse(self, readinput, ...)
298         self.readinput = (readinput ~= false)
299         self:_run_hooks("on_parse")
300
301         if self:formvalue("cbi.skip") then
302                 self.state = FORM_SKIP
303                 return self:state_handler(self.state)
304         end
305
306         Node.parse(self, ...)
307
308         if self.save then
309                 self:_run_hooks("on_save", "on_before_save")
310                 for i, config in ipairs(self.parsechain) do
311                         self.uci:save(config)
312                 end
313                 self:_run_hooks("on_after_save")
314                 if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then
315                         self:_run_hooks("on_before_commit")
316                         for i, config in ipairs(self.parsechain) do
317                                 self.uci:commit(config)
318
319                                 -- Refresh data because commit changes section names
320                                 self.uci:load(config)
321                         end
322                         self:_run_hooks("on_commit", "on_after_commit", "on_before_apply")
323                         if self.apply_on_parse then
324                                 self.uci:apply(self.parsechain)
325                                 self:_run_hooks("on_apply", "on_after_apply")
326                         else
327                                 -- This is evaluated by the dispatcher and delegated to the
328                                 -- template which in turn fires XHR to perform the actual
329                                 -- apply actions.
330                                 self.apply_needed = true
331                         end
332
333                         -- Reparse sections
334                         Node.parse(self, true)
335
336                 end
337                 for i, config in ipairs(self.parsechain) do
338                         self.uci:unload(config)
339                 end
340                 if type(self.commit_handler) == "function" then
341                         self:commit_handler(self:submitstate())
342                 end
343         end
344
345         if self:submitstate() then
346                 if not self.save then
347                         self.state = FORM_INVALID
348                 elseif self.proceed then
349                         self.state = FORM_PROCEED
350                 else
351                         self.state = self.changed and FORM_CHANGED or FORM_VALID
352                 end
353         else
354                 self.state = FORM_NODATA
355         end
356
357         return self:state_handler(self.state)
358 end
359
360 function Map.render(self, ...)
361         self:_run_hooks("on_init")
362         Node.render(self, ...)
363 end
364
365 -- Creates a child section
366 function Map.section(self, class, ...)
367         if instanceof(class, AbstractSection) then
368                 local obj  = class(self, ...)
369                 self:append(obj)
370                 return obj
371         else
372                 error("class must be a descendent of AbstractSection")
373         end
374 end
375
376 -- UCI add
377 function Map.add(self, sectiontype)
378         return self.uci:add(self.config, sectiontype)
379 end
380
381 -- UCI set
382 function Map.set(self, section, option, value)
383         if type(value) ~= "table" or #value > 0 then
384                 if option then
385                         return self.uci:set(self.config, section, option, value)
386                 else
387                         return self.uci:set(self.config, section, value)
388                 end
389         else
390                 return Map.del(self, section, option)
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 self.sortable then
1127                 local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype
1128                 local order = self.map:formvalue(stval)
1129                 if order and #order > 0 then
1130                         local sid
1131                         local num = 0
1132                         for sid in util.imatch(order) do
1133                                 self.map.uci:reorder(self.config, sid, num)
1134                                 num = num + 1
1135                         end
1136                         self.changed = (num > 0)
1137                 end
1138         end
1139
1140         if created or self.changed then
1141                 self:push_events()
1142         end
1143 end
1144
1145 -- Verifies scope of sections
1146 function TypedSection.checkscope(self, section)
1147         -- Check if we are not excluded
1148         if self.filter and not self:filter(section) then
1149                 return nil
1150         end
1151
1152         -- Check if at least one dependency is met
1153         if #self.deps > 0 and self:cfgvalue(section) then
1154                 local stat = false
1155
1156                 for k, v in ipairs(self.deps) do
1157                         if self:cfgvalue(section)[v.option] == v.value then
1158                                 stat = true
1159                         end
1160                 end
1161
1162                 if not stat then
1163                         return nil
1164                 end
1165         end
1166
1167         return self:validate(section)
1168 end
1169
1170
1171 -- Dummy validate function
1172 function TypedSection.validate(self, section)
1173         return section
1174 end
1175
1176
1177 --[[
1178 AbstractValue - An abstract Value Type
1179         null:           Value can be empty
1180         valid:          A function returning the value if it is valid otherwise nil
1181         depends:        A table of option => value pairs of which one must be true
1182         default:        The default value
1183         size:           The size of the input fields
1184         rmempty:        Unset value if empty
1185         optional:       This value is optional (see AbstractSection.optionals)
1186 ]]--
1187 AbstractValue = class(Node)
1188
1189 function AbstractValue.__init__(self, map, section, option, ...)
1190         Node.__init__(self, ...)
1191         self.section = section
1192         self.option  = option
1193         self.map     = map
1194         self.config  = map.config
1195         self.tag_invalid = {}
1196         self.tag_missing = {}
1197         self.tag_reqerror = {}
1198         self.tag_error = {}
1199         self.deps = {}
1200         self.subdeps = {}
1201         --self.cast = "string"
1202
1203         self.track_missing = false
1204         self.rmempty   = true
1205         self.default   = nil
1206         self.size      = nil
1207         self.optional  = false
1208 end
1209
1210 function AbstractValue.prepare(self)
1211         self.cast = self.cast or "string"
1212 end
1213
1214 -- Add a dependencie to another section field
1215 function AbstractValue.depends(self, field, value)
1216         local deps
1217         if type(field) == "string" then
1218                 deps = {}
1219                 deps[field] = value
1220         else
1221                 deps = field
1222         end
1223
1224         table.insert(self.deps, {deps=deps, add=""})
1225 end
1226
1227 -- Generates the unique CBID
1228 function AbstractValue.cbid(self, section)
1229         return "cbid."..self.map.config.."."..section.."."..self.option
1230 end
1231
1232 -- Return whether this object should be created
1233 function AbstractValue.formcreated(self, section)
1234         local key = "cbi.opt."..self.config.."."..section
1235         return (self.map:formvalue(key) == self.option)
1236 end
1237
1238 -- Returns the formvalue for this object
1239 function AbstractValue.formvalue(self, section)
1240         return self.map:formvalue(self:cbid(section))
1241 end
1242
1243 function AbstractValue.additional(self, value)
1244         self.optional = value
1245 end
1246
1247 function AbstractValue.mandatory(self, value)
1248         self.rmempty = not value
1249 end
1250
1251 function AbstractValue.add_error(self, section, type, msg)
1252         self.error = self.error or { }
1253         self.error[section] = msg or type
1254
1255         self.section.error = self.section.error or { }
1256         self.section.error[section] = self.section.error[section] or { }
1257         table.insert(self.section.error[section], msg or type)
1258
1259         if type == "invalid" then
1260                 self.tag_invalid[section] = true
1261         elseif type == "missing" then
1262                 self.tag_missing[section] = true
1263         end
1264
1265         self.tag_error[section] = true
1266         self.map.save = false
1267 end
1268
1269 function AbstractValue.parse(self, section, novld)
1270         local fvalue = self:formvalue(section)
1271         local cvalue = self:cfgvalue(section)
1272
1273         -- If favlue and cvalue are both tables and have the same content
1274         -- make them identical
1275         if type(fvalue) == "table" and type(cvalue) == "table" then
1276                 local equal = #fvalue == #cvalue
1277                 if equal then
1278                         for i=1, #fvalue do
1279                                 if cvalue[i] ~= fvalue[i] then
1280                                         equal = false
1281                                 end
1282                         end
1283                 end
1284                 if equal then
1285                         fvalue = cvalue
1286                 end
1287         end
1288
1289         if fvalue and #fvalue > 0 then -- If we have a form value, write it to UCI
1290                 local val_err
1291                 fvalue, val_err = self:validate(fvalue, section)
1292                 fvalue = self:transform(fvalue)
1293
1294                 if not fvalue and not novld then
1295                         self:add_error(section, "invalid", val_err)
1296                 end
1297
1298                 if fvalue and (self.forcewrite or 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                         -- trigger validator with nil value to get custom user error msg.
1314                         local _, val_err = self:validate(nil, section)
1315                         self:add_error(section, "missing", val_err)
1316                 end
1317         end
1318 end
1319
1320 -- Render if this value exists or if it is mandatory
1321 function AbstractValue.render(self, s, scope)
1322         if not self.optional or self.section:has_tabs() or self:cfgvalue(s) or self:formcreated(s) then
1323                 scope = scope or {}
1324                 scope.section   = s
1325                 scope.cbid      = self:cbid(s)
1326                 scope.striptags = luci.util.striptags
1327                 scope.pcdata    = luci.util.pcdata
1328
1329                 scope.ifattr = function(cond,key,val)
1330                         if cond then
1331                                 return string.format(
1332                                         ' %s="%s"', tostring(key),
1333                                         luci.util.pcdata(tostring( val
1334                                          or scope[key]
1335                                          or (type(self[key]) ~= "function" and self[key])
1336                                          or "" ))
1337                                 )
1338                         else
1339                                 return ''
1340                         end
1341                 end
1342
1343                 scope.attr = function(...)
1344                         return scope.ifattr( true, ... )
1345                 end
1346
1347                 Node.render(self, scope)
1348         end
1349 end
1350
1351 -- Return the UCI value of this object
1352 function AbstractValue.cfgvalue(self, section)
1353         local value
1354         if self.tag_error[section] then
1355                 value = self:formvalue(section)
1356         else
1357                 value = self.map:get(section, self.option)
1358         end
1359
1360         if not value then
1361                 return nil
1362         elseif not self.cast or self.cast == type(value) then
1363                 return value
1364         elseif self.cast == "string" then
1365                 if type(value) == "table" then
1366                         return value[1]
1367                 end
1368         elseif self.cast == "table" then
1369                 return { value }
1370         end
1371 end
1372
1373 -- Validate the form value
1374 function AbstractValue.validate(self, value)
1375         if self.datatype and value then
1376                 local args = { }
1377                 local dt, ar = self.datatype:match("^(%w+)%(([^%(%)]+)%)")
1378
1379                 if dt and ar then
1380                         local a
1381                         for a in ar:gmatch("[^%s,]+") do
1382                                 args[#args+1] = a
1383                         end
1384                 else
1385                         dt = self.datatype
1386                 end
1387
1388                 if dt and datatypes[dt] then
1389                         if type(value) == "table" then
1390                                 local v
1391                                 for _, v in ipairs(value) do
1392                                         if v and #v > 0 and not datatypes[dt](v, unpack(args)) then
1393                                                 return nil
1394                                         end
1395                                 end
1396                         else
1397                                 if not datatypes[dt](value, unpack(args)) then
1398                                         return nil
1399                                 end
1400                         end
1401                 end
1402         end
1403
1404         return value
1405 end
1406
1407 AbstractValue.transform = AbstractValue.validate
1408
1409
1410 -- Write to UCI
1411 function AbstractValue.write(self, section, value)
1412         return self.map:set(section, self.option, value)
1413 end
1414
1415 -- Remove from UCI
1416 function AbstractValue.remove(self, section)
1417         return self.map:del(section, self.option)
1418 end
1419
1420
1421
1422
1423 --[[
1424 Value - A one-line value
1425         maxlength:      The maximum length
1426 ]]--
1427 Value = class(AbstractValue)
1428
1429 function Value.__init__(self, ...)
1430         AbstractValue.__init__(self, ...)
1431         self.template  = "cbi/value"
1432         self.keylist = {}
1433         self.vallist = {}
1434 end
1435
1436 function Value.reset_values(self)
1437         self.keylist = {}
1438         self.vallist = {}
1439 end
1440
1441 function Value.value(self, key, val)
1442         val = val or key
1443         table.insert(self.keylist, tostring(key))
1444         table.insert(self.vallist, tostring(val))
1445 end
1446
1447
1448 -- DummyValue - This does nothing except being there
1449 DummyValue = class(AbstractValue)
1450
1451 function DummyValue.__init__(self, ...)
1452         AbstractValue.__init__(self, ...)
1453         self.template = "cbi/dvalue"
1454         self.value = nil
1455 end
1456
1457 function DummyValue.cfgvalue(self, section)
1458         local value
1459         if self.value then
1460                 if type(self.value) == "function" then
1461                         value = self:value(section)
1462                 else
1463                         value = self.value
1464                 end
1465         else
1466                 value = AbstractValue.cfgvalue(self, section)
1467         end
1468         return value
1469 end
1470
1471 function DummyValue.parse(self)
1472
1473 end
1474
1475
1476 --[[
1477 Flag - A flag being enabled or disabled
1478 ]]--
1479 Flag = class(AbstractValue)
1480
1481 function Flag.__init__(self, ...)
1482         AbstractValue.__init__(self, ...)
1483         self.template  = "cbi/fvalue"
1484
1485         self.enabled  = "1"
1486         self.disabled = "0"
1487         self.default  = self.disabled
1488 end
1489
1490 -- A flag can only have two states: set or unset
1491 function Flag.parse(self, section)
1492         local fexists = self.map:formvalue(
1493                 FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
1494
1495         if fexists then
1496                 local fvalue = self:formvalue(section) and self.enabled or self.disabled
1497                 if fvalue ~= self.default or (not self.optional and not self.rmempty) then
1498                         self:write(section, fvalue)
1499                 else
1500                         self:remove(section)
1501                 end
1502         else
1503                 self:remove(section)
1504         end
1505 end
1506
1507 function Flag.cfgvalue(self, section)
1508         return AbstractValue.cfgvalue(self, section) or self.default
1509 end
1510
1511
1512 --[[
1513 ListValue - A one-line value predefined in a list
1514         widget: The widget that will be used (select, radio)
1515 ]]--
1516 ListValue = class(AbstractValue)
1517
1518 function ListValue.__init__(self, ...)
1519         AbstractValue.__init__(self, ...)
1520         self.template  = "cbi/lvalue"
1521
1522         self.keylist = {}
1523         self.vallist = {}
1524         self.size   = 1
1525         self.widget = "select"
1526 end
1527
1528 function ListValue.reset_values(self)
1529         self.keylist = {}
1530         self.vallist = {}
1531 end
1532
1533 function ListValue.value(self, key, val, ...)
1534         if luci.util.contains(self.keylist, key) then
1535                 return
1536         end
1537
1538         val = val or key
1539         table.insert(self.keylist, tostring(key))
1540         table.insert(self.vallist, tostring(val))
1541
1542         for i, deps in ipairs({...}) do
1543                 self.subdeps[#self.subdeps + 1] = {add = "-"..key, deps=deps}
1544         end
1545 end
1546
1547 function ListValue.validate(self, val)
1548         if luci.util.contains(self.keylist, val) then
1549                 return val
1550         else
1551                 return nil
1552         end
1553 end
1554
1555
1556
1557 --[[
1558 MultiValue - Multiple delimited values
1559         widget: The widget that will be used (select, checkbox)
1560         delimiter: The delimiter that will separate the values (default: " ")
1561 ]]--
1562 MultiValue = class(AbstractValue)
1563
1564 function MultiValue.__init__(self, ...)
1565         AbstractValue.__init__(self, ...)
1566         self.template = "cbi/mvalue"
1567
1568         self.keylist = {}
1569         self.vallist = {}
1570
1571         self.widget = "checkbox"
1572         self.delimiter = " "
1573 end
1574
1575 function MultiValue.render(self, ...)
1576         if self.widget == "select" and not self.size then
1577                 self.size = #self.vallist
1578         end
1579
1580         AbstractValue.render(self, ...)
1581 end
1582
1583 function MultiValue.reset_values(self)
1584         self.keylist = {}
1585         self.vallist = {}
1586 end
1587
1588 function MultiValue.value(self, key, val)
1589         if luci.util.contains(self.keylist, key) then
1590                 return
1591         end
1592
1593         val = val or key
1594         table.insert(self.keylist, tostring(key))
1595         table.insert(self.vallist, tostring(val))
1596 end
1597
1598 function MultiValue.valuelist(self, section)
1599         local val = self:cfgvalue(section)
1600
1601         if not(type(val) == "string") then
1602                 return {}
1603         end
1604
1605         return luci.util.split(val, self.delimiter)
1606 end
1607
1608 function MultiValue.validate(self, val)
1609         val = (type(val) == "table") and val or {val}
1610
1611         local result
1612
1613         for i, value in ipairs(val) do
1614                 if luci.util.contains(self.keylist, value) then
1615                         result = result and (result .. self.delimiter .. value) or value
1616                 end
1617         end
1618
1619         return result
1620 end
1621
1622
1623 StaticList = class(MultiValue)
1624
1625 function StaticList.__init__(self, ...)
1626         MultiValue.__init__(self, ...)
1627         self.cast = "table"
1628         self.valuelist = self.cfgvalue
1629
1630         if not self.override_scheme
1631          and self.map:get_scheme(self.section.sectiontype, self.option) then
1632                 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1633                 if self.value and vs.values and not self.override_values then
1634                         for k, v in pairs(vs.values) do
1635                                 self:value(k, v)
1636                         end
1637                 end
1638         end
1639 end
1640
1641 function StaticList.validate(self, value)
1642         value = (type(value) == "table") and value or {value}
1643
1644         local valid = {}
1645         for i, v in ipairs(value) do
1646                 if luci.util.contains(self.keylist, v) then
1647                         table.insert(valid, v)
1648                 end
1649         end
1650         return valid
1651 end
1652
1653
1654 DynamicList = class(AbstractValue)
1655
1656 function DynamicList.__init__(self, ...)
1657         AbstractValue.__init__(self, ...)
1658         self.template  = "cbi/dynlist"
1659         self.cast = "table"
1660         self.keylist = {}
1661         self.vallist = {}
1662 end
1663
1664 function DynamicList.reset_values(self)
1665         self.keylist = {}
1666         self.vallist = {}
1667 end
1668
1669 function DynamicList.value(self, key, val)
1670         val = val or key
1671         table.insert(self.keylist, tostring(key))
1672         table.insert(self.vallist, tostring(val))
1673 end
1674
1675 function DynamicList.write(self, section, value)
1676         local t = { }
1677
1678         if type(value) == "table" then
1679                 local x
1680                 for _, x in ipairs(value) do
1681                         if x and #x > 0 then
1682                                 t[#t+1] = x
1683                         end
1684                 end
1685         else
1686                 t = { value }
1687         end
1688
1689         if self.cast == "string" then
1690                 value = table.concat(t, " ")
1691         else
1692                 value = t
1693         end
1694
1695         return AbstractValue.write(self, section, value)
1696 end
1697
1698 function DynamicList.cfgvalue(self, section)
1699         local value = AbstractValue.cfgvalue(self, section)
1700
1701         if type(value) == "string" then
1702                 local x
1703                 local t = { }
1704                 for x in value:gmatch("%S+") do
1705                         if #x > 0 then
1706                                 t[#t+1] = x
1707                         end
1708                 end
1709                 value = t
1710         end
1711
1712         return value
1713 end
1714
1715 function DynamicList.formvalue(self, section)
1716         local value = AbstractValue.formvalue(self, section)
1717
1718         if type(value) == "string" then
1719                 if self.cast == "string" then
1720                         local x
1721                         local t = { }
1722                         for x in value:gmatch("%S+") do
1723                                 t[#t+1] = x
1724                         end
1725                         value = t
1726                 else
1727                         value = { value }
1728                 end
1729         end
1730
1731         return value
1732 end
1733
1734
1735 --[[
1736 TextValue - A multi-line value
1737         rows:   Rows
1738 ]]--
1739 TextValue = class(AbstractValue)
1740
1741 function TextValue.__init__(self, ...)
1742         AbstractValue.__init__(self, ...)
1743         self.template  = "cbi/tvalue"
1744 end
1745
1746 --[[
1747 Button
1748 ]]--
1749 Button = class(AbstractValue)
1750
1751 function Button.__init__(self, ...)
1752         AbstractValue.__init__(self, ...)
1753         self.template  = "cbi/button"
1754         self.inputstyle = nil
1755         self.rmempty = true
1756 end
1757
1758
1759 FileUpload = class(AbstractValue)
1760
1761 function FileUpload.__init__(self, ...)
1762         AbstractValue.__init__(self, ...)
1763         self.template = "cbi/upload"
1764         if not self.map.upload_fields then
1765                 self.map.upload_fields = { self }
1766         else
1767                 self.map.upload_fields[#self.map.upload_fields+1] = self
1768         end
1769 end
1770
1771 function FileUpload.formcreated(self, section)
1772         return AbstractValue.formcreated(self, section) or
1773                 self.map:formvalue("cbi.rlf."..section.."."..self.option) or
1774                 self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1775 end
1776
1777 function FileUpload.cfgvalue(self, section)
1778         local val = AbstractValue.cfgvalue(self, section)
1779         if val and fs.access(val) then
1780                 return val
1781         end
1782         return nil
1783 end
1784
1785 function FileUpload.formvalue(self, section)
1786         local val = AbstractValue.formvalue(self, section)
1787         if val then
1788                 if not self.map:formvalue("cbi.rlf."..section.."."..self.option) and
1789                    not self.map:formvalue("cbi.rlf."..section.."."..self.option..".x")
1790                 then
1791                         return val
1792                 end
1793                 fs.unlink(val)
1794                 self.value = nil
1795         end
1796         return nil
1797 end
1798
1799 function FileUpload.remove(self, section)
1800         local val = AbstractValue.formvalue(self, section)
1801         if val and fs.access(val) then fs.unlink(val) end
1802         return AbstractValue.remove(self, section)
1803 end
1804
1805
1806 FileBrowser = class(AbstractValue)
1807
1808 function FileBrowser.__init__(self, ...)
1809         AbstractValue.__init__(self, ...)
1810         self.template = "cbi/browser"
1811 end