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