<?xml version="1.0" encoding="utf-8"?>
<luaLibraries version="1.30.5">
<luaLibrary name="callforward">
<code><![CDATA[
local valid = false
local active = config.get( pathPrefix .. "active" )
local function updateLed()
if not valid then
key:setLed( "orange" )
elseif active == "true" then
key:setLed( "green" )
else
key:setLed( "off" )
end
end
local function checkValid()
local value = config.get( pathPrefix .. "target" )
valid = value and value:len() > 0
end
local function checkActive()
active = config.get( pathPrefix .. "active" )
end
local function configListener( path )
checkValid()
checkActive()
updateLed()
end
function onKeyUp()
--[] check for validity []--
if not valid then
return
end
local value = config.get( pathPrefix .. "active" )
if value == "false" then
config.set( pathPrefix .. "active", "true" )
elseif value == "true" then
config.set( pathPrefix .. "active", "false" )
end
end
config.register( pathPrefix, configListener )
checkValid()
updateLed()]]></code>
</luaLibrary>
<luaLibrary name="subscription_key">
<code><![CDATA[
-- returns a function that needs to be called to start this subscription_key, it takes the following parameters in this order:
local identity = "" -- index of the identity to be used
local activeColor = "green" -- which color to constantly light LED in when subscription reports 'active'
local fctName = "myKeyFct" -- name of this function to use in logs, e.g.: DND or CallForwardWhenBusy
local isValid = function() -- reports if key has all it's params set to valid values. Set to nil to keep this default
if identity == "" or identity == nil then
return false
end
return true
end
local createUri = function(onNotOff, user) -- returns the sip-uri (or at least the user-name-part) to turn the feature
return "" -- either on or off through silent call. user contains the username of the
end -- associated identity
---------------------------------------------------------------------------------------------------------------
local userpath = "/identities/identity[1]/" -- will be overwritten in start()
local subscriptionIsTrying = false
local subscriptionIsWorking = false
local activatedOnServer = false
local inLimbo = false -- true when silent call to change setting is send until new notify is received
local currentLimboTimerId = 42 -- we can only start timers, never stop -> use ID to discard obsoleted timers when they fire
local lastWasOnCmd = false -- whether last silent-call made was to activate the feature or not (aka de-activate)
local user = ""
local domain = ""
local ongoingSubscription = nil
local function updateLed()
if subscriptionIsWorking then
if activatedOnServer then
key:setLed( activeColor )
else
key:setLed( "off" )
end
elseif subscriptionIsTrying then
key:setLed("orange", true) -- trying
else
key:setLed("orange", false) -- failed, nothing can be done atm (phone will auto-retry)
end
end
local function handleNotify(subscr, data, headers)
subscriptionIsWorking = true
subscriptionIsTrying = false
local x = xml.eval(data)
if x ~= nil then
debug.log("received subscr data from "..subscr:getUri() , "i")
inLimbo = false
local set_activatedOnServer = false
for _,dlg in ipairs(x) do
state = dlg:find("state")
if state and state[1] == "trying" then
set_activatedOnServer = true
break
end
end
activatedOnServer = set_activatedOnServer
else
debug.log("received empty notify from "..subscr:getUri() , "e")
end
updateLed()
end
local function unsubscribe()
subscriptionIsWorking = false
subscriptionIsTrying = false
if (ongoingSubscription) then
ongoingSubscription:unsubscribe()
ongoingSubscription = nil
end
end
local function subscriptionTerminated()
subscriptionIsWorking = false
subscriptionIsTrying = false
updateLed()
end
local function onSubscrIsTrying()
subscriptionIsWorking = false
subscriptionIsTrying = true
updateLed()
end
local function subscribe()
unsubscribe()
ongoingSubscription = sip.subscribe{uri=createUri(true, user), onNotify=handleNotify, line=identity,
onTerminated=subscriptionTerminated, onTrying=onSubscrIsTrying}
end
local function resubscribe()
subscriptionIsWorking = false
subscriptionIsTrying = false
if (ongoingSubscription) then
ongoingSubscription:resubscribe()
else
subscribe()
end
end
local function identityChanged(path)
new_user = config.get(userpath .. "username")
new_domain = sip.identities.getDomain(identity);
if new_user ~= user or new_domain ~= domain then
unsubscribe()
user = new_user
domain = new_domain
subscribe()
updateLed()
end
end
local function setupRegChange()
config.register(userpath, identityChanged)
identityChanged()
end
local function newLimboTimer(myId)
timer = function ()
if inLimbo and myId == currentLimboTimerId then
debug.log("no news from server after we've issued a change command, trying to force update through re-subscribing", "w")
resubscribe()
updateLed()
end
end
return timer
end
local function sendCmd (turnItOnNotOff)
lastWasOnCmd = turnItOnNotOff
local url = createUri(turnItOnNotOff, user)
if url == "" or url == nil then
debug.log("there is no way to "..(turnItOnNotOff and "activate " or "deactivate ")..fctName, "e")
else
debug.log("calling server to "..(turnItOnNotOff and "activate " or "deactivate ")..fctName, "d")
if not inLimbo then
inLimbo = true
currentLimboTimerId = currentLimboTimerId + 1
time.callbackIn(newLimboTimer(currentLimboTimerId), 14)
end
sip.invite{uri=url, line=identity, hidden=true}
key:setLed(activeColor, true)
end
end
function onKeyUp()
debug.log(fctName.."-key pressed", "d")
if not isValid() then
debug.log("missing parameter(s), "..fctName.."-key won't work ever", "e")
elseif not ongoingSubscription then
debug.log("subscription had failed before, attempting restart", "i")
subscribe()
updateLed()
elseif not subscriptionIsWorking then
debug.log("subscription is being tried: stopping and restarting", "i")
resubscribe()
updateLed()
else
if inLimbo then
debug.log("no news from server yet, trying the opposite command instead", "i")
sendCmd(not lastWasOnCmd);
else
sendCmd(not activatedOnServer);
end
end
end
local startFkt = function(id, aColor, name, validFkt, cUri)
identity = id
userpath = "/identities/identity["..id.."]/"
activeColor = aColor
fctName = name
createUri = cUri
if validFkt then
isValid = validFkt
end
if isValid() then
setupRegChange()
else
debug.log("missing parameters, "..fctName.."-key won't work", "e")
end
updateLed()
end
return startFkt]]></code>
</luaLibrary>
<luaLibrary name="subscription_key_optional">
<code><![CDATA[
-- key that tries to get a subscription from PBX for feature-code ##8*26 + [relay-id] + # + [user]. If that fails,
-- it enters a compatibility-mode for old pbx'es, were key just assumes/guesses about actual state in pbx
-- returns a function that needs to be called to start this key, it takes the following 4 parameters in this order:
local identity = "1"
local relid = "900"
local fctName = "opt subscr key" -- name of this to use in logs
-- the main difference between relay- and auto_config_switch-templates was, that on key-press the former always send a
-- toggle-cmd to pbx and blinked green for 2 secs while the later always either send a on- or off-cmd and lid the led
-- either green or off:
local isCustomRelay = true
----------------------------------------------------------------------------------------------------------------v
local dtmf_sequenz = "%23%238*26"
local activeBlinkFor2secs = false
local activeColor = "green" -- which color to constantly light LED in when subscription reports 'active'
local fctName = "auto_cfg_enable at "..tostring(key.MODULE)..":"..tostring(key.INDEX) -- name of this to use in logs
local userpath = "/identities/identity["..identity.."]/"
local subscriptionIsTrying = false
local subscriptionIsWorking = false
local activatedOnServer = false
local inLimbo = false -- true when silent call to change setting is send until new notify is received
local currentLimboTimerId = 42 -- we can only start timers, never stop -> use ID to discard obsoleted timers when they fire
local lastWasOnCmd = false -- whether last silent-call made was to activate the feature or not (aka de-activate)
local user = ""
local domain = ""
local ongoingSubscription = nil
-- compatibility-mode with old pbx'es that don't know the subscription:
-- subscription will be stopped and never retried once it fails on first subscr-attempt.
-- State is reset when identity de-registers
local subscriptionWorkedOnce = false -- true when initial subsc-attempt worked
local withSubscription = true -- wether key currently uses subscription. Set to false when first subscr-attempt fails
local isValid = function() -- reports if key has all it's params set to valid values. Set to nil to keep this default
if identity == "" or identity == nil or relid == "" or relid == nil then
return false
end
return true
end
-- sip-uri to call to turn the feature on or off
local function createUri(onNotOff, user)
if isCustomRelay then -- toggle
return dtmf_sequenz..relid.."%23" --"sip:"..##8*26900#
elseif onNotOff then
return dtmf_sequenz..relid.."*1%23" --"sip:"..##8*26900*1#
else
return dtmf_sequenz..relid.."*0%23" --"sip:"..##8*26900*0#
end
end
-- the sip-uri to be used when subscribing for the state of this feature
local function createSubscrUri(user)
return dtmf_sequenz..relid.."%23"..user --"sip:"..##8*26900# + user
end
local function updateLed()
if not withSubscription then
if activeBlinkFor2secs then
activeBlinkFor2secs = false
key:setLed(activeColor, true)
time.sleep("2")
key:setLed("off")
elseif activatedOnServer then
key:setLed(activeColor)
else
key:setLed("off")
end
elseif subscriptionIsWorking then
if activatedOnServer then
key:setLed(activeColor)
else
key:setLed("off")
end
elseif subscriptionIsTrying then
key:setLed("orange", true) -- trying
else
key:setLed("orange", false) -- failed, nothing can be done atm (phone will auto-retry)
end
end
local function handleNotify(subscr, data, headers)
subscriptionIsWorking = true
subscriptionIsTrying = false
local x = xml.eval(data)
if x ~= nil then
debug.log(fctName..": received subscr data from "..subscr:getUri() , "i")
subscriptionWorkedOnce = false -- it worked once, remove marker, we know pbx supports this subscr
inLimbo = false
local set_activatedOnServer = false
for _,dlg in ipairs(x) do
state = dlg:find("state")
if state and state[1] == "trying" then
set_activatedOnServer = true
break
end
end
activatedOnServer = set_activatedOnServer
else
debug.log(fctName..": received empty notify from "..subscr:getUri() , "e")
end
updateLed()
end
local function unsubscribe()
subscriptionIsWorking = false
subscriptionIsTrying = false
if (ongoingSubscription) then
ongoingSubscription:unsubscribe()
ongoingSubscription = nil
end
end
local function subscriptionTerminated()
subscriptionIsWorking = false
subscriptionIsTrying = false
if not subscriptionWorkedOnce then
debug.log(fctName..": initial subscr-attempt failed, entering compatibility mode" , "w")
withSubscription = false
end
updateLed()
end
local function onSubscrIsTrying()
subscriptionIsWorking = false
subscriptionIsTrying = true
updateLed()
end
local function subscribe()
unsubscribe()
if withSubscription then
ongoingSubscription = sip.subscribe{uri=createSubscrUri(user), onNotify=handleNotify, line=identity,
onTerminated=subscriptionTerminated, onTrying=onSubscrIsTrying}
else
debug.log(fctName..": ignoring subscribe-request in compatibility mode", "w")
end
end
local function resubscribe()
subscriptionIsWorking = false
subscriptionIsTrying = false
if (ongoingSubscription) then
ongoingSubscription:resubscribe()
else
subscribe()
end
end
local function identityChanged(path)
new_user = config.get(userpath .. "username")
new_domain = sip.identities.getDomain(identity);
if new_user ~= user or new_domain ~= domain then
unsubscribe()
user = new_user
domain = new_domain
subscribe()
updateLed()
end
end
function onIdRegChg(newState, idIdx)
if newState == "unregistered" then
-- reset subscr-once-compatibility-mode
debug.log(fctName..": reseting compatibility mode un de-register", "i")
withSubscription = not isCustomRelay
subscriptionWorkedOnce = false
subscribe()
updateLed()
end
end
local function setupRegChange()
config.register(userpath, identityChanged)
identityChanged()
sip.identities.listen{ callback=onIdRegChg, line=identity }
end
local function newLimboTimer(myId)
timer = function ()
if inLimbo and myId == currentLimboTimerId then
debug.log(fctName..": no news from server after we've issued a change command, trying to force update through re-subscribing", "w")
resubscribe()
updateLed()
end
end
return timer
end
local function sendCmd (turnItOnNotOff)
lastWasOnCmd = turnItOnNotOff
local url = createUri(turnItOnNotOff, user)
if url == "" or url == nil then
debug.log("there is no way to "..(turnItOnNotOff and "activate " or "deactivate ")..fctName, "e")
else
debug.log("calling server to "..(turnItOnNotOff and "activate " or "deactivate ")..fctName, "d")
if withSubscription then
if not inLimbo then
inLimbo = true
currentLimboTimerId = currentLimboTimerId + 1
time.callbackIn(newLimboTimer(currentLimboTimerId), 14)
end
key:setLed(activeColor, true)
else
if isCustomRelay then
url = dtmf_sequenz..relid.."%23"
sip.invite{uri=url, line=identity, hidden=true}
updateLed()
return
end
activatedOnServer = turnItOnNotOff
updateLed()
end
sip.invite{uri=url, line=identity, hidden=true}
end
end
function onKeyUp()
debug.log(fctName.."-key pressed", "d")
if not isValid() then
debug.log("missing parameter(s), "..fctName.."-key won't work ever", "e")
elseif withSubscription then
if not ongoingSubscription then
debug.log(fctName..": subscription had failed before, attempting restart", "i")
subscribe()
updateLed()
elseif not subscriptionIsWorking then
debug.log(fctName..": subscription is being tried: stopping and restarting", "i")
resubscribe()
updateLed()
else
if inLimbo then
debug.log(fctName..": no news from server yet, trying the opposite command instead", "i")
sendCmd(not lastWasOnCmd);
else
sendCmd(not activatedOnServer);
end
end
else
if isCustomRelay then
debug.log(fctName..": in compatibility mode -> just send on-cmd and let led blink green for 2 secs", "d")
activeBlinkFor2secs = true
sendCmd(true);
updateLed();
else
debug.log(fctName..": in compatibility mode -> just send opposite of previous cmd which was active = "..tostring(activatedOnServer), "d")
sendCmd(not activatedOnServer);
updateLed();
end
end
end
local startFkt = function(id, relayId, name, isCustom)
identity = id
relid = relayId
fctName = name
isCustomRelay = isCustom
withSubscription = not isCustomRelay
userpath = "/identities/identity["..id.."]/"
if isValid() then
setupRegChange()
else
debug.log("missing parameters, "..fctName.."-key won't work", "e")
end
updateLed()
end
return startFkt]]></code>
</luaLibrary>
</luaLibraries>