Mercurial > prosody-modules
view mod_remote_roster/mod_remote_roster.lua @ 4362:116c88c28532
mod_http_admin_api: restructure group-related info in API
- Return the members of the group right in the get_group_by_id
call. This is an O(1) of extra work.
- Remove the groups attribute from get_user_by_name as that is
O(n) of work and rarely immediately needed.
The replacement for the group membership information in the user
is for now to use the group API and iterate; future work may fix
that.
author | Jonas Schäfer <jonas@wielicki.name> |
---|---|
date | Wed, 20 Jan 2021 15:30:29 +0100 |
parents | 295ae44b8a01 |
children | ad6e9b0fd15b |
line wrap: on
line source
-- -- mod_remote_roster -- -- This is an experimental implementation of http://jkaluza.fedorapeople.org/remote-roster.html -- local st = require "util.stanza"; local jid_split = require "util.jid".split; local jid_prep = require "util.jid".prep; local t_concat = table.concat; local tonumber = tonumber; local pairs, ipairs = pairs, ipairs; local hosts = hosts; local load_roster = require "core.rostermanager".load_roster; local save_roster = require "core.rostermanager".save_roster; 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; local user_exists = require "core.usermanager".user_exists; local add_task = require "util.timer".add_task; module:hook("iq-get/bare/jabber:iq:roster:query", function(event) local origin, stanza = event.origin, event.stanza; if origin.type == "component" and stanza.attr.from == origin.host then local node, host = jid_split(stanza.attr.to); local roster = load_roster(node, host); local reply = st.reply(stanza):query("jabber:iq:roster"); for jid, item in pairs(roster) do if jid ~= "pending" and jid then local node, host = jid_split(jid); if host == origin.host then -- only include contacts which are on this component reply:tag("item", { jid = jid, subscription = item.subscription, ask = item.ask, name = item.name, }); for group in pairs(item.groups) do reply:tag("group"):text(group):up(); end reply:up(); -- move out from item end end end origin.send(reply); --origin.interested = true; -- resource is interested in roster updates return true; end end); module:hook("iq-set/bare/jabber:iq:roster:query", function(event) local session, stanza = event.origin, event.stanza; if not(session.type == "component" and stanza.attr.from == session.host) then return; end local from_node, from_host = jid_split(stanza.attr.to); if not(user_exists(from_node, from_host)) then return; end local roster = load_roster(from_node, from_host); if not(roster) then return; end local query = stanza.tags[1]; if #query.tags == 1 and query.tags[1].name == "item" and query.tags[1].attr.xmlns == "jabber:iq:roster" and query.tags[1].attr.jid -- Protection against overwriting roster.pending, until we move it and query.tags[1].attr.jid ~= "pending" then local item = query.tags[1]; local jid = jid_prep(item.attr.jid); local node, host, resource = jid_split(jid); if not resource and host == session.host then if jid ~= stanza.attr.to then -- not self-jid if item.attr.subscription == "remove" then local r_item = roster[jid]; if r_item then local to_bare = node and (node.."@"..host) or host; -- bare JID --if r_item.subscription == "both" or r_item.subscription == "from" or (roster.pending and roster.pending[jid]) then -- module:send(st.presence({type="unsubscribed", from=stanza.attr.to, to=to_bare})); --end --if r_item.subscription == "both" or r_item.subscription == "to" or r_item.ask then -- module:send(st.presence({type="unsubscribe", from=stanza.attr.to, to=to_bare})); --end roster[jid] = nil; if save_roster(from_node, from_host, roster) then session.send(st.reply(stanza)); rm_roster_push(from_node, from_host, jid); else roster[jid] = item; session.send(st.error_reply(stanza, "wait", "internal-server-error", "Unable to save roster")); end else session.send(st.error_reply(stanza, "modify", "item-not-found")); end else local subscription = item.attr.subscription; if subscription ~= "both" and subscription ~= "to" and subscription ~= "from" and subscription ~= "none" then -- TODO error on invalid subscription = roster[jid] and roster[jid].subscription or "none"; end local r_item = {name = item.attr.name, groups = {}}; if r_item.name == "" then r_item.name = nil; end r_item.subscription = subscription; if subscription ~= "both" and subscription ~= "to" then r_item.ask = roster[jid] and roster[jid].ask; end for _, child in ipairs(item) do if child.name == "group" then local text = t_concat(child); if text and text ~= "" then r_item.groups[text] = true; end end end local olditem = roster[jid]; roster[jid] = r_item; if save_roster(from_node, from_host, roster) then -- Ok, send success session.send(st.reply(stanza)); -- and push change to all resources rm_roster_push(from_node, from_host, jid); else -- Adding to roster failed roster[jid] = olditem; session.send(st.error_reply(stanza, "wait", "internal-server-error", "Unable to save roster")); end end else -- Trying to add self to roster session.send(st.error_reply(stanza, "cancel", "not-allowed")); end else -- Invalid JID added to roster session.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME what's the correct error? end else -- Roster set didn't include a single item, or its name wasn't 'item' session.send(st.error_reply(stanza, "modify", "bad-request")); end return true; end); function component_roster_push(node, host, jid) local roster = load_roster(node, host); if roster then local item = roster[jid]; local contact_node, contact_host = jid_split(jid); local stanza = st.iq({ type="set", from=node.."@"..host, to=contact_host }):query("jabber:iq:roster"); if item then stanza:tag("item", { jid = jid, subscription = item.subscription, name = item.name, ask = item.ask }); for group in pairs(item.groups) do stanza:tag("group"):text(group):up(); end else stanza:tag("item", {jid = jid, subscription = "remove"}); end stanza:up(); -- move out from item stanza:up(); -- move out from stanza module:send(stanza); end end module:hook("iq-set/bare/jabber:iq:roster:query", function(event) local origin, stanza = event.origin, event.stanza; local query = stanza.tags[1]; local item = query.tags[1]; local contact_jid = item and item.name == "item" and item.attr.jid ~= "pending" and item.attr.jid; if contact_jid then local contact_node, contact_host = jid_split(contact_jid); if hosts[contact_host] and hosts[contact_host].type == "component" then local node, host = jid_split(stanza.attr.to or origin.full_jid); add_task(0, function() component_roster_push(node, host, contact_jid); end); end end end, 100);