local ext_events = module:require "ext_events" local jid = require "util.jid" -- Options and configuration local poltergeist_component = module:get_option_string( "poltergeist_component", module.host ); local muc_domain_base = module:get_option_string("muc_mapper_domain_base"); if not muc_domain_base then module:log( "warn", "No 'muc_domain_base' option set, unable to send call events." ); return end -- Status strings that trigger call events. local calling_status = "calling" local busy_status = "busy" local rejected_status = "rejected" local connected_status = "connected" local expired_status = "expired" -- url_from_room_jid will determine the url for a conference -- provided a room jid. It is required that muc domain mapping -- is enabled and configured. There are two url formats that are supported. -- The following urls are examples of the supported formats. -- https://meet.jit.si/jitsi/ProductiveMeeting -- https://meet.jit.si/MoreProductiveMeeting -- The urls are derived from portions of the room jid. local function url_from_room_jid(room_jid) local node, _, _ = jid.split(room_jid) if not node then return nil end local target_subdomain, target_node = node:match("^%[([^%]]+)%](.+)$") if not(target_node or target_subdomain) then return "https://"..muc_domain_base.."/"..node else return "https://"..muc_domain_base.."/"..target_subdomain.."/"..target_node end end -- Listening for all muc presences stanza events. If a presence stanza is from -- a poltergeist then it will be further processed to determine if a call -- event should be triggered. Call events are triggered by status strings -- the status strings supported are: -- ------------------------- -- Status | Event Type -- _________________________ -- "calling" | INVITE -- "busy" | CANCEL -- "rejected" | CANCEL -- "connected" | CANCEL module:hook( "muc-broadcast-presence", function (event) -- Detect if the presence is for a poltergeist or not. if not (jid.bare(event.occupant.jid) == poltergeist_component) then return end -- A presence stanza is needed in order to trigger any calls. if not event.stanza then return end local call_id = event.stanza:get_child_text("call_id") if not call_id then module:log("info", "A call id was not provided in the status.") return end local invite = function() local url = assert(url_from_room_jid(event.stanza.attr.from)) ext_events.invite(event.stanza, url, call_id) end local cancel = function() local url = assert(url_from_room_jid(event.stanza.attr.from)) local status = event.stanza:get_child_text("status") ext_events.cancel(event.stanza, url, string.lower(status), call_id) end -- If for any reason call_cancel is set to true then a cancel -- is sent regardless of the rest of the presence info. local should_cancel = event.stanza:get_child_text("call_cancel") if should_cancel == "true" then cancel() return end local missed = function() cancel() ext_events.missed(event.stanza, call_id) end -- All other call flow actions will require a status. if event.stanza:get_child_text("status") == nil then return end local switch = function(status) case = { [calling_status] = function() invite() end, [busy_status] = function() cancel() end, [rejected_status] = function() missed() end, [expired_status] = function() missed() end, [connected_status] = function() cancel() end } if case[status] then case[status]() end end switch(event.stanza:get_child_text("status")) end, -101 );