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