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