view mod_carbons/mod_carbons.lua @ 737:e4ea03b060ed

mod_archive: switch from/to The XEP-0136 is not very explicit about the meening of <from> and <to> elements, but the examples are clear: <from> means it comes from the user in the 'with' attribute of the collection. That is the opposite of what is currently implemented in that module. So for better compatibility with complient clients, this switch the 'from' and 'to' fields
author Olivier Goffart <ogoffart@woboq.com>
date Wed, 04 Jul 2012 14:08:43 +0200
parents 2f11d2473afd
children 5f7dd5336dbe
line wrap: on
line source

-- XEP-0280: Message Carbons implementation for Prosody
-- Copyright (C) 2011 Kim Alvefur
--
-- This file is MIT/X11 licensed.

local st = require "util.stanza";
local jid_bare = require "util.jid".bare;
local jid_split = require "util.jid".split;
local xmlns_carbons = "urn:xmpp:carbons:1";
local xmlns_forward = "urn:xmpp:forward:0";
local host_sessions = hosts[module.host].sessions;

module:hook("iq/self/"..xmlns_carbons..":enable", function(event)
	local origin, stanza = event.origin, event.stanza;
	if stanza.attr.type == "set" then
		module:log("debug", "%s enabled carbons", origin.full_jid);
		origin.want_carbons = true;
		origin.send(st.reply(stanza));
		return true
	end
end);

module:hook("iq/self/"..xmlns_carbons..":disable", function(event)
	local origin, stanza = event.origin, event.stanza;
	if stanza.attr.type == "set" then
		module:log("debug", "%s disabled carbons", origin.full_jid);
		origin.want_carbons = nil;
		origin.send(st.reply(stanza));
		return true
	end
end);

local function message_handler(event, c2s)
	local origin, stanza = event.origin, event.stanza;
	local orig_type = stanza.attr.type;
	local orig_to = stanza.attr.to;
	local orig_from = stanza.attr.from;
	
	if not (orig_type == nil
			or orig_type == "normal"
			or orig_type == "chat") then
		return -- No carbons for messages of type error or headline
	end

	local bare_jid, user_sessions;
	local no_carbon_to = {};
	module:log("debug", "Message from %s to %s", tostring(orig_from), tostring(orig_to));
	if c2s then -- Stanza sent by a local client
		bare_jid = (origin.username.."@"..origin.host)
		user_sessions = host_sessions[origin.username];
	else -- Stanza about to be delivered to a local client
		local username, hostname, resource = jid_split(orig_to);
		bare_jid = jid_bare(orig_to);
		user_sessions = host_sessions[username];
		if resource then
			module:log("debug", "Message was to resource %s, it will not get carbon", resource);
			no_carbon_to[resource] = true;
		elseif user_sessions then
			local top_resources = user_sessions.top_resources;
			if top_resources then
				for _, session in ipairs(top_resources) do
					module:log("debug", "Not sending carbons to top resource %s", session.resource);
					no_carbon_to[session.resource] = true;
				end
			end
		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

	if not c2s and stanza:get_child("private", xmlns_carbons) then
		stanza:maptags(function(tag)
			return tag.attr.xmlns == xmlns_carbons
				and tag.name == "private" and tag or nil;
		end);
		module:log("debug", "Message tagged private, ignoring");
		return
	end

	local msg = st.clone(stanza);
	msg.attr.xmlns = msg.attr.xmlns or "jabber:client";
	local fwd = st.message{ from = bare_jid, type = orig_type, }
		:tag(c2s and "sent" or "received", { xmlns = xmlns_carbons }):up()
			:tag("forwarded", { xmlns = xmlns_forward })
				:add_child(msg):reset();

	user_sessions = user_sessions and user_sessions.sessions;
	for resource, session in pairs(user_sessions) do
		local full_jid = bare_jid .. "/" .. resource;
		if session.want_carbons and ((c2s and session ~= origin) or (not c2s and not no_carbon_to[resource])) then
			fwd.attr.to = full_jid;
			module:log("debug", "Sending carbon to %s", full_jid);
			session.send(fwd);
		end
	end
end

local function c2s_message_handler(event)
	return message_handler(event, true)
end

-- Stanzas sent by local clients
module:hook("pre-message/bare", c2s_message_handler, 1);
module:hook("pre-message/full", c2s_message_handler, 1);
-- Stanzas to local clients
module:hook("message/bare", message_handler, 1);
module:hook("message/full", message_handler, 1);

module:add_feature(xmlns_carbons);