From 1a3d44865f6cbda203b84340684aa539599bb876 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 21 Mar 2009 04:36:08 +0000 Subject: [PATCH] applications/luci-asterisk: rework dialplan management --- .../luci-asterisk/luasrc/asterisk.lua | 59 ++++++ .../luasrc/controller/asterisk.lua | 136 +++++++----- .../model/cbi/asterisk/dialplan_out.lua | 2 +- .../luasrc/view/asterisk/dialplans.htm | 200 +++++++++--------- .../luasrc/view/asterisk/dialzones.htm | 174 +++++++++++++++ .../luci-asterisk/root/etc/config/asterisk | 3 +- 6 files changed, 422 insertions(+), 152 deletions(-) create mode 100644 applications/luci-asterisk/luasrc/view/asterisk/dialzones.htm diff --git a/applications/luci-asterisk/luasrc/asterisk.lua b/applications/luci-asterisk/luasrc/asterisk.lua index 908986366..2967b42c0 100644 --- a/applications/luci-asterisk/luasrc/asterisk.lua +++ b/applications/luci-asterisk/luasrc/asterisk.lua @@ -25,6 +25,11 @@ AST_BIN = "/usr/sbin/asterisk" AST_FLAGS = "-r -x" +--- LuCI Asterisk - Resync uci context +function uci_resync() + uci = luci.model.uci.cursor() +end + --- LuCI Asterisk io interface -- Handles low level io. -- @type module @@ -318,3 +323,57 @@ function dialzone.ucisection(i) end) return hash end + + +--- LuCI Asterisk - Dialplan +-- @type module +dialplan = luci.util.class() + +--- Parse a dialplan section +-- @param plan Table containing the plan info +-- @return Table with parsed information +function dialplan.parse(z) + if z['.name'] then + local plan = { + zones = { }, + name = z['.name'], + description = z.description or z['.name'] + } + + for _, name in ipairs(tools.parse_list(z.include)) do + local zone = dialzone.zone(name) + if zone then + plan.zones[#plan.zones+1] = zone + end + end + + return plan + end +end + +--- Get a list of known dial plans +-- @return Associative table of plans and table of plan names +function dialplan.plans() + local plans = { } + local pnames = { } + uci:foreach("asterisk", "dialplan", + function(p) + plans[p['.name']] = dialplan.parse(p) + pnames[#pnames+1] = p['.name'] + end) + return plans, pnames +end + +--- Get a specific dial plan +-- @param name Name of the dial plan +-- @return Table containing plan information +function dialplan.plan(n) + local plan + uci:foreach("asterisk", "dialplan", + function(p) + if p['.name'] == n then + plan = dialplan.parse(p) + end + end) + return plan +end diff --git a/applications/luci-asterisk/luasrc/controller/asterisk.lua b/applications/luci-asterisk/luasrc/controller/asterisk.lua index 04b4e42b3..123666efc 100644 --- a/applications/luci-asterisk/luasrc/controller/asterisk.lua +++ b/applications/luci-asterisk/luasrc/controller/asterisk.lua @@ -40,76 +40,116 @@ function index() cbi("asterisk-mod-res-feature"), "Feature Module Configuration", 9 ) - entry({"admin", "asterisk"}, cbi("asterisk/main"), "Asterisk", 99).i18n = "asterisk" + entry({"admin", "asterisk"}, cbi("asterisk/main"), "Asterisk", 99).i18n = "asterisk" - entry({"admin", "asterisk", "phones"}, cbi("asterisk/phones"), "Phones", 1) - entry({"admin", "asterisk", "phones", "sip"}, cbi("asterisk/phone_sip"), nil, 1).leaf = true - --entry({"admin", "asterisk", "phones", "exten"}, cbi("asterisk/phone_exten"), "Extensions", 2).leaf = true + entry({"admin", "asterisk", "phones"}, cbi("asterisk/phones"), "Phones", 1) + entry({"admin", "asterisk", "phones", "sip"}, cbi("asterisk/phone_sip"), nil, 1).leaf = true + --entry({"admin", "asterisk", "phones", "exten"}, cbi("asterisk/phone_exten"), "Extensions", 2).leaf = true - entry({"admin", "asterisk", "trunks"}, cbi("asterisk/trunks"), "Trunks", 2) - entry({"admin", "asterisk", "trunks", "sip"}, cbi("asterisk/trunk_sip"), nil, 1).leaf = true + entry({"admin", "asterisk", "trunks"}, cbi("asterisk/trunks"), "Trunks", 2) + entry({"admin", "asterisk", "trunks", "sip"}, cbi("asterisk/trunk_sip"), nil, 1).leaf = true - --entry({"admin", "asterisk", "dialplans"}, cbi("asterisk/dialplans"), "Call Routing", 3) - entry({"admin", "asterisk", "dialplans"}, call("handle_dialplan"), "Call Routing", 3) - entry({"admin", "asterisk", "dialplans", "out"}, cbi("asterisk/dialplan_out"), nil, 1).leaf = true - entry({"admin", "asterisk", "dialplans", "zones"}, cbi("asterisk/dialzones"), "Dial Zones", 2).leaf = true + --entry({"admin", "asterisk", "dialplans"}, cbi("asterisk/dialplans"), "Call Routing", 3) + entry({"admin", "asterisk", "dialplans"}, call("handle_dialplan"), "Call Routing", 3) + entry({"admin", "asterisk", "dialplans", "out"}, cbi("asterisk/dialplan_out"), nil, 1).leaf = true + entry({"admin", "asterisk", "dialplans", "zones"}, call("handle_dialzones"), "Dial Zones", 2).leaf = true end function handle_dialplan() local uci = luci.model.uci.cursor() + local ast = require "luci.asterisk" + local err = false - if luci.http.formvalue("delete") then - local del = luci.http.formvalue("delete") - if #del > 0 and not del:match("[^a-zA-Z0-9_]") then - uci:delete("asterisk", del) - uci:foreach("asterisk", "dialplan", - function(s) - if s.include then - local inc = type(s.include) == "table" and s.include or - luci.util.split(s.include, "%s+", nil, true) - - local inc2 = { } - for _, v in ipairs(inc) do - if v ~= del then - inc2[#inc2+1] = v - end - end - - uci:set("asterisk", s['.name'], "include", inc2) - end - end) + for k, v in pairs(luci.http.formvaluetable("delzone")) do + local plan = ast.dialplan.plan(k) + if #v > 0 and plan then + local newinc = { } + + for _, z in ipairs(plan.zones) do + if z.name ~= v then + newinc[#newinc+1] = z.name + end + end + + uci:delete("asterisk", plan.name, "include") + + if #newinc > 0 then + uci:set("asterisk", plan.name, "include", newinc) + end uci:save("asterisk") - uci:commit("asterisk") end end - for k, v in pairs(luci.http.formvaluetable("create_entry")) do - if #v > 0 and not v:match("[^a-zA-Z0-9_]") then - uci:section("asterisk", "dialzone", v, { - context = k - } ) + for k, v in pairs(luci.http.formvaluetable("addzone")) do + local plan = ast.dialplan.plan(k) + local zone = ast.dialzone.zone(v) + if #v > 0 and plan and zone then + local newinc = { zone.name } - local inc = uci:get("asterisk", k, "include") - inc = type(inc) == "table" and inc or - type(inc) == "string" and #inc > 0 and - luci.util.split(inc, "%s+", nil, true) or { } + for _, z in ipairs(plan.zones) do + newinc[#newinc+1] = z.name + end - inc[#inc+1] = v + uci:delete("asterisk", plan.name, "include") + + if #newinc > 0 then + uci:set("asterisk", plan.name, "include", newinc) + end - uci:set("asterisk", k, "include", inc) uci:save("asterisk") - uci:commit("asterisk") + end + end - luci.http.redirect(luci.dispatcher.build_url( - "asterisk", "dialplans", "out", v - )) + local aname = luci.http.formvalue("addplan") + if aname and #aname > 0 then + if aname:match("^[a-zA-Z0-9_]+$") then + uci:section("asterisk", "dialplan", aname, { }) + uci:save("asterisk") + else + err = true + end + end - return + local dname = luci.http.formvalue("delplan") + if dname and #dname > 0 then + if uci:get("asterisk", dname) == "dialplan" then + uci:delete("asterisk", dname) + uci:save("asterisk") + end + end + + ast.uci_resync() + luci.template.render("asterisk/dialplans", { create_error = err }) +end + +function handle_dialzones() + local ast = require "luci.asterisk" + local uci = luci.model.uci.cursor() + local err = false + + if luci.http.formvalue("newzone") then + local name = luci.http.formvalue("newzone_name") + if name and name:match("^[a-zA-Z0-9_]+$") then + uci:section("asterisk", "dialzone", name, { + uses = ast.tools.parse_list(luci.http.formvalue("newzone_uses") or {}), + match = ast.tools.parse_list(luci.http.formvalue("newzone_match") or {}) + }) + uci:save("asterisk") + else + err = true + end + end + + if luci.http.formvalue("delzone") then + local name = luci.http.formvalue("delzone") + if uci:get("asterisk", name) == "dialzone" then + uci:delete("asterisk", name) + uci:save("asterisk") end end - luci.template.render("asterisk/dialplans") + luci.template.render("asterisk/dialzones", { create_error = err }) end diff --git a/applications/luci-asterisk/luasrc/model/cbi/asterisk/dialplan_out.lua b/applications/luci-asterisk/luasrc/model/cbi/asterisk/dialplan_out.lua index c8538426c..94bf7d4d5 100644 --- a/applications/luci-asterisk/luasrc/model/cbi/asterisk/dialplan_out.lua +++ b/applications/luci-asterisk/luasrc/model/cbi/asterisk/dialplan_out.lua @@ -114,7 +114,7 @@ if arg[1] then intl = entry:option(DynamicList, "international", "Intl. prefix matches (optional)") - trunk = entry:option(ListValue, "uses", "Used trunk") + trunk = entry:option(MultiValue, "uses", "Used trunk") for _, v in ipairs(find_trunks(cbimap.uci)) do trunk:value(unpack(v)) end diff --git a/applications/luci-asterisk/luasrc/view/asterisk/dialplans.htm b/applications/luci-asterisk/luasrc/view/asterisk/dialplans.htm index 7432cebf3..217fc6e3c 100644 --- a/applications/luci-asterisk/luasrc/view/asterisk/dialplans.htm +++ b/applications/luci-asterisk/luasrc/view/asterisk/dialplans.htm @@ -17,53 +17,11 @@ $Id$ <% local uci = luci.model.uci.cursor_state() + local ast = require "luci.asterisk" - function find_rules(plan) - local r = { } - if plan and plan.include then - local i = luci.util.split(plan.include, "%s+", nil, true) - for _, i in ipairs(i) do - i = uci:get("asterisk", "dialzone", i) - if i then - r[#r+1] = i - end - end - end - return r - end - - dp_lookup_table = { } - - function dialplan_lookup(s) - if not dp_lookup_table[s['.name']] then - s.childs = { } - s.matches = type(s.match) == "table" and s.match or { s.match } - s.name, s.type = s['.name'], s['.type'] - s['.name'], s['.type'] = nil, nil - dp_lookup_table[s.name] = s - end - end - - uci:foreach("asterisk", "dialplan", dialplan_lookup) - uci:foreach("asterisk", "dialzone", dialplan_lookup) - - for k, p in pairs(dp_lookup_table) do - if p.include then - local i = type(p.include) == "string" - and luci.util.split(p.include, "%s+", nil, true) or p.include - - for _, i in ipairs(i) do - i = dp_lookup_table[i] - if i then - p.childs[#p.childs+1] = i - i.parent = p - end - end - end - end - - function digit_pattern(s) - return "%s" % s + function digit_pattern(s,t) + return "%s" + %{ t and " title='" .. t .. "'" or "", s } end function rowstyle(i) @@ -72,18 +30,33 @@ $Id$ } end - function link_trunks(s) - local l = { } - for s in s:gmatch("(%S+)") do - if s:match("^[sS][iI][pP]/") then - l[#l+1] = '%s' %{ - luci.dispatcher.build_url("admin", "asterisk", "trunks", - "sip", (s:gsub("^.+/",""))), - (s:gsub("^.+/","SIP: ")) - } + function format_matches(z) + local html = { } + + if z.localprefix then + for _, m in ipairs(z.matches) do + html[#html+1] = + digit_pattern(z.localprefix, "local prefix") .. " " .. + digit_pattern(m) + end + end + + if #z.intlmatches > 0 then + for _, i in ipairs(z.intlmatches) do + for _, m in ipairs(z.matches) do + html[#html+1] = "%s %s" %{ + digit_pattern("(%s)" % i, "intl. prefix"), + digit_pattern(m) + } + end + end + else + for _, m in ipairs(z.matches) do + html[#html+1] = digit_pattern(m) end end - return '%s' % table.concat(l, ", ") + + return table.concat(html, "; ") end %> @@ -100,69 +73,92 @@ $Id$
-
- - - - +
+ Here you can manage your dial plans which are used to route outgoing calls from your local extensions. +
- <% for name, plan in luci.util.kspairs(dp_lookup_table) do - if plan.type == "dialplan" then %> + <% for i, plan in pairs(ast.dialplan.plans()) do %>
- + - - - - - - - - - <% for i, rule in pairs(plan.childs) do - if rule.type == "dialzone" then %> + + <% local zones_used = { } %> + <% for i, zone in ipairs(plan.zones) do zones_used[zone.name] = true %> - - - - - - <% end end %> + <% end %> + + + + + +
-  Dialplan <%=name%> + + Dialplan <%=plan.name%> + + Remove this dialplan + +
Prepend- MatchTrunkDescription
- <% for _ in ipairs(rule.matches) do %> - <%=rule.addprefix and digit_pattern(rule.addprefix)%> 
- <% end %> -
- <% for _, m in ipairs(rule.matches) do %> - <%=rule.localprefix and "%s " % digit_pattern(rule.localprefix)%> - <%=digit_pattern(m)%>
- <% end %> +
+ └ Dialzone <%=zone.name%> +

+ Description: <%=zone.description%>
+ Lines: + <%=ast.tools.hyperlinks( + zone.trunks, function(v) + return luci.dispatcher.build_url("admin", "asterisk", "trunks", "%s") % v:lower() + end + )%>
+ Matches: + <%=format_matches(zone)%> +

- <%=rule.uses and link_trunks(rule.uses)%> - - <%=rule.description or rule.name%> - - - Edit entry + + + Edit dialzone - - Delete entry + + Remove from this dialplan
+
+ + +     + Manage dialzones +
-
- - -
+

- <% end end %> + <% end %> + +
+
+

Create a new dialplan

+ The name is required and must be unique. It may only contain the characters A-Z, a-z, 0-9 and _ .
+ + <%- if create_error then %> +
Invalid name given!
+ <% end -%> + +
+ + +
+
diff --git a/applications/luci-asterisk/luasrc/view/asterisk/dialzones.htm b/applications/luci-asterisk/luasrc/view/asterisk/dialzones.htm new file mode 100644 index 000000000..2f7ed420e --- /dev/null +++ b/applications/luci-asterisk/luasrc/view/asterisk/dialzones.htm @@ -0,0 +1,174 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<%+header%> + +<% + local uci = luci.model.uci.cursor_state() + local ast = require("luci.asterisk") + + function digit_pattern(s) + return "%s" % s + end + + function rowstyle(i) + return "cbi-rowstyle-%i" %{ + ( i % 2 ) == 0 and 2 or 1 + } + end + + local function find_trunks() + local t = { } + + uci:foreach("asterisk", "sip", + function(s) + if uci:get_bool("asterisk", s['.name'], "provider") then + t[#t+1] = { + "SIP/%s" % s['.name'], + "SIP: %s" % s['.name'] + } + end + end) + + uci:foreach("asterisk", "iax", + function(s) + t[#t+1] = { + "IAX/%s" % s['.name'], + "IAX: %s" % s.extension or s['.name'] + } + end) + + return t + end + +%> + + +
" enctype="multipart/form-data"> +
+ + + +
+ +
+

Dial Zone Management

+
+ " class="cbi-title-ref">Back to dialplan overview

+ Here you can manage your dial zones. The zones are used to route outgoing calls to the destination. + Each zone groups multiple trunks and number matches to represent a logical destination. Zones can + also be used to enforce certain dial restrictions on selected extensions. +
+ + +
+
+ + + + + + + + + + + + + + + <% for i, rule in pairs(ast.dialzone.zones()) do %> + + + + + + + + + <% end %> +
+

Dialzone Overview

+
NamePrepend- MatchTrunkDescription
+ <%=rule.name%> + + <% for _ in ipairs(rule.matches) do %> + <%=rule.addprefix and digit_pattern(rule.addprefix)%> 
+ <% end %> +
+ <% for _, m in ipairs(rule.matches) do %> + <%=rule.localprefix and "%s " % digit_pattern(rule.localprefix)%> + <%=digit_pattern(m)%>
+ <% end %> +
+ <%=ast.tools.hyperlinks( + rule.trunks, function(v) + return luci.dispatcher.build_url("admin", "asterisk", "trunks", "%s") % v:lower() + end + )%> + + <%=rule.description or rule.name%> + + + Edit entry + + + Delete entry + +
+
+
+
+ +
+
+

Create a new dialzone

+ The name is required and must be unique. It may only contain the characters A-Z, a-z, 0-9 and _ .
+ You can specifiy multiple number matches by separating them with spaces.
+ + <%- if create_error then %> +
Invalid name given!
+ <% end -%> + + + + + + +
+
+ +

+ +
+ +
+
+ +
+
+ + +
+
+
+
+
+
+<%+footer%> diff --git a/applications/luci-asterisk/root/etc/config/asterisk b/applications/luci-asterisk/root/etc/config/asterisk index b2fd9ad27..6fd3572bb 100644 --- a/applications/luci-asterisk/root/etc/config/asterisk +++ b/applications/luci-asterisk/root/etc/config/asterisk @@ -75,6 +75,7 @@ config 'sip' 'PAP2T2' option 'incoming' 'provider_inbound' config 'sip' 'providerphone' + option 'provider' 'yes' option 'type' 'friend' option 'timeout' '55' option 'internationalprefix' '0011' @@ -188,7 +189,7 @@ config 'dialzone' 'interstate' option 'localprefix' '0' config 'dialzone' 'mobile' - option 'uses' 'SIP/iinetphone' + option 'uses' 'SIP/providerphone' option 'match' '04XXXXXXXX' option 'localprefix' '0' -- 2.25.1