6d871573413a0cf698b9fdad7830c89a98fcb3ef
[project/luci.git] / libs / web / luasrc / cbi / datatypes.lua
1 --[[
2
3 LuCI - Configuration Bind Interface - Datatype Tests
4 (c) 2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 local fs = require "nixio.fs"
17 local ip = require "luci.ip"
18 local math = require "math"
19 local util = require "luci.util"
20 local tonumber, type, unpack, select = tonumber, type, unpack, select
21
22
23 module "luci.cbi.datatypes"
24
25
26 _M['or'] = function(v, ...)
27         local i
28         for i = 1, select('#', ...), 2 do
29                 local f = select(i, ...)
30                 local a = select(i+1, ...)
31                 if type(f) ~= "function" then
32                         print("COMP", f, v)
33                         if f == v then
34                                 return true
35                         end
36                         i = i - 1
37                 elseif f(v, unpack(a)) then
38                         return true
39                 end
40         end
41         return false
42 end
43
44 _M['and'] = function(v, ...)
45         local i
46         for i = 1, select('#', ...), 2 do
47                 local f = select(i, ...)
48                 local a = select(i+1, ...)
49                 if type(f) ~= "function" then
50                         if f ~= v then
51                                 return false
52                         end
53                         i = i - 1
54                 elseif not f(v, unpack(a)) then
55                         return false
56                 end
57         end
58         return true
59 end
60
61 function neg(v, ...)
62         return _M['or'](v:gsub("^%s*!%s*", ""), ...)
63 end
64
65 function list(v, subvalidator, subargs)
66         if type(subvalidator) ~= "function" then
67                 return false
68         end
69         local token
70         for token in v:gmatch("%S+") do
71                 if not subvalidator(token, unpack(subargs)) then
72                         return false
73                 end
74         end
75         return true
76 end
77
78 function bool(val)
79         if val == "1" or val == "yes" or val == "on" or val == "true" then
80                 return true
81         elseif val == "0" or val == "no" or val == "off" or val == "false" then
82                 return true
83         elseif val == "" or val == nil then
84                 return true
85         end
86
87         return false
88 end
89
90 function uinteger(val)
91         local n = tonumber(val)
92         if n ~= nil and math.floor(n) == n and n >= 0 then
93                 return true
94         end
95
96         return false
97 end
98
99 function integer(val)
100         local n = tonumber(val)
101         if n ~= nil and math.floor(n) == n then
102                 return true
103         end
104
105         return false
106 end
107
108 function ufloat(val)
109         local n = tonumber(val)
110         return ( n ~= nil and n >= 0 )
111 end
112
113 function float(val)
114         return ( tonumber(val) ~= nil )
115 end
116
117 function ipaddr(val)
118         return ip4addr(val) or ip6addr(val)
119 end
120
121 function ip4addr(val)
122         if val then
123                 return ip.IPv4(val) and true or false
124         end
125
126         return false
127 end
128
129 function ip4prefix(val)
130         val = tonumber(val)
131         return ( val and val >= 0 and val <= 32 )
132 end
133
134 function ip6addr(val)
135         if val then
136                 return ip.IPv6(val) and true or false
137         end
138
139         return false
140 end
141
142 function ip6prefix(val)
143         val = tonumber(val)
144         return ( val and val >= 0 and val <= 128 )
145 end
146
147 function port(val)
148         val = tonumber(val)
149         return ( val and val >= 0 and val <= 65535 )
150 end
151
152 function portrange(val)
153         local p1, p2 = val:match("^(%d+)%-(%d+)$")
154         if p1 and p2 and port(p1) and port(p2) then
155                 return true
156         else
157                 return port(val)
158         end
159 end
160
161 function macaddr(val)
162         if val and val:match(
163                 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
164                  "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
165         ) then
166                 local parts = util.split( val, ":" )
167
168                 for i = 1,6 do
169                         parts[i] = tonumber( parts[i], 16 )
170                         if parts[i] < 0 or parts[i] > 255 then
171                                 return false
172                         end
173                 end
174
175                 return true
176         end
177
178         return false
179 end
180
181 function hostname(val)
182         if val and (#val < 254) and (
183            val:match("^[a-zA-Z]+$") or
184            (val:match("^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$") and
185             val:match("[^0-9%.]"))
186         ) then
187                 return true
188         end
189         return false
190 end
191
192 function host(val)
193         return hostname(val) or ipaddr(val)
194 end
195
196 function network(val)
197         return uciname(val) or host(val)
198 end
199
200 function wpakey(val)
201         if #val == 64 then
202                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
203         else
204                 return (#val >= 8) and (#val <= 63)
205         end
206 end
207
208 function wepkey(val)
209         if val:sub(1, 2) == "s:" then
210                 val = val:sub(3)
211         end
212
213         if (#val == 10) or (#val == 26) then
214                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
215         else
216                 return (#val == 5) or (#val == 13)
217         end
218 end
219
220 function string(val)
221         return true             -- Everything qualifies as valid string
222 end
223
224 function directory( val, seen )
225         local s = fs.stat(val)
226         seen = seen or { }
227
228         if s and not seen[s.ino] then
229                 seen[s.ino] = true
230                 if s.type == "dir" then
231                         return true
232                 elseif s.type == "lnk" then
233                         return directory( fs.readlink(val), seen )
234                 end
235         end
236
237         return false
238 end
239
240 function file( val, seen )
241         local s = fs.stat(val)
242         seen = seen or { }
243
244         if s and not seen[s.ino] then
245                 seen[s.ino] = true
246                 if s.type == "reg" then
247                         return true
248                 elseif s.type == "lnk" then
249                         return file( fs.readlink(val), seen )
250                 end
251         end
252
253         return false
254 end
255
256 function device( val, seen )
257         local s = fs.stat(val)
258         seen = seen or { }
259
260         if s and not seen[s.ino] then
261                 seen[s.ino] = true
262                 if s.type == "chr" or s.type == "blk" then
263                         return true
264                 elseif s.type == "lnk" then
265                         return device( fs.readlink(val), seen )
266                 end
267         end
268
269         return false
270 end
271
272 function uciname(val)
273         return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
274 end
275
276 function range(val, min, max)
277         val = tonumber(val)
278         min = tonumber(min)
279         max = tonumber(max)
280
281         if val ~= nil and min ~= nil and max ~= nil then
282                 return ((val >= min) and (val <= max))
283         end
284
285         return false
286 end
287
288 function min(val, min)
289         val = tonumber(val)
290         min = tonumber(min)
291
292         if val ~= nil and min ~= nil then
293                 return (val >= min)
294         end
295
296         return false
297 end
298
299 function max(val, max)
300         val = tonumber(val)
301         max = tonumber(max)
302
303         if val ~= nil and max ~= nil then
304                 return (val <= max)
305         end
306
307         return false
308 end