1) Massive whitespace reorganization (untabified, and made consistent everything).
[project/luci.git] / applications / luci-pbx / luasrc / model / cbi / pbx-advanced.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 appname         = "PBX"
29 modulename      = "pbx-advanced"
30 defaultbindport = 5060
31 defaultrtpstart = 19850
32 defaultrtpend   = 19900
33
34 -- Returns all the network related settings, including a constructed RTP range
35 function get_network_info()
36         externhost = m.uci:get(modulename, "advanced", "externhost")
37         ipaddr     = m.uci:get("network", "lan", "ipaddr")
38         bindport   = m.uci:get(modulename, "advanced", "bindport")
39         rtpstart   = m.uci:get(modulename, "advanced", "rtpstart")
40         rtpend     = m.uci:get(modulename, "advanced", "rtpend")
41
42         if bindport == nil then bindport = defaultbindport end
43         if rtpstart == nil then rtpstart = defaultrtpstart end
44         if rtpend   == nil then rtpend   = defaultrtpend   end
45
46         if rtpstart == nil or rtpend == nil then
47                 rtprange = nil
48         else
49                 rtprange = rtpstart .. "-" .. rtpend
50         end
51
52         return bindport, rtprange, ipaddr, externhost
53 end
54
55 -- If not present, insert empty rules in the given config & section named PBX-SIP and PBX-RTP
56 function insert_empty_sip_rtp_rules(config, section)
57
58                 -- Add rules named PBX-SIP and PBX-RTP if not existing
59                 found_sip_rule = false
60                 found_rtp_rule = false
61                 m.uci:foreach(config, section,
62                         function(s1)
63                                 if     s1._name == 'PBX-SIP' then
64                                         found_sip_rule = true
65                                 elseif s1._name == 'PBX-RTP' then
66                                         found_rtp_rule = true
67                                 end
68                         end)
69                 
70                 if found_sip_rule ~= true then
71                         newrule=m.uci:add(config, section)
72                         m.uci:set(config, newrule, '_name', 'PBX-SIP')
73                 end
74                 if found_rtp_rule ~= true then
75                         newrule=m.uci:add(config, section)
76                         m.uci:set(config, newrule, '_name', 'PBX-RTP')
77                 end
78 end
79
80 -- Delete rules in the given config & section named PBX-SIP and PBX-RTP
81 function delete_sip_rtp_rules(config, section)
82
83                 -- Remove rules named PBX-SIP and PBX-RTP
84                 commit = false
85                 m.uci:foreach(config, section,
86                         function(s1)
87                                 if s1._name == 'PBX-SIP' or s1._name == 'PBX-RTP' then
88                                         m.uci:delete(config, s1['.name'])
89                                         commit = true
90                                 end
91                         end)
92
93         -- If something changed, then we commit the config.
94         if commit == true then m.uci:commit(config) end
95 end
96
97 -- Deletes QoS rules associated with this PBX.
98 function delete_qos_rules()
99         delete_sip_rtp_rules ("qos", "classify")
100 end
101
102
103 function insert_qos_rules()
104         -- Insert empty PBX-SIP and PBX-RTP rules if not present.
105         insert_empty_sip_rtp_rules ("qos", "classify")
106
107         -- Get the network information
108         bindport, rtprange, ipaddr, externhost = get_network_info()
109
110         -- Iterate through the QoS rules, and if there is no other rule with the same port
111         -- range at the express service level, insert this rule.
112         commit = false
113         m.uci:foreach("qos", "classify",
114                 function(s1)
115                         if     s1._name == 'PBX-SIP' then
116                                 if s1.ports ~= bindport or s1.target ~= "Express" or s1.proto ~= "udp" then
117                                         m.uci:set("qos", s1['.name'], "ports",  bindport)
118                                         m.uci:set("qos", s1['.name'], "proto",  "udp")
119                                         m.uci:set("qos", s1['.name'], "target", "Express")
120                                         commit = true
121                                 end
122                         elseif s1._name == 'PBX-RTP' then
123                                 if s1.ports ~= rtprange or s1.target ~= "Express" or s1.proto ~= "udp" then
124                                         m.uci:set("qos", s1['.name'], "ports",  rtprange)
125                                         m.uci:set("qos", s1['.name'], "proto",  "udp")
126                                         m.uci:set("qos", s1['.name'], "target", "Express")
127                                         commit = true
128                                 end
129                         end
130                 end)
131
132         -- If something changed, then we commit the qos config.
133         if commit == true then m.uci:commit("qos") end
134 end
135
136 -- This function is a (so far) unsuccessful attempt to manipulate the firewall rules from here
137 -- Need to do more testing and eventually move to this mode.
138 function maintain_firewall_rules()
139         -- Get the network information
140         bindport, rtprange, ipaddr, externhost = get_network_info()
141
142         commit = false
143         -- Only if externhost is set, do we control firewall rules.
144         if externhost ~= nil and bindport ~= nil and rtprange ~= nil then
145                 -- Insert empty PBX-SIP and PBX-RTP rules if not present.
146                 insert_empty_sip_rtp_rules ("firewall", "rule")
147
148                 -- Iterate through the firewall rules, and if the dest_port and dest_ip setting of the\
149                 -- SIP and RTP rule do not match what we want configured, set all the entries in the rule\
150                 -- appropriately.
151                 m.uci:foreach("firewall", "rule",
152                         function(s1)
153                                 if     s1._name == 'PBX-SIP' then
154                                         if s1.dest_port ~= bindport then
155                                                 m.uci:set("firewall", s1['.name'], "dest_port", bindport)
156                                                 m.uci:set("firewall", s1['.name'], "src", "wan")
157                                                 m.uci:set("firewall", s1['.name'], "proto", "udp")
158                                                 m.uci:set("firewall", s1['.name'], "target", "ACCEPT")
159                                                 commit = true
160                                         end
161                                 elseif s1._name == 'PBX-RTP' then
162                                         if s1.dest_port ~= rtprange then
163                                                 m.uci:set("firewall", s1['.name'], "dest_port", rtprange)
164                                                 m.uci:set("firewall", s1['.name'], "src", "wan")
165                                                 m.uci:set("firewall", s1['.name'], "proto", "udp")
166                                                 m.uci:set("firewall", s1['.name'], "target", "ACCEPT")
167                                                 commit = true
168                                         end
169                                 end
170                         end)
171         else
172                 -- We delete the firewall rules if one or more of the necessary parameters are not set.
173                 sip_rule_name=nil
174                 rtp_rule_name=nil
175         
176                 -- First discover the configuration names of the rules.
177                 m.uci:foreach("firewall", "rule",
178                         function(s1)
179                                 if     s1._name == 'PBX-SIP' then
180                                         sip_rule_name = s1['.name']
181                                 elseif s1._name == 'PBX-RTP' then
182                                         rtp_rule_name = s1['.name']
183                                 end
184                         end)
185                 
186                 -- Then, using the names, actually delete the rules.
187                 if sip_rule_name ~= nil then
188                         m.uci:delete("firewall", sip_rule_name)
189                         commit = true
190                 end
191                 if rtp_rule_name ~= nil then
192                         m.uci:delete("firewall", rtp_rule_name)
193                         commit = true
194                 end
195         end
196
197         -- If something changed, then we commit the firewall config.
198         if commit == true then m.uci:commit("firewall") end
199 end
200
201 m = Map (modulename, translate("Advanced Settings"),
202          translate("This section contains settings which do not need to be changed under\
203          normal circumstances. In addition, here you can configure your system\
204          for use with remote SIP devices, and resolve call quality issues by enabling\
205          the insertion of QoS rules."))
206
207 -- Recreate the voip server config, and restart necessary services after changes are commited
208 -- to the advanced configuration. The firewall must restart because of "Remote Usage".
209 function m.on_after_commit(self)
210
211         -- Make sure firewall rules are in place
212         maintain_firewall_rules()
213
214         -- If insertion of QoS rules is enabled
215         if m.uci:get(modulename, "advanced", "qos_enabled") == "yes" then
216                 insert_qos_rules()
217         else
218                 delete_qos_rules()
219         end
220
221         luci.sys.call("/etc/init.d/pbx-" .. server .. " restart 1\>/dev/null 2\>/dev/null")
222         luci.sys.call("/etc/init.d/"     .. server .. " restart 1\>/dev/null 2\>/dev/null")
223         luci.sys.call("/etc/init.d/firewall             restart 1\>/dev/null 2\>/dev/null")
224 end
225
226 -----------------------------------------------------------------------------
227 s = m:section(NamedSection, "advanced", "settings", translate("Advanced Settings"))
228 s.anonymous = true
229
230 s:tab("general",  translate("General Settings"))
231 s:tab("remote_usage", translate("Remote Usage"),
232       translatef("You can use your SIP devices/softphones with this system from a remote location\
233       as well, as long as your Internet Service Provider gives you a public IP.\
234       You will be able to call other local users for free (e.g. other Analog Telephone Adapters (ATAs))\
235       and use your VoIP providers to make calls as if you were at local to the PBX.\
236       After configuring this tab, go back to where users are configured and see the new\
237       Server and Port setting you need to configure the SIP devices with. Please note that by default\
238       %s uses UDP port range %d to %d for RTP traffic (which carries voice), in case you need to configure\
239       NAT or QoS on another device.", appname, defaultrtpstart, defaultrtpend))
240
241 s:tab("qos",  translate("QoS Settings"), 
242       translate("If you experience jittery or high latency audio during heavy downloads, you may want \
243       to enable QoS. QoS prioritizes traffic to and from your network for specified ports and IP \
244       addresses, resulting in better latency and throughput for sound in our case. If enabled below, \
245       a QoS rule for this service will be configured by the PBX automatically, but you must visit the \
246       QoS configuration page (Network->QoS) to configure other critical QoS settings like Download \
247       and Upload speed."))
248
249 ua = s:taboption("general", Value, "useragent", translate("User Agent String"),
250                  translate("This is the name that the VoIP server will use to identify itself when\
251                  registering to VoIP (SIP) providers. Some providers require this to a specific\
252                  string matching a hardware SIP device."))
253 ua.default = appname
254
255 h = s:taboption("remote_usage", Value, "externhost", translate("Domain Name/Dynamic Domain Name"),
256                 translate("You should either have registered a domain name and have a static IP\
257                 address, or have configured Dynamic DNS on this router. Enter a\
258                 domain name which resolves to your external IP address."))
259 h.datatype = "hostname"
260
261 p = s:taboption("remote_usage", Value, "bindport", translate("External SIP Port"),
262                 translate("Pick a random port number between 6500 and 9500 for the service to listen on.\
263                 Do not pick the standard 5060, because it is often subject to brute-force attacks.\
264                 When finished, (1) click \"Save and Apply\", and (2) click the \"Restart VoIP Service\"\
265                 button above. Finally, (3) look in the \"SIP Device/Softphone Accounts\" section for\
266                 updated Server and Port settings for your SIP Devices/Softphones."))
267 p.datatype = "port"
268
269 p = s:taboption("remote_usage", Value, "rtpstart", translate("RTP Port Range Start"),
270                 translate("RTP traffic carries actual voice packets. This is the start of the port range\
271                 which will be used for setting up RTP communication. It's usually OK to leave this\
272                 at the default value."))
273 p.datatype = "port"
274 p.default = defaultrtpstart
275
276 p = s:taboption("remote_usage", Value, "rtpend", translate("RTP Port Range End"))
277 p.datatype = "port"
278 p.default = defaultrtpend
279
280 p = s:taboption("qos", ListValue, "qos_enabled", translate("Insert QoS Rules"))
281 p:value("yes", translate("Yes"))
282 p:value("no",  translate("No"))
283 p.default = "yes"
284
285 return m