Mercurial > prosody-modules
view mod_remote_roster/mod_remote_roster.lua @ 5853:97c9b76867ca
mod_log_ringbuffer: Detach event handlers on logging reload (thanks Menel)
Otherwise the global event handlers accumulate, one added each time
logging is reoladed, and each invocation of the signal or event triggers
one dump of each created ringbuffer.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 03 Mar 2024 11:23:40 +0100 |
parents | ad6e9b0fd15b |
children |
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; local new_id = require "util.id".short; 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, id = new_id() }):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);