Files
2022-09-29 07:59:16 +02:00

130 lines
4.1 KiB
Lua

-- mod_muc_notifications
--
-- Copyright (C) 2019 Marcos de Vera Piquero <marcos.devera@quobis.com>
-- enhanced by Stefan Sänger <stefan.saenger@vnc.biz>
-- This file is MIT/X11 licensed.
--
-- A module to notify non-present members of messages in a group chat
--
local id = require"util.id"
local st = require"util.stanza"
local use_invite = module:get_option_boolean("muc_notification_invite", false)
local function dumpTable1(t, depth)
local result = "";
if (not depth) then depth = 0 end;
local prefix = string.rep(" ", depth);
if (type(t) ~= "table") then
result = result.." "..tostring(t);
else
for key,value in pairs(t) do
result = result..prefix..tostring(key).." => "..tostring(value).."\n"
end
end
return result;
end
local function dumpTable(t, depth)
local result = "";
if (not depth) then depth = 0 end;
local prefix = string.rep(" ", depth);
if (type(t) ~= "table") then
result = result.." "..tostring(t);
else
for key,value in pairs(t) do
result = result..prefix..tostring(key).." => "..dumpTable(value, depth+1).."\n"
end
end
return result;
end
-- Given a stanza, compute if it qualifies as important (notifiable)
-- return true for message stanzas with non-empty body
-- Should probably use something similar to muc-message-is-historic event
local function is_important(stanza)
local body = stanza:find("body#")
return body and #body
end
local function handle_muc_message(event)
-- event.room and event.stanza are available
local room = event.room
-- module:log("info","room: %s", dumpTable(room._occupants));
local stanza = event.stanza
local aff_jids = {};
for jid, aff in pairs(room._affiliations) do
if aff ~= "outcast" then
local is_occupant = false
local sessions = prosody.bare_sessions;
local user_online = sessions[jid] or nil;
local jid_resources = {};
if (user_online ~= nil) then
local u_sessions = user_online["sessions"] or nil;
for k,v in pairs(u_sessions) do
jid_resources[jid.."/"..tostring(k)] = true;
end
-- module:log("info", "room user %s sessions: \n %s", jid, dumpTable(jid_resources));
end
for _, occupant in pairs(room._occupants) do
if occupant.bare_jid == jid then
for k,v in pairs(occupant.sessions) do
-- module:log("info", "occupant k %s", k);
jid_resources[k] = nil;
end
-- module:log("info", "remaining resources: ", dumpTable(jid_resources));
-- module:log("info", "remaining resources#: %s", #jid_resources);
if next(jid_resources) == nil then
-- module:log("info", "user %s is occupant with all sessions", jid);
is_occupant = true
break
end
end
end
-- module:log("info", "got jid: %s", jid);
-- local sessions = prosody.bare_sessions;
-- local user_online_sessions = sessions[jid] or nil;
if not is_occupant and is_important(stanza) and (user_online ~= nil) then
-- send notification to jid
local attrs = {
to = jid,
id = id.short(),
from = room.jid,
}
local not_attrs = {
xmlns = "http://vnc.biz/xmpp/muc#hook",
jid = room.jid,
}
local reason = "You have messages in group chat "..(room:get_name() or room.jid)
local notification = st.message(attrs)
:body(reason):up()
:tag("notification", not_attrs):up()
:tag("no-store", {xmlns = "urn:xmpp:hints"})
local invite = st.message(attrs):tag("x", {xmlns = "http://jabber.org/protocol/muc#user"})
:tag("invite", {from = stanza.attr.from})
:tag("reason"):text(reason):up():up():up()
:tag("notification", not_attrs):up()
:tag("no-store", {xmlns = "urn:xmpp:hints"})
module:log("debug", "notifying with %s", tostring(use_invite and invite or notification))
module:send(use_invite and invite or notification)
module:log("debug", "sent notification of MUC message %s", use_invite and invite or notification)
else
module:log("debug", "user %s is not online or already occupant - not sending invite", jid);
end
end
end
end
module:hook("muc-broadcast-message", handle_muc_message)
module:log("debug", "Module loaded")