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