8cede198c5615f82b7f54524a6b95d5d496c2532
[project/luci.git] / applications / luci-pbx / luasrc / model / cbi / pbx-calls.lua
1 --[[
2 Copyright 2011 Iordan Iordanov <iiordanov (AT) gmail.com>
3
4 This file is part of luci-pbx.
5
6 luci-pbx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 luci-pbx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with luci-pbx. If not, see <http://www.gnu.org/licenses/>.
18 ]]--
19
20 if nixio.fs.access("/etc/init.d/asterisk") then
21 server = "asterisk"
22 elseif nixio.fs.access("/etc/init.d/freeswitch") then
23 server = "freeswitch"
24 else
25 server = ""
26 end
27
28 modulename = "pbx-calls"
29 voipmodulename = "pbx-voip"
30 googlemodulename = "pbx-google"
31 usersmodulename = "pbx-users"
32 allvalidaccounts = {}
33 nallvalidaccounts = 0
34 validoutaccounts = {}
35 nvalidoutaccounts = 0
36 validinaccounts = {}
37 nvalidinaccounts = 0
38 allvalidusers = {}
39 nallvalidusers = 0
40 validoutusers = {}
41 nvalidoutusers = 0
42
43
44 -- Checks whether the entered extension is valid syntactically.
45 function is_valid_extension(exten)
46 return (exten:match("[#*+0-9NXZ]+$") ~= nil)
47 end
48
49
50 m = Map (modulename, translate("Call Routing"),
51 translate("This is where you indicate which Google/SIP accounts are used to call what \
52 country/area codes, which users can use what SIP/Google accounts, how incoming \
53 calls are routed, what numbers can get into this PBX with a password, and what \
54 numbers are blacklisted."))
55
56 -- Recreate the config, and restart services after changes are commited to the configuration.
57 function m.on_after_commit(self)
58 luci.sys.call("/etc/init.d/pbx-" .. server .. " restart 1\>/dev/null 2\>/dev/null")
59 luci.sys.call("/etc/init.d/" .. server .. " restart 1\>/dev/null 2\>/dev/null")
60 end
61
62 -- Add Google accounts to all valid accounts, and accounts valid for incoming and outgoing calls.
63 m.uci:foreach(googlemodulename, "gtalk_jabber",
64 function(s1)
65 -- Add this provider to list of valid accounts.
66 if s1.username ~= nil and s1.name ~= nil then
67 allvalidaccounts[s1.name] = s1.username
68 nallvalidaccounts = nallvalidaccounts + 1
69
70 if s1.make_outgoing_calls == "yes" then
71 -- Add provider to the associative array of valid outgoing accounts.
72 validoutaccounts[s1.name] = s1.username
73 nvalidoutaccounts = nvalidoutaccounts + 1
74 end
75
76 if s1.register == "yes" then
77 -- Add provider to the associative array of valid outgoing accounts.
78 validinaccounts[s1.name] = s1.username
79 nvalidinaccounts = nvalidinaccounts + 1
80 end
81 end
82 end)
83
84 -- Add SIP accounts to all valid accounts, and accounts valid for incoming and outgoing calls.
85 m.uci:foreach(voipmodulename, "voip_provider",
86 function(s1)
87 -- Add this provider to list of valid accounts.
88 if s1.defaultuser ~= nil and s1.host ~= nil and s1.name ~= nil then
89 allvalidaccounts[s1.name] = s1.defaultuser .. "@" .. s1.host
90 nallvalidaccounts = nallvalidaccounts + 1
91
92 if s1.make_outgoing_calls == "yes" then
93 -- Add provider to the associative array of valid outgoing accounts.
94 validoutaccounts[s1.name] = s1.defaultuser .. "@" .. s1.host
95 nvalidoutaccounts = nvalidoutaccounts + 1
96 end
97
98 if s1.register == "yes" then
99 -- Add provider to the associative array of valid outgoing accounts.
100 validinaccounts[s1.name] = s1.defaultuser .. "@" .. s1.host
101 nvalidinaccounts = nvalidinaccounts + 1
102 end
103 end
104 end)
105
106 -- Add Local User accounts to all valid users, and users allowed to make outgoing calls.
107 m.uci:foreach(usersmodulename, "local_user",
108 function(s1)
109 -- Add user to list of all valid users.
110 if s1.defaultuser ~= nil then
111 allvalidusers[s1.defaultuser] = true
112 nallvalidusers = nallvalidusers + 1
113
114 if s1.can_call == "yes" then
115 validoutusers[s1.defaultuser] = true
116 nvalidoutusers = nvalidoutusers + 1
117 end
118 end
119 end)
120
121
122 ----------------------------------------------------------------------------------------------------
123 -- If there are no accounts configured, or no accounts enabled for outgoing calls, display a warning.
124 -- Otherwise, display the usual help text within the section.
125 if nallvalidaccounts == 0 then
126 text = translate("NOTE: There are no Google or SIP provider accounts configured.")
127 elseif nvalidoutaccounts == 0 then
128 text = translate("NOTE: There are no Google or SIP provider accounts enabled for outgoing calls.")
129 else
130 text = translate("If you have more than one account that can make outgoing calls, you \
131 should enter a list of phone numbers and prefixes in the following fields for each \
132 provider listed. Invalid prefixes are removed silently, and only 0-9, X, Z, N, #, *, \
133 and + are valid characters. The letter X matches 0-9, Z matches 1-9, and N matches 2-9. \
134 For example to make calls to Germany through a provider, you can enter 49. To make calls \
135 to North America, you can enter 1NXXNXXXXXX. If one of your providers can make \"local\" \
136 calls to an area code like New York's 646, you can enter 646NXXXXXX for that \
137 provider. You should leave one account with an empty list to make calls with \
138 it by default, if no other provider's prefixes match. The system will automatically \
139 replace an empty list with a message that the provider dials all numbers. Be as specific as \
140 possible (i.e. 1NXXNXXXXXX is better than 1). Please note all international dial codes \
141 are discarded (e.g. 00, 011, 010, 0011). Entries can be made in a space-separated \
142 list, and/or one per line by hitting enter after every one.")
143 end
144
145
146 s = m:section(NamedSection, "outgoing_calls", "call_routing", translate("Outgoing Calls"), text)
147 s.anonymous = true
148
149 for k,v in pairs(validoutaccounts) do
150 patterns = s:option(DynamicList, k, v)
151
152 -- If the saved field is empty, we return a string
153 -- telling the user that this account would dial any exten.
154 function patterns.cfgvalue(self, section)
155 value = self.map:get(section, self.option)
156
157 if value == nil then
158 return {translate("Used for numbers unmatched elsewhere")}
159 else
160 return value
161 end
162 end
163
164 -- Write only valid extensions into the config file.
165 function patterns.write(self, section, value)
166 newvalue = {}
167 nindex = 1
168 for index, field in ipairs(value) do
169 val = luci.util.trim(value[index])
170 if is_valid_extension(val) == true then
171 newvalue[nindex] = val
172 nindex = nindex + 1
173 end
174 end
175 DynamicList.write(self, section, newvalue)
176 end
177 end
178
179 ----------------------------------------------------------------------------------------------------
180 -- If there are no accounts configured, or no accounts enabled for incoming calls, display a warning.
181 -- Otherwise, display the usual help text within the section.
182 if nallvalidaccounts == 0 then
183 text = translate("NOTE: There are no Google or SIP provider accounts configured.")
184 elseif nvalidinaccounts == 0 then
185 text = translate("NOTE: There are no Google or SIP provider accounts enabled for incoming calls.")
186 else
187 text = translate("For each provider enabled for incoming calls, here you can restrict which users to\
188 ring on incoming calls. If the list is empty, the system will indicate that all users \
189 enabled for incoming calls will ring. Invalid usernames will be rejected \
190 silently. Also, entering a username here overrides the user's setting to not receive \
191 incoming calls. This way, you can make certain users ring only for specific providers. \
192 Entries can be made in a space-separated list, and/or one per line by hitting enter after \
193 every one.")
194 end
195
196
197 s = m:section(NamedSection, "incoming_calls", "call_routing", translate("Incoming Calls"), text)
198 s.anonymous = true
199
200 for k,v in pairs(validinaccounts) do
201 users = s:option(DynamicList, k, v)
202
203 -- If the saved field is empty, we return a string
204 -- telling the user that this account would dial any exten.
205 function users.cfgvalue(self, section)
206 value = self.map:get(section, self.option)
207
208 if value == nil then
209 return {translate("All users enabled for incoming calls")}
210 else
211 return value
212 end
213 end
214
215 -- Write only valid user names.
216 function users.write(self, section, value)
217 newvalue = {}
218 nindex = 1
219 for index, field in ipairs(value) do
220 trimuser = luci.util.trim(value[index])
221 if allvalidusers[trimuser] == true then
222 newvalue[nindex] = trimuser
223 nindex = nindex + 1
224 end
225 end
226 DynamicList.write(self, section, newvalue)
227 end
228 end
229
230
231 ----------------------------------------------------------------------------------------------------
232 -- If there are no user accounts configured, no user accounts enabled for outgoing calls,
233 -- display a warning. Otherwise, display the usual help text within the section.
234 if nallvalidusers == 0 then
235 text = translate("NOTE: There are no local user accounts configured.")
236 elseif nvalidoutusers == 0 then
237 text = translate("NOTE: There are no local user accounts enabled for outgoing calls.")
238 else
239 text = translate("For each user enabled for outgoing calls you can restrict what providers the user \
240 can use for outgoing calls. By default all users can use all providers. To show up in the list \
241 below the user should be allowed to make outgoing calls in the \"User Accounts\" page. Enter VoIP \
242 providers in the format username@some.host.name, as listed in \"Outgoing Calls\" above. It's \
243 easiest to copy and paste the providers from above. Invalid entries, including providers not \
244 enabled for outgoing calls, will be rejected silently. Entries can be made in a space-separated \
245 list, and/or one per line by hitting enter after every one.")
246 end
247
248
249 s = m:section(NamedSection, "providers_user_can_use", "call_routing",
250 translate("Providers Used for Outgoing Calls"), text)
251 s.anonymous = true
252
253 for k,v in pairs(validoutusers) do
254 providers = s:option(DynamicList, k, k)
255
256 -- If the saved field is empty, we return a string
257 -- telling the user that this account would dial any exten.
258 function providers.cfgvalue(self, section)
259 value = self.map:get(section, self.option)
260
261 if value == nil then
262 return {translate("All providers enabled for outgoing calls")}
263 else
264 newvalue = {}
265 -- Convert internal names to user@host values.
266 for i,v in ipairs(value) do
267 newvalue[i] = validoutaccounts[v]
268 end
269 return newvalue
270 end
271 end
272
273 -- Cook the new values prior to entering them into the config file.
274 -- Also, enter them only if they are valid.
275 function providers.write(self, section, value)
276 cookedvalue = {}
277 cindex = 1
278 for index, field in ipairs(value) do
279 cooked = string.gsub(luci.util.trim(value[index]), "%W", "_")
280 if validoutaccounts[cooked] ~= nil then
281 cookedvalue[cindex] = cooked
282 cindex = cindex + 1
283 end
284 end
285 DynamicList.write(self, section, cookedvalue)
286 end
287 end
288
289 ----------------------------------------------------------------------------------------------------
290 s = m:section(TypedSection, "callthrough_numbers", translate("Call-through Numbers"),
291 translate("Designate numbers that are allowed to call through this system and which user's \
292 privileges it will have."))
293 s.anonymous = true
294 s.addremove = true
295
296 num = s:option(DynamicList, "callthrough_number_list", translate("Call-through Numbers"))
297 num.datatype = "uinteger"
298
299 p = s:option(ListValue, "enabled", translate("Enabled"))
300 p:value("yes", translate("Yes"))
301 p:value("no", translate("No"))
302 p.default = "yes"
303
304 user = s:option(Value, "defaultuser", translate("User Name"),
305 translate("The number(s) specified above will be able to dial out with this user's providers. \
306 Invalid usernames, including users not enabled for outgoing calls, are dropped silently. \
307 Please verify that the entry was accepted."))
308 function user.write(self, section, value)
309 trimuser = luci.util.trim(value)
310 if allvalidusers[trimuser] == true then
311 Value.write(self, section, trimuser)
312 end
313 end
314
315 pwd = s:option(Value, "pin", translate("PIN"),
316 translate("Your PIN disappears when saved for your protection. It will be changed \
317 only when you enter a value different from the saved one. Leaving the PIN \
318 empty is possible, but please beware of the security implications."))
319 pwd.password = true
320 pwd.rmempty = false
321
322 -- We skip reading off the saved value and return nothing.
323 function pwd.cfgvalue(self, section)
324 return ""
325 end
326
327 -- We check the entered value against the saved one, and only write if the entered value is
328 -- something other than the empty string, and it differes from the saved value.
329 function pwd.write(self, section, value)
330 local orig_pwd = m:get(section, self.option)
331 if value and #value > 0 and orig_pwd ~= value then
332 Value.write(self, section, value)
333 end
334 end
335
336 ----------------------------------------------------------------------------------------------------
337 s = m:section(NamedSection, "blacklisting", "call_routing", translate("Blacklisted Numbers"),
338 translate("Enter phone numbers that you want to decline calls from automatically. \
339 You should probably omit the country code and any leading zeroes, but please \
340 experiment to make sure you are blocking numbers from your desired area successfully."))
341 s.anonymous = true
342
343 b = s:option(DynamicList, "blacklist1", translate("Dynamic List of Blacklisted Numbers"),
344 translate("Specify numbers individually here. Press enter to add more numbers."))
345 b.cast = "string"
346 b.datatype = "uinteger"
347
348 b = s:option(Value, "blacklist2", translate("Space-Separated List of Blacklisted Numbers"),
349 translate("Copy-paste large lists of numbers here."))
350 b.template = "cbi/tvalue"
351 b.rows = 3
352
353 return m