File

plugins/mod_message.lua @ 10813:4a9ff4f61796

mod_presence: Send unavailable presence in current thread run `session:dispatch_stanza(pres)` enqueues processing of the stanza in the sessions async thread, but becasue the entire stream close handling is now in that thread it would process the presence after the stream and session was completely closed, leading to weird errors "sent to a resting session". We call core_process_stanza() since this is what :dispatch_stanza calls in the end.
author Kim Alvefur <zash@zash.se>
date Sat, 09 May 2020 00:28:10 +0200
parent 8728:41c959c5c84b
child 11482:671f6b867e0d
line wrap: on
line source

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--


local full_sessions = prosody.full_sessions;
local bare_sessions = prosody.bare_sessions;

local st = require "util.stanza";
local jid_bare = require "util.jid".bare;
local jid_split = require "util.jid".split;
local user_exists = require "core.usermanager".user_exists;

local function process_to_bare(bare, origin, stanza)
	local user = bare_sessions[bare];

	local t = stanza.attr.type;
	if t == "error" then
		return true; -- discard
	elseif t == "groupchat" then
		origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
	elseif t == "headline" then
		if user and stanza.attr.to == bare then
			for _, session in pairs(user.sessions) do
				if session.presence and session.priority >= 0 then
					session.send(stanza);
				end
			end
		end  -- current policy is to discard headlines if no recipient is available
	else -- chat or normal message
		if user then -- some resources are connected
			local recipients = user.top_resources;
			if recipients then
				local sent;
				for i=1,#recipients do
					sent = recipients[i].send(stanza) or sent;
				end
				if sent then
					return true;
				end
			end
		end
		-- no resources are online
		local node, host = jid_split(bare);
		local ok
		if user_exists(node, host) then
			ok = module:fire_event('message/offline/handle', {
				username = node;
				origin = origin,
				stanza = stanza,
			});
		end

		if not ok then
			origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
		end
	end
	return true;
end

module:hook("message/full", function(data)
	-- message to full JID received
	local origin, stanza = data.origin, data.stanza;

	local session = full_sessions[stanza.attr.to];
	if session and session.send(stanza) then
		return true;
	else -- resource not online
		return process_to_bare(jid_bare(stanza.attr.to), origin, stanza);
	end
end, -1);

module:hook("message/bare", function(data)
	-- message to bare JID received
	local origin, stanza = data.origin, data.stanza;

	return process_to_bare(stanza.attr.to or (origin.username..'@'..origin.host), origin, stanza);
end, -1);

module:add_feature("msgoffline");