Software /
code /
prosody-modules
File
mod_remote_roster/mod_remote_roster.lua @ 2491:5fbca7de2088
mod_smacks: Send out more ack requests where needed
Under some circumstances it was possible that more than "max_unacked_stanzas"
where left in the outgoing stanza queue without forcing an ack.
This could happen, when more stanzas entered the queue while the last ack request
was still unanswered.
Now the test "#queue > max_unacked_stanzas" is done upon receiving
an ack as well as when sending out stanzas, which fixes this bug.
author | tmolitor <thilo@eightysoft.de> |
---|---|
date | Sun, 12 Feb 2017 19:27:50 +0100 |
parent | 758:295ae44b8a01 |
child | 5376: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);