2 Copyright 2011 Iordan Iordanov <iiordanov (AT) gmail.com>
4 This file is part of luci-pbx.
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.
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.
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/>.
20 if nixio.fs.access("/etc/init.d/asterisk") then
22 elseif nixio.fs.access("/etc/init.d/freeswitch") then
28 modulename = "pbx-calls"
29 voipmodulename = "pbx-voip"
30 googlemodulename = "pbx-google"
31 usersmodulename = "pbx-users"
33 -- This function builds and returns a table with all the entries in a given "module" and "section".
34 function get_existing_entries(module, section)
37 m.uci:foreach(module, section,
39 existing_entries[i] = s1
42 return existing_entries
45 -- This function is used to build and return a table where the name field for
46 -- every element in a table entries are the indexes to the table (used to check
47 -- validity of user input.
48 function get_valid_names(entries)
50 for index,value in ipairs(entries) do
51 validnames[entries[index].name] = true
56 -- This function is used to build and return a table where the defaultuser field for
57 -- every element in a table entries are the indexes to the table (used to check
58 -- validity of user input.
59 function get_valid_defaultusers(entries)
61 for index,value in ipairs(entries) do
62 validnames[entries[index].defaultuser] = true
67 function is_valid_extension(exten)
68 return (exten:match("[#*+0-9NXZ]+$") ~= nil)
71 m = Map (modulename, translate("Call Routing"),
72 translate("This is where you indicate which Google/SIP accounts are used to call what \
73 country/area codes, which users can use which SIP/Google accounts, how incoming\
74 calls are routed, what numbers can get into this PBX with a password, and what\
75 numbers are blacklisted."))
77 -- Recreate the config, and restart services after changes are commited to the configuration.
78 function m.on_after_commit(self)
79 luci.sys.call("/etc/init.d/pbx-" .. server .. " restart 1\>/dev/null 2\>/dev/null")
80 luci.sys.call("/etc/init.d/" .. server .. " restart 1\>/dev/null 2\>/dev/null")
83 ----------------------------------------------------------------------------------------------------
84 s = m:section(NamedSection, "outgoing_calls", "call_routing", translate("Outgoing Calls"),
85 translate("If you have more than one account which can make outgoing calls, you\
86 should enter a list of phone numbers and prefixes in the following fields for each\
87 provider listed. Invalid prefixes are removed silently, and only 0-9, X, Z, N, #, *,\
88 and + are valid characters. The letter X matches 0-9, Z matches 1-9, and N matches 2-9.\
89 For example to make calls to Germany through a provider, you can enter 49. To make calls\
90 to North America, you can enter 1NXXNXXXXXX. If one of your providers can make \"local\"\
91 calls to an area code like New York's 646, you can enter 646NXXXXXX for that\
92 provider. You should leave one account with an empty list to make calls with\
93 it by default, if no other provider's prefixes match. The system will automatically\
94 replace an empty list with a message that the provider dials all numbers. Be as specific as\
95 possible (i.e. 1NXXNXXXXXX is better than 1). Please note all international dial codes\
96 are discarded (e.g. 00, 011, 010, 0011). Entries can be made in a\
97 space-separated list, and/or one per line by hitting enter after every one."))
100 m.uci:foreach(googlemodulename, "gtalk_jabber",
102 if s1.username ~= nil and s1.name ~= nil and
103 s1.make_outgoing_calls == "yes" then
104 patt = s:option(DynamicList, s1.name, s1.username)
106 -- If the saved field is empty, we return a string
107 -- telling the user that this account would dial any exten.
108 function patt.cfgvalue(self, section)
109 value = self.map:get(section, self.option)
112 return {"Dials any number"}
118 -- Write only valid extensions into the config file.
119 function patt.write(self, section, value)
122 for index, field in ipairs(value) do
123 if is_valid_extension(value[index]) == true then
124 newvalue[nindex] = value[index]
128 DynamicList.write(self, section, newvalue)
133 m.uci:foreach(voipmodulename, "voip_provider",
135 if s1.defaultuser ~= nil and s1.host ~= nil and
136 s1.name ~= nil and s1.make_outgoing_calls == "yes" then
137 patt = s:option(DynamicList, s1.name, s1.defaultuser .. "@" .. s1.host)
139 -- If the saved field is empty, we return a string
140 -- telling the user that this account would dial any exten.
141 function patt.cfgvalue(self, section)
142 value = self.map:get(section, self.option)
145 return {"Dials any number"}
151 -- Write only valid extensions into the config file.
152 function patt.write(self, section, value)
155 for index, field in ipairs(value) do
156 if is_valid_extension(value[index]) == true then
157 newvalue[nindex] = value[index]
161 DynamicList.write(self, section, newvalue)
166 ----------------------------------------------------------------------------------------------------
167 s = m:section(NamedSection, "incoming_calls", "call_routing", translate("Incoming Calls"),
168 translate("For each provider that receives calls, here you can restrict which users to ring\
169 on incoming calls. If the list is empty, the system will indicate that all users\
170 which are enabled for incoming calls will ring. Invalid usernames will be rejected\
171 silently. Also, entering a username here overrides the user's setting to not receive\
172 incoming calls, so this way, you can make users ring only for select providers.\
173 Entries can be made in a space-separated list, and/or one per\
174 line by hitting enter after every one."))
177 m.uci:foreach(googlemodulename, "gtalk_jabber",
179 if s1.username ~= nil and s1.register == "yes" then
180 field_name=string.gsub(s1.username, "%W", "_")
181 gtalkaccts = s:option(DynamicList, field_name, s1.username)
183 -- If the saved field is empty, we return a string
184 -- telling the user that this account would dial any exten.
185 function gtalkaccts.cfgvalue(self, section)
186 value = self.map:get(section, self.option)
189 return {"Rings all users"}
195 -- Write only valid user names.
196 function gtalkaccts.write(self, section, value)
197 users=get_valid_defaultusers(get_existing_entries(usersmodulename, "local_user"))
200 for index, field in ipairs(value) do
201 if users[value[index]] == true then
202 newvalue[nindex] = value[index]
206 DynamicList.write(self, section, newvalue)
212 m.uci:foreach(voipmodulename, "voip_provider",
214 if s1.defaultuser ~= nil and s1.host ~= nil and s1.register == "yes" then
215 field_name=string.gsub(s1.defaultuser .. "_" .. s1.host, "%W", "_")
216 voipaccts = s:option(DynamicList, field_name, s1.defaultuser .. "@" .. s1.host)
218 -- If the saved field is empty, we return a string
219 -- telling the user that this account would dial any exten.
220 function voipaccts.cfgvalue(self, section)
221 value = self.map:get(section, self.option)
224 return {"Rings all users"}
230 -- Write only valid user names.
231 function voipaccts.write(self, section, value)
232 users=get_valid_defaultusers(get_existing_entries(usersmodulename, "local_user"))
235 for index, field in ipairs(value) do
236 if users[value[index]] == true then
237 newvalue[nindex] = value[index]
241 DynamicList.write(self, section, newvalue)
246 ----------------------------------------------------------------------------------------------------
247 s = m:section(NamedSection, "providers_user_can_use", "call_routing",
248 translate("Providers Used for Outgoing Calls"),
249 translate("If you would like, you could restrict which providers users are allowed to use for outgoing\
250 calls. By default all users can use all providers. To show up in the list below the user should\
251 be allowed to make outgoing calls in the \"User Accounts\" page. Enter VoIP providers in the format\
252 username@some.host.name, as listed in \"Outgoing Calls\" above. It's easiest to copy and paste\
253 the providers from above. Invalid entries will be rejected silently. Also, any entries automatically\
254 change to this PBX's internal naming scheme, with \"_\" replacing all non-alphanumeric characters.\
255 Entries can be made in a space-separated list, and/or one per line by hitting enter after every\
259 m.uci:foreach(usersmodulename, "local_user",
261 if s1.defaultuser ~= nil and s1.can_call == "yes" then
262 providers = s:option(DynamicList, s1.defaultuser, s1.defaultuser)
264 -- If the saved field is empty, we return a string
265 -- telling the user that this account would dial any exten.
266 function providers.cfgvalue(self, section)
267 value = self.map:get(section, self.option)
270 return {"Uses all provider accounts"}
276 -- Cook the new values prior to entering them into the config file.
277 -- Also, enter them only if they are valid.
278 function providers.write(self, section, value)
279 validvoip=get_valid_names(get_existing_entries(voipmodulename, "voip_provider"))
280 validgoog=get_valid_names(get_existing_entries(googlemodulename, "gtalk_jabber"))
283 for index, field in ipairs(value) do
284 cooked = string.gsub(value[index], "%W", "_")
285 if validvoip[cooked] == true or validgoog[cooked] == true then
286 cookedvalue[cindex] = string.gsub(value[index], "%W", "_")
290 DynamicList.write(self, section, cookedvalue)
295 ----------------------------------------------------------------------------------------------------
296 s = m:section(TypedSection, "callthrough_numbers", translate("Call-through Numbers"),
297 translate("Designate numbers which will be allowed to call through this system and which user's\
298 privileges it will have."))
302 num = s:option(DynamicList, "callthrough_number_list", translate("Call-through Numbers"))
303 num.datatype = "uinteger"
305 p = s:option(ListValue, "enabled", translate("Enabled"))
306 p:value("yes", translate("Yes"))
307 p:value("no", translate("No"))
310 user = s:option(Value, "defaultuser", translate("User Name"),
311 translate("The number(s) specified above will be able to dial outwith this user's providers.\
312 Invalid usernames are dropped silently, please verify that the entry was accepted."))
313 function user.write(self, section, value)
314 users=get_valid_defaultusers(get_existing_entries(usersmodulename, "local_user"))
315 if users[value] == true then
316 Value.write(self, section, value)
320 pwd = s:option(Value, "pin", translate("PIN"),
321 translate("Your PIN disappears when saved for your protection. It will be changed\
322 only when you enter a value different from the saved one. Leaving the PIN\
323 empty is possible, but please beware of the security implications."))
327 -- We skip reading off the saved value and return nothing.
328 function pwd.cfgvalue(self, section)
332 -- We check the entered value against the saved one, and only write if the entered value is
333 -- something other than the empty string, and it differes from the saved value.
334 function pwd.write(self, section, value)
335 local orig_pwd = m:get(section, self.option)
336 if value and #value > 0 and orig_pwd ~= value then
337 Value.write(self, section, value)
341 ----------------------------------------------------------------------------------------------------
342 s = m:section(NamedSection, "blacklisting", "call_routing", translate("Blacklisted Numbers"),
343 translate("Enter phone numbers that you want to decline calls from automatically.\
344 You should probably omit the country code and any leading\
345 zeroes, but please experiment to make sure you are blocking numbers from your\
346 desired area successfully."))
349 b = s:option(DynamicList, "blacklist1", translate("Dynamic List of Blacklisted Numbers"),
350 translate("Specify numbers individually here. Press enter to add more numbers."))
352 b.datatype = "uinteger"
354 b = s:option(Value, "blacklist2", translate("Space-Separated List of Blacklisted Numbers"),
355 translate("Copy-paste large lists of numbers here."))
356 b.template = "cbi/tvalue"