Diff

plugins/mod_carbons.lua @ 11120:b2331f3dfeea

Merge 0.11->trunk
author Matthew Wild <mwild1@gmail.com>
date Wed, 30 Sep 2020 09:50:33 +0100
parent 10820:e0a09d3af563
child 11260:08b397c21805
line wrap: on
line diff
--- a/plugins/mod_carbons.lua	Thu Oct 01 15:08:58 2020 +0100
+++ b/plugins/mod_carbons.lua	Wed Sep 30 09:50:33 2020 +0100
@@ -5,10 +5,15 @@
 
 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;
 
+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;
@@ -20,6 +25,50 @@
 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") then
+		-- XXX Experimental XEP stuck in Proposed for almost a year at the time of this comment
+		return true, "jingle call";
+	end
+
+	for archived in stanza:childtags("stanza-id", "urn:xmpp:sid:0") do
+		if archived and archived.attr.by == user_bare then
+			return true, "archived";
+		end
+	end
+
+	return false, "default";
+end
+
 local function message_handler(event, c2s)
 	local origin, stanza = event.origin, event.stanza;
 	local orig_type = stanza.attr.type or "normal";
@@ -28,10 +77,6 @@
 	local orig_to = stanza.attr.to;
 	local bare_to = jid_bare(orig_to);
 
-	if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body"))) then
-		return -- Only chat type messages
-	end
-
 	-- Stanza sent by a local client
 	local bare_jid = bare_from; -- JID of the local user
 	local target_session = origin;
@@ -56,35 +101,21 @@
 		return -- No use in sending carbons to an offline user
 	end
 
-	if stanza:get_child("private", xmlns_carbons) then
-		if not c2s then
+	local should, why = should_copy(stanza, c2s, bare_jid);
+
+	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
-		module:log("debug", "Message tagged private, ignoring");
-		return
-	elseif stanza:get_child("no-copy", "urn:xmpp:hints") then
-		module:log("debug", "Message has no-copy hint, ignoring");
-		return
-	elseif not c2s and bare_jid ~= orig_to and stanza:get_child("x", "http://jabber.org/protocol/muc#user") then
-		module:log("debug", "MUC PM, ignoring");
-		return
+		return;
 	end
 
-	-- 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";
-	local 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();
-
+	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
@@ -93,6 +124,20 @@
 		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);