Software /
code /
prosody
File
plugins/mod_carbons.lua @ 12960:31b22cc221b5
mod_pubsub, mod_pep: Support per-node configurable inclusion of publisher
This matches ejabberd's behaviour, using the 'pubsub#itemreply' config option.
Although the current definition of this option in the specification is not
as clear as it could be, I think matching what existing deployments do is the
best option to resolve the ambiguity and reduce fragmentation.
We should update the spec to be clearer about how to use and interpret this
option.
The 'expose_publisher' option for mod_pubsub is now an override (always expose
or never expose). If unset, it will use the per-node config (which defaults to
not exposing).
Thanks to Link Mauve, edhelas and goffi for sparking this feature.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 22 Mar 2023 11:39:19 +0000 |
parent | 12308:063ce658c181 |
child | 12977:74b9e05af71e |
line wrap: on
line source
-- XEP-0280: Message Carbons implementation for Prosody -- Copyright (C) 2011-2016 Kim Alvefur -- -- This file is MIT/X11 licensed. local st = require "util.stanza"; local jid_bare = require "util.jid".bare; local jid_resource = require "util.jid".resource; local xmlns_carbons = "urn:xmpp:carbons:2"; local xmlns_forward = "urn:xmpp:forward:0"; local full_sessions, bare_sessions = prosody.full_sessions, prosody.bare_sessions; module:add_feature("urn:xmpp:carbons:rules:0"); local function is_bare(jid) return not jid_resource(jid); end local function toggle_carbons(event) local origin, stanza = event.origin, event.stanza; local state = stanza.tags[1].name; module:log("debug", "%s %sd carbons", origin.full_jid, state); origin.want_carbons = state == "enable" and stanza.tags[1].attr.xmlns; origin.send(st.reply(stanza)); return true; end module:hook("iq-set/self/"..xmlns_carbons..":disable", toggle_carbons); module:hook("iq-set/self/"..xmlns_carbons..":enable", toggle_carbons); local function should_copy(stanza, c2s, user_bare) --> boolean, reason: string local st_type = stanza.attr.type or "normal"; if stanza:get_child("private", xmlns_carbons) then return false, "private"; end if stanza:get_child("no-copy", "urn:xmpp:hints") then return false, "hint"; end if not c2s and stanza.attr.to ~= user_bare and stanza:get_child("x", "http://jabber.org/protocol/muc#user") then -- MUC PMs are normally sent to full JIDs return false, "muc-pm"; end if st_type == "chat" then return true, "type"; end if st_type == "normal" and stanza:get_child("body") then return true, "type"; end -- Normal outgoing chat messages are sent to=bare JID. This clause should -- match the error bounces from those, which would have from=bare JID and -- be incoming (not c2s). if st_type == "error" and not c2s and is_bare(stanza.attr.from) then return true, "bounce"; end if stanza:get_child(nil, "urn:xmpp:jingle-message:0") or stanza:get_child(nil, "urn:xmpp:jingle-message:1") then -- XXX Experimental XEP return true, "jingle call"; end if stanza:get_child_with_attr("stanza-id", "urn:xmpp:sid:0", "by", user_bare) then return true, "archived"; end return false, "default"; end module:hook("carbons-should-copy", function (event) local should, why = should_copy(event.stanza); event.reason = why; return should; end, -1) local function message_handler(event, c2s) local origin, stanza = event.origin, event.stanza; local orig_type = stanza.attr.type or "normal"; local orig_from = stanza.attr.from; local bare_from = jid_bare(orig_from); local orig_to = stanza.attr.to; local bare_to = jid_bare(orig_to); -- Stanza sent by a local client local bare_jid = bare_from; -- JID of the local user local target_session = origin; local top_priority = false; local user_sessions = bare_sessions[bare_from]; -- Stanza about to be delivered to a local client if not c2s then bare_jid = bare_to; target_session = full_sessions[orig_to]; user_sessions = bare_sessions[bare_jid]; if not target_session and user_sessions then -- The top resources will already receive this message per normal routing rules, -- so we are going to skip them in order to avoid sending duplicated messages. local top_resources = user_sessions.top_resources; top_priority = top_resources and top_resources[1].priority end end if not user_sessions then module:log("debug", "Skip carbons for offline user"); return -- No use in sending carbons to an offline user end local event_payload = { stanza = stanza; session = origin }; local should = module:fire_event("carbons-should-copy", event_payload); local why = event_payload.reason; if not should then module:log("debug", "Not copying stanza: %s (%s)", stanza:top_tag(), why); if why == "private" and not c2s then stanza:maptags(function(tag) if not ( tag.attr.xmlns == xmlns_carbons and tag.name == "private" ) then return tag; end end); end return; end local carbon; user_sessions = user_sessions and user_sessions.sessions; for _, session in pairs(user_sessions) do -- Carbons are sent to resources that have enabled it if session.want_carbons -- but not the resource that sent the message, or the one that it's directed to and session ~= target_session -- and isn't among the top resources that would receive the message per standard routing rules and (c2s or session.priority ~= top_priority) then if not carbon then -- Create the carbon copy and wrap it as per the Stanza Forwarding XEP local copy = st.clone(stanza); if c2s and not orig_to then stanza.attr.to = bare_from; end copy.attr.xmlns = "jabber:client"; carbon = st.message{ from = bare_jid, type = orig_type, } :tag(c2s and "sent" or "received", { xmlns = xmlns_carbons }) :tag("forwarded", { xmlns = xmlns_forward }) :add_child(copy):reset(); end carbon.attr.to = session.full_jid; module:log("debug", "Sending carbon to %s", session.full_jid); session.send(carbon); end end end local function c2s_message_handler(event) return message_handler(event, true) end -- Stanzas sent by local clients module:hook("pre-message/host", c2s_message_handler, -0.5); module:hook("pre-message/bare", c2s_message_handler, -0.5); module:hook("pre-message/full", c2s_message_handler, -0.5); -- Stanzas to local clients module:hook("message/bare", message_handler, -0.5); module:hook("message/full", message_handler, -0.5); module:add_feature(xmlns_carbons);