# HG changeset patch # User Seve Ferrer # Date 1601391914 -7200 # Node ID 032e1c79d03912cb1f3c1eed8e90fcc32fbd6d88 # Parent 9626d5d1adc4a6c0d769611e1a275637f8ab408e mod_muc_inject_mentions: Add new configuration setting to look for mentions even if the client sent some already diff -r 9626d5d1adc4 -r 032e1c79d039 mod_muc_inject_mentions/README.markdown --- a/mod_muc_inject_mentions/README.markdown Mon Sep 28 19:06:20 2020 +0200 +++ b/mod_muc_inject_mentions/README.markdown Tue Sep 29 17:05:14 2020 +0200 @@ -52,6 +52,16 @@ If none or both are found, all rooms in the muc component will have mentions enabled. +By default, if a message contains at least one mention, +the module does not do anything, as it believes all mentions were already sent by the client. +In cases where it is desired the module to inspect the message and try to find extra mentions +that could be missing, the following setting can be added: + +``` +muc_inject_mentions_append_mentions = true +``` + + It is also possible to modify how this module detects mentions. In short, the module will detect if a mention is actually a mention if the nickname (with or without affixes) is between spaces, new lines, or at the beginning/end of the message. diff -r 9626d5d1adc4 -r 032e1c79d039 mod_muc_inject_mentions/mod_muc_inject_mentions.lua --- a/mod_muc_inject_mentions/mod_muc_inject_mentions.lua Mon Sep 28 19:06:20 2020 +0200 +++ b/mod_muc_inject_mentions/mod_muc_inject_mentions.lua Tue Sep 29 17:05:14 2020 +0200 @@ -7,10 +7,27 @@ local enabled_rooms = module:get_option("muc_inject_mentions_enabled_rooms", nil) local disabled_rooms = module:get_option("muc_inject_mentions_disabled_rooms", nil) local mention_delimiters = module:get_option_set("muc_inject_mentions_mention_delimiters", {" ", "", "\n"}) +local append_mentions = module:get_option("muc_inject_mentions_append_mentions", true) local reference_xmlns = "urn:xmpp:reference:0" + +local function get_client_mentions(stanza) + local has_mentions = false + local client_mentions = {} + + for element in stanza:childtags("reference", reference_xmlns) do + if element.attr.type == "mention" then + local key = tonumber(element.attr.begin) + 1 -- count starts at 0 + client_mentions[key] = {bare_jid=element.attr.uri, first=element.attr.begin, last=element.attr["end"]} + has_mentions = true + end + end + + return has_mentions, client_mentions +end + local function is_room_eligible(jid) if not enabled_rooms and not disabled_rooms then return true; @@ -79,8 +96,7 @@ return false end -local function search_mentions(room, stanza) - local body = stanza:get_child("body"):get_text(); +local function search_mentions(room, body, client_mentions) local mentions = {} for _, occupant in pairs(room._occupants) do @@ -102,31 +118,33 @@ for _, match in ipairs(matches) do local bare_jid = occupant.bare_jid local first, last = match.first, match.last - - -- Body only contains nickname or is between spaces, new lines or at the end/start of the body - if mention_delimiters:contains(body:sub(first - 1, first - 1)) and - mention_delimiters:contains(body:sub(last + 1, last + 1)) - then - table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) - else - -- Check if occupant is mentioned using affixes - local has_preffix = has_nick_prefix(body, first) - local has_suffix = has_nick_suffix(body, last) + -- Only append new mentions in case the client already sent some + if not client_mentions[first] then + -- Body only contains nickname or is between spaces, new lines or at the end/start of the body + if mention_delimiters:contains(body:sub(first - 1, first - 1)) and + mention_delimiters:contains(body:sub(last + 1, last + 1)) + then + mentions[first] = {bare_jid=bare_jid, first=first, last=last} + else + -- Check if occupant is mentioned using affixes + local has_preffix = has_nick_prefix(body, first) + local has_suffix = has_nick_suffix(body, last) - -- @nickname: ... - if has_preffix and has_suffix then - table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) + -- @nickname: ... + if has_preffix and has_suffix then + mentions[first] = {bare_jid=bare_jid, first=first, last=last} - -- @nickname ... - elseif has_preffix and not has_suffix then - if mention_delimiters:contains(body:sub(last + 1, last + 1)) then - table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) - end + -- @nickname ... + elseif has_preffix and not has_suffix then + if mention_delimiters:contains(body:sub(last + 1, last + 1)) then + mentions[first] = {bare_jid=bare_jid, first=first, last=last} + end - -- nickname: ... - elseif not has_preffix and has_suffix then - if mention_delimiters:contains(body:sub(first - 1, first - 1)) then - table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) + -- nickname: ... + elseif not has_preffix and has_suffix then + if mention_delimiters:contains(body:sub(first - 1, first - 1)) then + mentions[first] = {bare_jid=bare_jid, first=first, last=last} + end end end end @@ -138,14 +156,20 @@ local function muc_inject_mentions(event) local room, stanza = event.room, event.stanza; + local body = stanza:get_child("body") + + if not body then return; end + -- Inject mentions only if the room is configured for them if not is_room_eligible(room.jid) then return; end - -- Only act on messages that do not include references. - -- If references are found, it is assumed the client has mentions support - if stanza:get_child("reference", reference_xmlns) then return; end - local mentions = search_mentions(room, stanza) - for _, mention in ipairs(mentions) do + -- Only act on messages that do not include mentions + -- unless configuration states otherwise. + local has_mentions, client_mentions = get_client_mentions(stanza) + if has_mentions and not append_mentions then return; end + + local mentions = search_mentions(room, body:get_text(), client_mentions) + for _, mention in pairs(mentions) do -- https://xmpp.org/extensions/xep-0372.html#usecase_mention stanza:tag( "reference", {