mix_pam: Add roster changes and keep track of SPIDs

This commit is contained in:
PapaTutuWawa 2020-11-02 17:07:20 +01:00
parent 53e53efa44
commit e09f4ebcd3

View File

@ -1,23 +1,58 @@
if module:get_host() ~= "*" then
local host = module:get_host()
--[[
if host ~= "*" then
module:log("error", "mix_pam should be used on the user host!");
end
]]--
local jid = require("util.jid");
local st = require("util.stanza");
local rm_remove_from_roster = require("core.rostermanager").remove_from_roster;
local rm_add_to_roster = require("core.rostermanager").add_to_roster;
local rm_roster_push = require("core.rostermanager").roster_push;
-- Persistent storage
local mix_pam = module:open_store("mix_pam", "keyval");
-- Runtime data
local mix_hosts = {};
local mix_spids = {}; -- user -> channel -> spid
-- Namespaceing
local mix_pam_xmlns = "urn:xmpp:mix:pam:2";
local mix_roster_xmlns = "urn:xmpp:mix:roster:0";
module:add_feature(mix_pam_xmlns);
-- NOTE: To show that we archive messages
-- module:add_feature(mix_pam_xmlns.."#archive");
function contains_key(table, key)
-- Returns true if table contains the key key. Returns false
-- otherwise.
return table[key] ~= nil;
end
function set_mix_spid(user, channel, spid)
if mix_spids[user] ~= nil then
mix_spids[user][channel] = spid;
else
mix_spids[user] = { [channel] = spid };
end
mix_pam:set("spids", mix_spids);
end
function get_mix_spid(user, channel)
return mix_spids[user][channel];
end;
function remove_mix_spid(user, channel)
mix_spids[user][channel] = nil;
if mix_spids[user][channel] == {} then
mix_spids[user][channel] = nil;
end
mix_pam:set("spids", mix_spids);
end
function add_mix_host(host)
if mix_hosts[host] ~= nil then
mix_hosts[host] = mix_hosts[host] + 1;
@ -26,6 +61,8 @@ function add_mix_host(host)
module:log("debug", "Added %s as a new MIX host", host);
mix_hosts[host] = 1;
end
mix_pam:set("hosts", mix_hosts);
end
function remove_mix_host(host)
@ -41,6 +78,8 @@ function remove_mix_host(host)
else
module:log("debug", "Attempt to remove unknown MIX host");
end
mix_pam:set("hosts", mix_hosts);
end
function is_mix_host(host)
@ -58,11 +97,28 @@ function module.load()
if mix_hosts == nil then
module:log("info", "No known MIX hosts loaded");
mix_hosts = {};
return;
end
for _, host in pairs(mix_hosts) do
for host, _ in pairs(mix_hosts) do
module:log("debug", "Known host: %s", host);
end
mix_spids = mix_pam:get("spids");
module:log("info", "Loaded known MIX SPIDs");
if mix_spids == nil then
module:log("info", "No known MIX SPIDs loaded");
mix_spids = {};
end
for user, channel_map in pairs(mix_spids) do
module:log("debug", "-- %s", user);
if channel_map[user] then
for channel, spid in pairs(channel_map[user]) do
module:log("debug", "%s -> %s", channel, spid);
end
else
module:log("warn", "User mapping empty");
end
end
end
local client_state_tracker = {}; -- [stanza ID] -> resource
@ -117,7 +173,7 @@ function handle_client_join(event)
local join_iq = st.iq({ type = "set", from = jid.bare(stanza.attr.from), to = client_join.attr.channel, id = stanza.attr.id, xmlns = "jabber:client" });
join_iq:add_child(join);
add_state(stanza.attr.id, jid.resource(stanza.attr.from));
add_state(stanza.attr.id, origin);
module:send(join_iq);
return true;
@ -144,7 +200,7 @@ function handle_client_leave(event)
local leave_iq = st.iq({ type = "set", from = jid.bare(stanza.attr.from), to = client_leave.attr.channel, id = stanza.attr.id });
leave_iq:add_child(leave);
add_state(stanza.attr.id, jid.resource(stanza.attr.from));
add_state(stanza.attr.id, origin);
module:send(leave_iq);
return true;
@ -168,44 +224,66 @@ end);
function handle_mix_join(event)
-- The MIX server responded
-- TODO: Do stuff to the user's roster
module:log("debug", "Received MIX-JOIN result");
module:log("debug", "Adding %s as a new MIX host", jid.host(event.stanza.attr.from));
add_mix_host(jid.host(event.stanza.attr.from));
mix_pam:set("hosts", mix_hosts);
local stanza = event.stanza;
local channel_jid = stanza:get_child("join", "urn:xmpp:mix:core:1").attr.id.."#"..stanza.attr.from;
local resource = pop_state(stanza.attr.id);
local spid = stanza:get_child("join", "urn:xmpp:mix:core:1").attr.id;
local channel_jid = spid.."#"..stanza.attr.from;
local origin = pop_state(stanza.attr.id);
local resource = origin.resource;
if resource == nil then
module:log("error", "Got a MIX join result for a not-requested id %s. Maybe the MIX server changed the stanza ID?", stanza.attr.id);
return false;
end
-- Keep track of the SPID
set_mix_spid(stanza.attr.to, stanza.attr.from, spid);
local client_join = st.iq({ type = "result", id = stanza.attr.id, from = jid.bare(stanza.attr.to), to = stanza.attr.to.."/"..resource })
:tag("client-join", { xmlns = mix_pam_xmlns, jid = channel_jid });
client_join:add_child(stanza:get_child("join", "urn:xmpp:mix:core:1"));
module:send(client_join);
-- TODO: Error handling?
rm_add_to_roster(origin, stanza.attr.from, {
subscription = "both",
groups = {},
});
rm_roster_push(jid.node(stanza.attr.to), host, stanza.attr.from);
return true;
end
function handle_mix_leave(event)
-- The MIX server responded
-- TODO: Do stuff to the user's roster
module:log("debug", "Received MIX-LEAVE result");
remove_mix_host(jid.host(event.stanza.attr.from));
mix_pam:set("hosts", mix_hosts);
local stanza = event.stanza;
local resource = pop_state(stanza.attr.id);
local origin = pop_state(stanza.attr.id);
local resource = origin.resource;
if resource == nil then
module:log("error", "Got a MIX leave result for a not-requested id %s. Maybe the MIX server changed the stanza ID?", stanza.attr.id);
return false;
end
-- Keep track of the SPID
set_mix_spid(stanza.attr.to, jid.bare(stanza.attr.from));
local client_leave = st.iq({ type = "result", id = stanza.attr.id, from = jid.bare(stanza.attr.to), to = stanza.attr.to.."/"..resource })
:tag("client-leave", { xmlns = mix_pam_xmlns });
client_leave:add_child(stanza:get_child("leave", "urn:xmpp:mix:core:1"));
module:send(client_leave);
-- Remove from roster
-- TODO: Error handling
rm_remove_from_roster(origin, jid.bare(stanza.attr.from));
rm_roster_push(jid.node(stanza.attr.to), host, jid.bare(stanza.attr.from));
return true;
end
@ -238,6 +316,29 @@ module:hook("resource-unbind", function(event)
module:log("debug", "Unbind of not recorded resource %s (%s)", resource, jid);
end);
module:hook("roster-get", function(event)
-- NOTE: Currently this requires a patch to make mod_roster emit
-- the roster-get event
local annotate = event.stanza
:get_child("query", "jabber:iq:roster")
:get_child("annotate", mix_roster_xmlns);
if not annotate then return; end
local reply, stanza = event.reply, event.stanza;
module:log("debug", "Annotated roster request received");
-- User requested the roster with an <annotate/>
for item in event.reply:get_child("query", "jabber:iq:roster"):children() do
if contains_key(mix_hosts, jid.host(item.attr.jid)) then
local spid = get_mix_spid(jid.bare(stanza.attr.from), item.attr.jid);
item:tag("channel", {
xmlns = mix_roster_xmlns,
["participant-id"] = spid,
});
end
end
end);
module:hook("message/bare", function(event)
local stanza = event.stanza;
local host = jid.host(stanza.attr.from);