2 LuCI - Lua Configuration Interface
3 Asterisk PBX interface library
5 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
17 module("luci.asterisk", package.seeall)
19 local _io = require("io")
20 local uci = require("luci.model.uci").cursor()
21 local sys = require("luci.sys")
22 local util = require("luci.util")
24 AST_BIN = "/usr/sbin/asterisk"
28 --- LuCI Asterisk - Resync uci context
30 uci = luci.model.uci.cursor()
33 --- LuCI Asterisk io interface
34 -- Handles low level io.
36 io = luci.util.class()
38 --- Execute command and return output
39 -- @param command String containing the command to execute
40 -- @return String containing the command output
41 function io.exec(command)
42 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
43 assert(fh, "Failed to invoke asterisk")
45 local buffer = fh:read("*a")
50 --- Execute command and invoke given callback for each readed line
51 -- @param command String containing the command to execute
52 -- @param callback Function to call back for each line
53 -- @return Always true
54 function io.execl(command, callback)
56 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
57 assert(fh, "Failed to invoke asterisk")
68 --- Execute command and return an iterator that returns one line per invokation
69 -- @param command String containing the command to execute
70 -- @return Iterator function
71 function io.execi(command)
72 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
73 assert(fh, "Failed to invoke asterisk")
76 local ln = fh:read("*l")
77 if not ln then fh:close() end
83 --- LuCI Asterisk - core status
84 core = luci.util.class()
86 --- Retrive version string.
87 -- @return String containing the reported asterisk version
88 function core.version(self)
89 local version = io.exec("core show version")
90 return version:gsub(" *\n", "")
94 --- LuCI Asterisk - SIP information.
96 sip = luci.util.class()
98 --- Get a list of known SIP peers
99 -- @return Table containing each SIP peer
100 function sip.peers(self)
104 for line in io.execi("sip show peers") do
107 elseif not line:match(" sip peers ") then
108 local online, delay, id, uid
109 local name, host, dyn, nat, acl, port, status =
110 line:match("(.-) +(.-) +([D ]) ([N ]) (.) (%d+) +(.+)")
112 if host == '(Unspecified)' then host = nil end
113 if port == '0' then port = nil else port = tonumber(port) end
115 dyn = ( dyn == 'D' and true or false )
116 nat = ( nat == 'N' and true or false )
117 acl = ( acl ~= ' ' and true or false )
119 online, delay = status:match("(OK) %((%d+) ms%)")
121 if online == 'OK' then
123 delay = tonumber(delay)
124 elseif status ~= 'Unmonitored' then
132 id, uid = name:match("(.+)/(.+)")
134 if not ( id and uid ) then
156 --- Get informations of given SIP peer
157 -- @param peer String containing the name of the SIP peer
158 function sip.peer(peer)
162 for line in io.execi("sip show peer " .. peer) do
164 local key, val = line:match("(.-) *: +(.*)")
167 key = key:gsub("^ +",""):gsub(" +$", "")
168 val = val:gsub("^ +",""):gsub(" +$", "")
170 if key == "* Name" then
172 elseif key == "Addr->IP" then
173 info.address, info.port = val:match("(.+) Port (.+)")
174 info.port = tonumber(info.port)
175 elseif key == "Status" then
176 info.online, info.delay = val:match("(OK) %((%d+) ms%)")
177 if info.online == 'OK' then
179 info.delay = tonumber(info.delay)
180 elseif status ~= 'Unmonitored' then
189 if val == 'Yes' or val == 'yes' or val == '<Set>' then
191 elseif val == 'No' or val == 'no' then
193 elseif val == '<Not set>' or val == '(none)' then
207 --- LuCI Asterisk - Internal helpers
209 tools = luci.util.class()
211 --- Convert given value to a list of tokens. Split by white space.
212 -- @param val String or table value
213 -- @return Table containing tokens
214 function tools.parse_list(v)
217 v = type(v) == "table" and v or { v }
218 for _, v in ipairs(v) do
219 if type(v) == "string" then
220 for v in v:gmatch("(%S+)") do
221 tokens[#tokens+1] = v
229 --- Convert given list to a collection of hyperlinks
230 -- @param list Table of tokens
231 -- @param url String pattern or callback function to construct urls (optional)
232 -- @param sep String containing the seperator (optional, default is ", ")
233 -- @return String containing the html fragment
234 function tools.hyperlinks(list, url, sep)
237 local function mkurl(p, t)
238 if type(p) == "string" then
240 elseif type(p) == "function" then
251 for _, token in ipairs(list) do
252 html = ( html and html .. sep or '' ) ..
253 '<a href="%s">%s</a>' %{ mkurl(url, token), token }
260 --- LuCI Asterisk - Dialzone
262 dialzone = luci.util.class()
264 --- Parse a dialzone section
265 -- @param zone Table containing the zone info
266 -- @return Table with parsed information
267 function dialzone.parse(z)
270 trunks = tools.parse_list(z.uses),
272 description = z.description or z['.name'],
273 addprefix = z.addprefix,
274 matches = tools.parse_list(z.match),
275 intlmatches = tools.parse_list(z.international),
276 countrycode = z.countrycode,
277 localzone = z.localzone,
278 localprefix = z.localprefix
283 --- Get a list of known dial zones
284 -- @return Associative table of zones and table of zone names
285 function dialzone.zones()
288 uci:foreach("asterisk", "dialzone",
290 zones[z['.name']] = dialzone.parse(z)
291 znames[#znames+1] = z['.name']
296 --- Get a specific dial zone
297 -- @param name Name of the dial zone
298 -- @return Table containing zone information
299 function dialzone.zone(n)
301 uci:foreach("asterisk", "dialzone",
303 if z['.name'] == n then
304 zone = dialzone.parse(z)
310 --- Find uci section hash for given zone number
311 -- @param idx Zone number
312 -- @return String containing the uci hash pointing to the section
313 function dialzone.ucisection(i)
317 uci:foreach("asterisk", "dialzone",
319 if not hash and index == i then
328 --- LuCI Asterisk - Dialplan
330 dialplan = luci.util.class()
332 --- Parse a dialplan section
333 -- @param plan Table containing the plan info
334 -- @return Table with parsed information
335 function dialplan.parse(z)
340 description = z.description or z['.name']
343 for _, name in ipairs(tools.parse_list(z.include)) do
344 local zone = dialzone.zone(name)
346 plan.zones[#plan.zones+1] = zone
354 --- Get a list of known dial plans
355 -- @return Associative table of plans and table of plan names
356 function dialplan.plans()
359 uci:foreach("asterisk", "dialplan",
361 plans[p['.name']] = dialplan.parse(p)
362 pnames[#pnames+1] = p['.name']
367 --- Get a specific dial plan
368 -- @param name Name of the dial plan
369 -- @return Table containing plan information
370 function dialplan.plan(n)
372 uci:foreach("asterisk", "dialplan",
374 if p['.name'] == n then
375 plan = dialplan.parse(p)