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