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 io interface
29 -- Handles low level io.
31 io = luci.util.class()
33 --- Execute command and return output
34 -- @param command String containing the command to execute
35 -- @return String containing the command output
36 function io.exec(command)
37 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
38 assert(fh, "Failed to invoke asterisk")
40 local buffer = fh:read("*a")
45 --- Execute command and invoke given callback for each readed line
46 -- @param command String containing the command to execute
47 -- @param callback Function to call back for each line
48 -- @return Always true
49 function io.execl(command, callback)
51 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
52 assert(fh, "Failed to invoke asterisk")
63 --- Execute command and return an iterator that returns one line per invokation
64 -- @param command String containing the command to execute
65 -- @return Iterator function
66 function io.execi(command)
67 local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
68 assert(fh, "Failed to invoke asterisk")
71 local ln = fh:read("*l")
72 if not ln then fh:close() end
78 --- LuCI Asterisk - core status
79 core = luci.util.class()
81 --- Retrive version string.
82 -- @return String containing the reported asterisk version
83 function core.version(self)
84 local version = io.exec("core show version")
85 return version:gsub(" *\n", "")
89 --- LuCI Asterisk - SIP information.
91 sip = luci.util.class()
93 --- Get a list of known SIP peers
94 -- @return Table containing each SIP peer
95 function sip.peers(self)
99 for line in io.execi("sip show peers") do
102 elseif not line:match(" sip peers ") then
103 local online, delay, id, uid
104 local name, host, dyn, nat, acl, port, status =
105 line:match("(.-) +(.-) +([D ]) ([N ]) (.) (%d+) +(.+)")
107 if host == '(Unspecified)' then host = nil end
108 if port == '0' then port = nil else port = tonumber(port) end
110 dyn = ( dyn == 'D' and true or false )
111 nat = ( nat == 'N' and true or false )
112 acl = ( acl ~= ' ' and true or false )
114 online, delay = status:match("(OK) %((%d+) ms%)")
116 if online == 'OK' then
118 delay = tonumber(delay)
119 elseif status ~= 'Unmonitored' then
127 id, uid = name:match("(.+)/(.+)")
129 if not ( id and uid ) then
151 --- Get informations of given SIP peer
152 -- @param peer String containing the name of the SIP peer
153 function sip.peer(peer)
157 for line in io.execi("sip show peer " .. peer) do
159 local key, val = line:match("(.-) *: +(.*)")
162 key = key:gsub("^ +",""):gsub(" +$", "")
163 val = val:gsub("^ +",""):gsub(" +$", "")
165 if key == "* Name" then
167 elseif key == "Addr->IP" then
168 info.address, info.port = val:match("(.+) Port (.+)")
169 info.port = tonumber(info.port)
170 elseif key == "Status" then
171 info.online, info.delay = val:match("(OK) %((%d+) ms%)")
172 if info.online == 'OK' then
174 info.delay = tonumber(info.delay)
175 elseif status ~= 'Unmonitored' then
184 if val == 'Yes' or val == 'yes' or val == '<Set>' then
186 elseif val == 'No' or val == 'no' then
188 elseif val == '<Not set>' or val == '(none)' then
202 --- LuCI Asterisk - Internal helpers
204 tools = luci.util.class()
206 --- Convert given value to a list of tokens. Split by white space.
207 -- @param val String or table value
208 -- @return Table containing tokens
209 function tools.parse_list(v)
212 v = type(v) == "table" and v or { v }
213 for _, v in ipairs(v) do
214 if type(v) == "string" then
215 for v in v:gmatch("(%S+)") do
216 tokens[#tokens+1] = v
224 --- Convert given list to a collection of hyperlinks
225 -- @param list Table of tokens
226 -- @param url String pattern or callback function to construct urls (optional)
227 -- @param sep String containing the seperator (optional, default is ", ")
228 -- @return String containing the html fragment
229 function tools.hyperlinks(list, url, sep)
232 local function mkurl(p, t)
233 if type(p) == "string" then
235 elseif type(p) == "function" then
246 for _, token in ipairs(list) do
247 html = ( html and html .. sep or '' ) ..
248 '<a href="%s">%s</a>' %{ mkurl(url, token), token }
255 --- LuCI Asterisk - Dialzone
257 dialzone = luci.util.class()
259 --- Parse a dialzone section
260 -- @param zone Table containing the zone info
261 -- @return Table with parsed information
262 function dialzone.parse(z)
265 trunks = tools.parse_list(z.uses),
267 description = z.description or z['.name'],
268 addprefix = z.addprefix,
269 matches = tools.parse_list(z.match),
270 intlmatches = tools.parse_list(z.international),
271 countrycode = z.countrycode,
272 localzone = z.localzone,
273 localprefix = z.localprefix
278 --- Get a list of known dial zones
279 -- @return Associative table of zones and table of zone names
280 function dialzone.zones()
283 uci:foreach("asterisk", "dialzone",
285 zones[z['.name']] = dialzone.parse(z)
286 znames[#znames+1] = z['.name']
291 --- Get a specific dial zone
292 -- @param name Name of the dial zone
293 -- @return Table containing zone information
294 function dialzone.zone(n)
296 uci:foreach("asterisk", "dialzone",
298 if z['.name'] == n then
299 zone = dialzone.parse(z)
305 --- Find uci section hash for given zone number
306 -- @param idx Zone number
307 -- @return String containing the uci hash pointing to the section
308 function dialzone.ucisection(i)
312 uci:foreach("asterisk", "dialzone",
314 if not hash and index == i then