mod_muc_room_mention_notifications/mod_muc_room_mention_notifications.lua
changeset 4311 af7297e49885
parent 4310 747a14017d00
child 4312 2d42dd45638a
equal deleted inserted replaced
4310:747a14017d00 4311:af7297e49885
     1 local jid = require "util.jid";
       
     2 local st = require "util.stanza";
       
     3 local datetime = require "util.datetime";
       
     4 local jid_resource = require "util.jid".resource;
       
     5 
       
     6 local notify_unaffiliated_users = module:get_option("muc_rmn_notify_unaffiliated_users", false)
       
     7 
       
     8 local muc_affiliation_store = module:open_store("config", "map");
       
     9 
       
    10 local mmn_xmlns = "urn:xmpp:mmn:0";
       
    11 local reference_xmlns = "urn:xmpp:reference:0";
       
    12 local forwarded_xmlns = "urn:xmpp:forward:0";
       
    13 local deplay_xmlns = "urn:xmpp:delay";
       
    14 
       
    15 
       
    16 -- Returns a set of rooms the user is affiliated to
       
    17 local function get_user_rooms(user_bare_jid)
       
    18 	return muc_affiliation_store:get_all(user_bare_jid);
       
    19 end
       
    20 
       
    21 local function is_eligible(user_bare_jid, room)
       
    22 	if notify_unaffiliated_users then return true; end
       
    23 
       
    24 	local user_rooms, err = get_user_rooms(user_bare_jid);
       
    25 	if not user_rooms then
       
    26 		if err then
       
    27 			return false, err;
       
    28 		end
       
    29 		return false;
       
    30 	end
       
    31 
       
    32 	local room_node = jid.node(room.jid)
       
    33 	if user_rooms[room_node] then
       
    34 		return true;
       
    35 	end
       
    36 
       
    37 	return false
       
    38 end
       
    39 
       
    40 -- Send a single notification for a room, updating data structures as needed
       
    41 local function send_single_notification(user_bare_jid, room_jid, mention_stanza)
       
    42 	local notification = st.message({ to = user_bare_jid, from = module.host })
       
    43 		:tag("mentions", { xmlns = mmn_xmlns })
       
    44 		:tag("forwarded", {xmlns = forwarded_xmlns})
       
    45 		:tag("delay", {xmlns = deplay_xmlns, stamp = datetime.datetime()}):up()
       
    46 		:add_child(mention_stanza)
       
    47 		:reset();
       
    48 	module:log("debug", "Sending mention notification from %s to %s", room_jid, user_bare_jid);
       
    49 	return module:send(notification);
       
    50 end
       
    51 
       
    52 local function notify_mentioned_users(room, client_mentions, mention_stanza)
       
    53 	module:log("debug", "NOTIFYING FOR %s", room.jid)
       
    54 	for mentioned_jid in pairs(client_mentions) do
       
    55 		local user_bare_jid = mentioned_jid;
       
    56 		if (string.match(mentioned_jid, room.jid)) then
       
    57 			local nick = jid_resource(mentioned_jid);
       
    58 			user_bare_jid = room:get_registered_jid(nick);
       
    59 		end
       
    60 		if is_eligible(user_bare_jid, room) then
       
    61 			send_single_notification(user_bare_jid, room.jid, mention_stanza);
       
    62 		end
       
    63 	end
       
    64 end
       
    65 
       
    66 local function get_mentions(stanza)
       
    67 	local has_mentions = false
       
    68 	local client_mentions = {}
       
    69 
       
    70 	for element in stanza:childtags("reference", reference_xmlns) do
       
    71 		if element.attr.type == "mention" then
       
    72 			local user_bare_jid = element.attr.uri:match("^xmpp:(.+)$");
       
    73 			if user_bare_jid then
       
    74 				client_mentions[user_bare_jid] = user_bare_jid;
       
    75 				has_mentions = true
       
    76 			end
       
    77 		end
       
    78 	end
       
    79 
       
    80 	return has_mentions, client_mentions
       
    81 end
       
    82 
       
    83 module:hook("muc-broadcast-message", function (event)
       
    84 	local room, stanza = event.room, event.stanza;
       
    85 	local body = stanza:get_child_text("body")
       
    86 	if not body or #body < 1 then return; end
       
    87 	local correction = stanza:get_child("replace", "urn:xmpp:message-correct:0");
       
    88 	if correction then return; end -- Do not notify on message corrections
       
    89 
       
    90 	local has_mentions, client_mentions = get_mentions(stanza)
       
    91 	if not has_mentions then return; end
       
    92 
       
    93 	-- Notify any users that need to be notified
       
    94 	notify_mentioned_users(room, client_mentions, stanza);
       
    95 end, -1);