applications: drop luci-app-asterisk
[project/luci.git] / applications / luci-app-asterisk / luasrc / asterisk.lua
diff --git a/applications/luci-app-asterisk/luasrc/asterisk.lua b/applications/luci-app-asterisk/luasrc/asterisk.lua
deleted file mode 100644 (file)
index da94c55..0000000
+++ /dev/null
@@ -1,746 +0,0 @@
--- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
--- Licensed to the public under the Apache License 2.0.
-
-module("luci.asterisk", package.seeall)
-require("luci.asterisk.cc_idd")
-
-local _io  = require("io")
-local uci  = require("luci.model.uci").cursor()
-local sys  = require("luci.sys")
-local util = require("luci.util")
-
-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
-io = luci.util.class()
-
---- Execute command and return output
--- @param command      String containing the command to execute
--- @return                     String containing the command output
-function io.exec(command)
-       local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
-       assert(fh, "Failed to invoke asterisk")
-
-       local buffer = fh:read("*a")
-       fh:close()
-       return buffer
-end
-
---- Execute command and invoke given callback for each read line
--- @param command      String containing the command to execute
--- @param callback     Function to call back for each line
--- @return                     Always true
-function io.execl(command, callback)
-       local ln
-       local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
-       assert(fh, "Failed to invoke asterisk")
-
-       repeat
-               ln = fh:read("*l")
-               callback(ln)
-       until not ln
-
-       fh:close()
-       return true
-end
-
---- Execute command and return an iterator that returns one line per invocation
--- @param command      String containing the command to execute
--- @return                     Iterator function
-function io.execi(command)
-       local fh = _io.popen( "%s %s %q" %{ AST_BIN, AST_FLAGS, command }, "r" )
-       assert(fh, "Failed to invoke asterisk")
-
-       return function()
-               local ln = fh:read("*l")
-               if not ln then fh:close() end
-               return ln
-       end
-end
-
-
---- LuCI Asterisk - core status
-core = luci.util.class()
-
---- Retrieve version string.
--- @return     String containing the reported asterisk version
-function core.version(self)
-       local version = io.exec("core show version")
-       return version:gsub(" *\n", "")
-end
-
-
---- LuCI Asterisk - SIP information.
--- @type module
-sip = luci.util.class()
-
---- Get a list of known SIP peers
--- @return             Table containing each SIP peer
-function sip.peers(self)
-       local head  = false
-       local peers = { }
-
-       for line in io.execi("sip show peers") do
-               if not head then
-                       head = true
-               elseif not line:match(" sip peers ") then
-                       local online, delay, id, uid
-                       local name, host, dyn, nat, acl, port, status =
-                               line:match("(.-) +(.-) +([D ])   ([N ])   (.)  (%d+) +(.+)")
-
-                       if host == '(Unspecified)' then host = nil end
-                       if port == '0' then port = nil else port = tonumber(port) end
-
-                       dyn = ( dyn == 'D' and true or false )
-                       nat = ( nat == 'N' and true or false )
-                       acl = ( acl ~= ' ' and true or false )
-
-                       online, delay = status:match("(OK) %((%d+) ms%)")
-
-                       if online == 'OK' then
-                               online = true
-                               delay  = tonumber(delay)
-                       elseif status ~= 'Unmonitored' then
-                               online = false
-                               delay  = 0
-                       else
-                               online = nil
-                               delay  = 0
-                       end
-
-                       id, uid = name:match("(.+)/(.+)")
-
-                       if not ( id and uid ) then
-                               id  = name .. "..."
-                               uid = nil
-                       end
-
-                       peers[#peers+1] = {
-                               online  = online,
-                               delay   = delay,
-                               name    = id,
-                               user    = uid,
-                               dynamic = dyn,
-                               nat     = nat,
-                               acl     = acl,
-                               host    = host,
-                               port    = port
-                       }
-               end
-       end
-
-       return peers
-end
-
---- Get information of given SIP peer
--- @param peer String containing the name of the SIP peer
-function sip.peer(peer)
-       local info = { }
-       local keys = { }
-
-       for line in io.execi("sip show peer " .. peer) do
-               if #line > 0 then
-                       local key, val = line:match("(.-) *: +(.*)")
-                       if key and val then
-
-                               key = key:gsub("^ +",""):gsub(" +$", "")
-                               val = val:gsub("^ +",""):gsub(" +$", "")
-
-                               if key == "* Name" then
-                                       key = "Name"
-                               elseif key == "Addr->IP" then
-                                       info.address, info.port = val:match("(.+) Port (.+)")
-                                       info.port = tonumber(info.port)
-                               elseif key == "Status" then
-                                       info.online, info.delay = val:match("(OK) %((%d+) ms%)")
-                                       if info.online == 'OK' then
-                                               info.online = true
-                                               info.delay  = tonumber(info.delay)
-                                       elseif status ~= 'Unmonitored' then
-                                               info.online = false
-                                               info.delay  = 0
-                                       else
-                                               info.online = nil
-                                               info.delay  = 0
-                                       end
-                               end
-
-                               if val == 'Yes' or val == 'yes' or val == '<Set>' then
-                                       val = true
-                               elseif val == 'No' or val == 'no' then
-                                       val = false
-                               elseif val == '<Not set>' or val == '(none)' then
-                                       val = nil
-                               end
-
-                               keys[#keys+1] = key
-                               info[key] = val
-                       end
-               end
-       end
-
-       return info, keys
-end
-
-
---- LuCI Asterisk - Internal helpers
--- @type module
-tools = luci.util.class()
-
---- Convert given value to a list of tokens. Split by white space.
--- @param val  String or table value
--- @return             Table containing tokens
-function tools.parse_list(v)
-       local tokens = { }
-
-       v = type(v) == "table" and v or { v }
-       for _, v in ipairs(v) do
-               if type(v) == "string" then
-                       for v in v:gmatch("(%S+)") do
-                               tokens[#tokens+1] = v
-                       end
-               end
-       end
-
-       return tokens
-end
-
---- Convert given list to a collection of hyperlinks
--- @param list Table of tokens
--- @param url  String pattern or callback function to construct urls (optional)
--- @param sep  String containing the separator (optional, default is ", ")
--- @return             String containing the html fragment
-function tools.hyperlinks(list, url, sep)
-       local html
-
-       local function mkurl(p, t)
-               if type(p) == "string" then
-                       return p:format(t)
-               elseif type(p) == "function" then
-                       return p(t)
-               else
-                       return '#'
-               end
-       end
-
-       list = list or { }
-       url  = url  or "%s"
-       sep  = sep  or ", "
-
-       for _, token in ipairs(list) do
-               html = ( html and html .. sep or '' ) ..
-                       '<a href="%s">%s</a>' %{ mkurl(url, token), token }
-       end
-
-       return html or ''
-end
-
-
---- LuCI Asterisk - International Direct Dialing Prefixes
--- @type module
-idd = luci.util.class()
-
---- Lookup the country name for the given IDD code.
--- @param country      String containing IDD code
--- @return                     String containing the country name
-function idd.country(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if type(v[3]) == "table" then
-                       for _, v2 in ipairs(v[3]) do
-                               if v2 == tostring(c) then
-                                       return v[1]
-                               end
-                       end
-               elseif v[3] == tostring(c) then
-                       return v[1]
-               end
-       end
-end
-
---- Lookup the country code for the given IDD code.
--- @param country      String containing IDD code
--- @return                     Table containing the country code(s)
-function idd.cc(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if type(v[3]) == "table" then
-                       for _, v2 in ipairs(v[3]) do
-                               if v2 == tostring(c) then
-                                       return type(v[2]) == "table"
-                                               and v[2] or { v[2] }
-                               end
-                       end
-               elseif v[3] == tostring(c) then
-                       return type(v[2]) == "table"
-                               and v[2] or { v[2] }
-               end
-       end
-end
-
---- Lookup the IDD code(s) for the given country.
--- @param idd          String containing the country name
--- @return                     Table containing the IDD code(s)
-function idd.idd(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if v[1]:lower():match(c:lower()) then
-                       return type(v[3]) == "table"
-                               and v[3] or { v[3] }
-               end
-       end
-end
-
---- Populate given CBI field with IDD codes.
--- @param field                CBI option object
--- @return                     (nothing)
-function idd.cbifill(o)
-       for i, v in ipairs(cc_idd.CC_IDD) do
-               o:value("_%i" % i, util.pcdata(v[1]))
-       end
-
-       o.formvalue = function(...)
-               local val = luci.cbi.Value.formvalue(...)
-               if val:sub(1,1) == "_" then
-                       val = tonumber((val:gsub("^_", "")))
-                       if val then
-                               return type(cc_idd.CC_IDD[val][3]) == "table"
-                                       and cc_idd.CC_IDD[val][3] or { cc_idd.CC_IDD[val][3] }
-                       end
-               end
-               return val
-       end
-
-       o.cfgvalue = function(...)
-               local val = luci.cbi.Value.cfgvalue(...)
-               if val then
-                       val = tools.parse_list(val)
-                       for i, v in ipairs(cc_idd.CC_IDD) do
-                               if type(v[3]) == "table" then
-                                       if v[3][1] == val[1] then
-                                               return "_%i" % i
-                                       end
-                               else
-                                       if v[3] == val[1] then
-                                               return "_%i" % i
-                                       end
-                               end
-                       end
-               end
-               return val
-       end
-end
-
-
---- LuCI Asterisk - Country Code Prefixes
--- @type module
-cc = luci.util.class()
-
---- Lookup the country name for the given CC code.
--- @param country      String containing CC code
--- @return                     String containing the country name
-function cc.country(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if type(v[2]) == "table" then
-                       for _, v2 in ipairs(v[2]) do
-                               if v2 == tostring(c) then
-                                       return v[1]
-                               end
-                       end
-               elseif v[2] == tostring(c) then
-                       return v[1]
-               end
-       end
-end
-
---- Lookup the international dialing code for the given CC code.
--- @param cc           String containing CC code
--- @return                     String containing IDD code
-function cc.idd(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if type(v[2]) == "table" then
-                       for _, v2 in ipairs(v[2]) do
-                               if v2 == tostring(c) then
-                                       return type(v[3]) == "table"
-                                               and v[3] or { v[3] }
-                               end
-                       end
-               elseif v[2] == tostring(c) then
-                       return type(v[3]) == "table"
-                               and v[3] or { v[3] }
-               end
-       end
-end
-
---- Lookup the CC code(s) for the given country.
--- @param country      String containing the country name
--- @return                     Table containing the CC code(s)
-function cc.cc(c)
-       for _, v in ipairs(cc_idd.CC_IDD) do
-               if v[1]:lower():match(c:lower()) then
-                       return type(v[2]) == "table"
-                               and v[2] or { v[2] }
-               end
-       end
-end
-
---- Populate given CBI field with CC codes.
--- @param field                CBI option object
--- @return                     (nothing)
-function cc.cbifill(o)
-       for i, v in ipairs(cc_idd.CC_IDD) do
-               o:value("_%i" % i, util.pcdata(v[1]))
-       end
-
-       o.formvalue = function(...)
-               local val = luci.cbi.Value.formvalue(...)
-               if val:sub(1,1) == "_" then
-                       val = tonumber((val:gsub("^_", "")))
-                       if val then
-                               return type(cc_idd.CC_IDD[val][2]) == "table"
-                                       and cc_idd.CC_IDD[val][2] or { cc_idd.CC_IDD[val][2] }
-                       end
-               end
-               return val
-       end
-
-       o.cfgvalue = function(...)
-               local val = luci.cbi.Value.cfgvalue(...)
-               if val then
-                       val = tools.parse_list(val)
-                       for i, v in ipairs(cc_idd.CC_IDD) do
-                               if type(v[2]) == "table" then
-                                       if v[2][1] == val[1] then
-                                               return "_%i" % i
-                                       end
-                               else
-                                       if v[2] == val[1] then
-                                               return "_%i" % i
-                                       end
-                               end
-                       end
-               end
-               return val
-       end
-end
-
-
---- LuCI Asterisk - Dialzone
--- @type       module
-dialzone = luci.util.class()
-
---- Parse a dialzone section
--- @param zone Table containing the zone info
--- @return             Table with parsed information
-function dialzone.parse(z)
-       if z['.name'] then
-               return {
-                       trunks          = tools.parse_list(z.uses),
-                       name            = z['.name'],
-                       description     = z.description or z['.name'],
-                       addprefix       = z.addprefix,
-                       matches         = tools.parse_list(z.match),
-                       intlmatches     = tools.parse_list(z.international),
-                       countrycode     = z.countrycode,
-                       localzone       = z.localzone,
-                       localprefix     = z.localprefix
-               }
-       end
-end
-
---- Get a list of known dial zones
--- @return             Associative table of zones and table of zone names
-function dialzone.zones()
-       local zones  = { }
-       local znames = { }
-       uci:foreach("asterisk", "dialzone",
-               function(z)
-                       zones[z['.name']] = dialzone.parse(z)
-                       znames[#znames+1] = z['.name']
-               end)
-       return zones, znames
-end
-
---- Get a specific dial zone
--- @param name Name of the dial zone
--- @return             Table containing zone information
-function dialzone.zone(n)
-       local zone
-       uci:foreach("asterisk", "dialzone",
-               function(z)
-                       if z['.name'] == n then
-                               zone = dialzone.parse(z)
-                       end
-               end)
-       return zone
-end
-
---- Find uci section hash for given zone number
--- @param idx  Zone number
--- @return             String containing the uci hash pointing to the section
-function dialzone.ucisection(i)
-       local hash
-       local index = 1
-       i = tonumber(i)
-       uci:foreach("asterisk", "dialzone",
-               function(z)
-                       if not hash and index == i then
-                               hash = z['.name']
-                       end
-                       index = index + 1
-               end)
-       return hash
-end
-
-
---- LuCI Asterisk - Voicemailbox
--- @type       module
-voicemail = luci.util.class()
-
---- Parse a voicemail section
--- @param zone Table containing the mailbox info
--- @return             Table with parsed information
-function voicemail.parse(z)
-       if z.number and #z.number > 0 then
-               local v = {
-                       id                      = '%s@%s' %{ z.number, z.context or 'default' },
-                       number          = z.number,
-                       context         = z.context     or 'default',
-                       name            = z.name                or z['.name'] or 'OpenWrt',
-                       zone            = z.zone                or 'homeloc',
-                       password        = z.password    or '0000',
-                       email           = z.email               or '',
-                       page            = z.page                or '',
-                       dialplans       = { }
-               }
-
-               uci:foreach("asterisk", "dialplanvoice",
-                       function(s)
-                               if s.dialplan and #s.dialplan > 0 and
-                                  s.voicebox == v.number
-                               then
-                                       v.dialplans[#v.dialplans+1] = s.dialplan
-                               end
-                       end)
-
-               return v
-       end
-end
-
---- Get a list of known voicemail boxes
--- @return             Associative table of boxes and table of box numbers
-function voicemail.boxes()
-       local vboxes = { }
-       local vnames = { }
-       uci:foreach("asterisk", "voicemail",
-               function(z)
-                       local v = voicemail.parse(z)
-                       if v then
-                               local n = '%s@%s' %{ v.number, v.context }
-                               vboxes[n]  = v
-                               vnames[#vnames+1] = n
-                       end
-               end)
-       return vboxes, vnames
-end
-
---- Get a specific voicemailbox
--- @param number       Number of the voicemailbox
--- @return                     Table containing mailbox information
-function voicemail.box(n)
-       local box
-       n = n:gsub("@.+$","")
-       uci:foreach("asterisk", "voicemail",
-               function(z)
-                       if z.number == tostring(n) then
-                               box = voicemail.parse(z)
-                       end
-               end)
-       return box
-end
-
---- Find all voicemailboxes within the given dialplan
--- @param plan Dialplan name or table
--- @return             Associative table containing extensions mapped to mailbox info
-function voicemail.in_dialplan(p)
-       local plan  = type(p) == "string" and p or p.name
-       local boxes = { }
-       uci:foreach("asterisk", "dialplanvoice",
-               function(s)
-                       if s.extension and #s.extension > 0 and s.dialplan == plan then
-                               local box = voicemail.box(s.voicebox)
-                               if box then
-                                       boxes[s.extension] = box
-                               end
-                       end
-               end)
-       return boxes
-end
-
---- Remove voicemailbox and associated extensions from config
--- @param box  Voicemailbox number or table
--- @param ctx  UCI context to use (optional)
--- @return             Boolean indicating success
-function voicemail.remove(v, ctx)
-       ctx = ctx or uci
-       local box = type(v) == "string" and v or v.number
-       local ok1 = ctx:delete_all("asterisk", "voicemail", {number=box})
-       local ok2 = ctx:delete_all("asterisk", "dialplanvoice", {voicebox=box})
-       return ( ok1 or ok2 ) and true or false
-end
-
-
---- LuCI Asterisk - MeetMe Conferences
--- @type       module
-meetme = luci.util.class()
-
---- Parse a meetme section
--- @param room Table containing the room info
--- @return             Table with parsed information
-function meetme.parse(r)
-       if r.room and #r.room > 0 then
-               local v = {
-                       room            = r.room,
-                       pin                     = r.pin                         or '',
-                       adminpin        = r.adminpin            or '',
-                       description = r._description    or '',
-                       dialplans       = { }
-               }
-
-               uci:foreach("asterisk", "dialplanmeetme",
-                       function(s)
-                               if s.dialplan and #s.dialplan > 0 and s.room == v.room then
-                                       v.dialplans[#v.dialplans+1] = s.dialplan
-                               end
-                       end)
-
-               return v
-       end
-end
-
---- Get a list of known meetme rooms
--- @return             Associative table of rooms and table of room numbers
-function meetme.rooms()
-       local mrooms = { }
-       local mnames = { }
-       uci:foreach("asterisk", "meetme",
-               function(r)
-                       local v = meetme.parse(r)
-                       if v then
-                               mrooms[v.room] = v
-                               mnames[#mnames+1] = v.room
-                       end
-               end)
-       return mrooms, mnames
-end
-
---- Get a specific meetme room
--- @param number       Number of the room
--- @return                     Table containing room information
-function meetme.room(n)
-       local room
-       uci:foreach("asterisk", "meetme",
-               function(r)
-                       if r.room == tostring(n) then
-                               room = meetme.parse(r)
-                       end
-               end)
-       return room
-end
-
---- Find all meetme rooms within the given dialplan
--- @param plan Dialplan name or table
--- @return             Associative table containing extensions mapped to room info
-function meetme.in_dialplan(p)
-       local plan  = type(p) == "string" and p or p.name
-       local rooms = { }
-       uci:foreach("asterisk", "dialplanmeetme",
-               function(s)
-                       if s.extension and #s.extension > 0 and s.dialplan == plan then
-                               local room = meetme.room(s.room)
-                               if room then
-                                       rooms[s.extension] = room
-                               end
-                       end
-               end)
-       return rooms
-end
-
---- Remove meetme room and associated extensions from config
--- @param room Voicemailbox number or table
--- @param ctx  UCI context to use (optional)
--- @return             Boolean indicating success
-function meetme.remove(v, ctx)
-       ctx = ctx or uci
-       local room = type(v) == "string" and v or v.number
-       local ok1  = ctx:delete_all("asterisk", "meetme", {room=room})
-       local ok2  = ctx:delete_all("asterisk", "dialplanmeetme", {room=room})
-       return ( ok1 or ok2 ) and true or false
-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']
-               }
-
-               -- dialzones
-               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
-
-               -- voicemailboxes
-               plan.voicemailboxes = voicemail.in_dialplan(plan)
-
-               -- meetme conferences
-               plan.meetmerooms = meetme.in_dialplan(plan)
-
-               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