From e367490839561de697341c88ef5376af229d5d6d Mon Sep 17 00:00:00 2001 From: Jacob MacElroy Date: Thu, 24 May 2018 15:20:52 +0000 Subject: [PATCH] Properly propagating call id for call response handling. Previously a new call id was generated for INVITE and CANCEL. Now the id generated during the initial INVITE will be used for corresponding CANCEL events. Also, adding the ability to trigger a call cancel via the poltergeist update api. --- resources/prosody-plugins/mod_muc_call.lua | 22 +++- .../prosody-plugins/mod_muc_poltergeist.lua | 120 +++++++++++++----- 2 files changed, 103 insertions(+), 39 deletions(-) diff --git a/resources/prosody-plugins/mod_muc_call.lua b/resources/prosody-plugins/mod_muc_call.lua index ec3d026a9..b5f8ea7a0 100644 --- a/resources/prosody-plugins/mod_muc_call.lua +++ b/resources/prosody-plugins/mod_muc_call.lua @@ -67,17 +67,29 @@ module:hook("muc-broadcast-presence", function (event) return end - local invite = function() - local url = assert(url_from_room_jid(event.stanza.attr.from)) - ext_events.invite(event.stanza, url) + 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 cancel = function() + 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)) + ext_events.cancel(event.stanza, url, string.lower(status), call_id) end + local should_cancel = event.stanza:get_child_text("call_cancel") + if should_cancel == "true" then + cancel() + return + end + local switch = function(status) case = { [calling_status] = function() invite() end, diff --git a/resources/prosody-plugins/mod_muc_poltergeist.lua b/resources/prosody-plugins/mod_muc_poltergeist.lua index 94712b3c2..464bb9b60 100644 --- a/resources/prosody-plugins/mod_muc_poltergeist.lua +++ b/resources/prosody-plugins/mod_muc_poltergeist.lua @@ -108,6 +108,27 @@ function remove_username(room, nick) end end +-- Provides a new presence stanza for a poltergeist. +-- @param room the room instance +-- @param nick the user nick +function generate_poltergeist_presence(room, nick, status) + local presence_stanza = st.presence({ + to = room.jid.."/"..nick, + from = poltergeist_component.."/"..nick, + }):tag("x", { xmlns = MUC_NS }):up(); + + presence_stanza:tag("call_cancel"):text(nil):up(); + presence_stanza:tag("call_id"):text(nil):up(); + + if status then + presence_stanza:tag("status"):text(status):up(); + else + presence_stanza:tag("status"):text(nil):up(); + end + + return presence_stanza; +end + --- Verifies room name, domain name with the values in the token -- @param token the token we received -- @param room_name the room name @@ -182,7 +203,7 @@ prosody.events.add_handler("pre-jitsi-authentication", function(session) if (have_poltergeist_occupant(room, nick)) then -- notify that user connected using the poltergeist update_poltergeist_occupant_status( - room, nick, "connected"); + room, nick, "connected"); remove_poltergeist_occupant(room, nick, true); end @@ -202,10 +223,7 @@ end); function create_poltergeist_occupant(room, nick, name, avatar, status, context) log("debug", "create_poltergeist_occupant %s", nick); -- Join poltergeist occupant to room, with the invited JID as their nick - local join_presence = st.presence({ - to = room.jid.."/"..nick, - from = poltergeist_component.."/"..nick - }):tag("x", { xmlns = MUC_NS }):up(); + local join_presence = generate_poltergeist_presence(room, nick, status) if (name) then join_presence:tag( @@ -215,9 +233,6 @@ function create_poltergeist_occupant(room, nick, name, avatar, status, context) if (avatar) then join_presence:tag("avatar-url"):text(avatar):up(); end - if (status) then - join_presence:tag("status"):text(status):up(); - end -- If the room has a password set, let the poltergeist enter using it local room_password = room:get_password(); @@ -226,6 +241,9 @@ function create_poltergeist_occupant(room, nick, name, avatar, status, context) join:tag("password", { xmlns = MUC_NS }):text(room_password); end + local call_id = get_username(room, context.user.id); + join_presence:tag("call_id"):text(get_username(room, context.user.id)):up(); + update_presence_identity( join_presence, context.user, @@ -278,15 +296,13 @@ end -- @param room the room instance where to remove the occupant -- @param nick the nick of the occupant to remove -- @param status the status to update -function update_poltergeist_occupant_status(room, nick, status) +-- @param call_details is a table of call flow details +function update_poltergeist_occupant_status(room, nick, status, call_details) local update_presence = get_presence(room, nick); if (not update_presence) then -- no presence found for occupant, create one - update_presence = st.presence({ - to = room.jid.."/"..nick, - from = poltergeist_component.."/"..nick - }); + update_presence = generate_poltergeist_presence(room, nick) else -- update occupant presence with appropriate to and from -- so we can send it again @@ -295,31 +311,56 @@ function update_poltergeist_occupant_status(room, nick, status) update_presence.attr.from = poltergeist_component.."/"..nick; end - local once = false; - -- the status tag we will attach - local statusTag = st.stanza("status"):text(status); - - -- if there is already a status tag replace it - update_presence:maptags(function (tag) - if tag.name == statusTag.name then - if not once then - once = true; - return statusTag; - else - return nil; - end - end - return tag; - end); - if (not once) then - -- no status tag was repleced, attach it - update_presence:add_child(statusTag); - end + update_presence = update_presence_tags(update_presence, status, call_details) room:handle_normal_presence( prosody.hosts[poltergeist_component], update_presence); end +-- Updates the status tags and call flow tags of an existing poltergeist's +-- presence. +-- @param presence_stanza is the actual presence stanza for a poltergeist. +-- @param status is the new status to be updated in the stanza. +-- @param call_details is a table of call flow signal information. +function update_presence_tags(presence_stanza, status, call_details) + local call_cancel = false; + local call_id = nil; + + -- Extract optional call flow signal information. + if call_details then + call_id = call_details["id"]; + + if call_details["cancel"] then + call_cancel = call_details["cancel"]; + end + end + + presence_stanza:maptags(function (tag) + if tag.name == "status" then + if call_cancel then + -- If call cancel is set then the status should not be changed. + return tag + end + return st.stanza("status"):text(status); + elseif tag.name == "call_id" then + if call_id then + return st.stanza("call_id"):text(call_id); + else + -- If no call id is provided the re-use the existing id. + return tag; + end + elseif tag.name == "call_cancel" then + if call_cancel then + return st.stanza("call_cancel"):text("true"); + else + return st.stanza("call_cancel"):text("false"); + end + end + end); + + return presence_stanza +end + -- Checks for existance of a poltergeist occupant -- @param room the room instance where to check for occupant -- @param nick the nick of the occupant @@ -436,6 +477,12 @@ function handle_update_poltergeist (event) local room_name = params["room"]; local group = params["group"]; local status = params["status"]; + local call_id = params["callid"]; + + local call_cancel = false + if params["callcancel"] == "true" then + call_cancel = true; + end if not verify_token(params["token"], room_name, group, {}) then return 403; @@ -452,9 +499,14 @@ function handle_update_poltergeist (event) return 404; end + local call_details = { + ["cancel"] = call_cancel; + ["id"] = call_id; + }; + local nick = string.sub(username, 0, 8); if (have_poltergeist_occupant(room, nick)) then - update_poltergeist_occupant_status(room, nick, status); + update_poltergeist_occupant_status(room, nick, status, call_details); return 200; else return 404;