comparison mod_muc_inject_mentions/mod_muc_inject_mentions.lua @ 4161:032e1c79d039

mod_muc_inject_mentions: Add new configuration setting to look for mentions even if the client sent some already
author Seve Ferrer <seve@delape.net>
date Tue, 29 Sep 2020 17:05:14 +0200
parents 94e3e7753220
children f7bc0e4ab4a2
comparison
equal deleted inserted replaced
4160:9626d5d1adc4 4161:032e1c79d039
5 local prefixes = module:get_option("muc_inject_mentions_prefixes", nil) 5 local prefixes = module:get_option("muc_inject_mentions_prefixes", nil)
6 local suffixes = module:get_option("muc_inject_mentions_suffixes", nil) 6 local suffixes = module:get_option("muc_inject_mentions_suffixes", nil)
7 local enabled_rooms = module:get_option("muc_inject_mentions_enabled_rooms", nil) 7 local enabled_rooms = module:get_option("muc_inject_mentions_enabled_rooms", nil)
8 local disabled_rooms = module:get_option("muc_inject_mentions_disabled_rooms", nil) 8 local disabled_rooms = module:get_option("muc_inject_mentions_disabled_rooms", nil)
9 local mention_delimiters = module:get_option_set("muc_inject_mentions_mention_delimiters", {" ", "", "\n"}) 9 local mention_delimiters = module:get_option_set("muc_inject_mentions_mention_delimiters", {" ", "", "\n"})
10 local append_mentions = module:get_option("muc_inject_mentions_append_mentions", true)
10 11
11 12
12 local reference_xmlns = "urn:xmpp:reference:0" 13 local reference_xmlns = "urn:xmpp:reference:0"
14
15
16 local function get_client_mentions(stanza)
17 local has_mentions = false
18 local client_mentions = {}
19
20 for element in stanza:childtags("reference", reference_xmlns) do
21 if element.attr.type == "mention" then
22 local key = tonumber(element.attr.begin) + 1 -- count starts at 0
23 client_mentions[key] = {bare_jid=element.attr.uri, first=element.attr.begin, last=element.attr["end"]}
24 has_mentions = true
25 end
26 end
27
28 return has_mentions, client_mentions
29 end
13 30
14 local function is_room_eligible(jid) 31 local function is_room_eligible(jid)
15 if not enabled_rooms and not disabled_rooms then 32 if not enabled_rooms and not disabled_rooms then
16 return true; 33 return true;
17 end 34 end
77 end 94 end
78 95
79 return false 96 return false
80 end 97 end
81 98
82 local function search_mentions(room, stanza) 99 local function search_mentions(room, body, client_mentions)
83 local body = stanza:get_child("body"):get_text();
84 local mentions = {} 100 local mentions = {}
85 101
86 for _, occupant in pairs(room._occupants) do 102 for _, occupant in pairs(room._occupants) do
87 local nick = jid_resource(occupant.nick); 103 local nick = jid_resource(occupant.nick);
88 -- Check for multiple mentions to the same nickname in a message 104 -- Check for multiple mentions to the same nickname in a message
100 116
101 -- Filter out intentional mentions from unintentional ones 117 -- Filter out intentional mentions from unintentional ones
102 for _, match in ipairs(matches) do 118 for _, match in ipairs(matches) do
103 local bare_jid = occupant.bare_jid 119 local bare_jid = occupant.bare_jid
104 local first, last = match.first, match.last 120 local first, last = match.first, match.last
121 -- Only append new mentions in case the client already sent some
122 if not client_mentions[first] then
123 -- Body only contains nickname or is between spaces, new lines or at the end/start of the body
124 if mention_delimiters:contains(body:sub(first - 1, first - 1)) and
125 mention_delimiters:contains(body:sub(last + 1, last + 1))
126 then
127 mentions[first] = {bare_jid=bare_jid, first=first, last=last}
128 else
129 -- Check if occupant is mentioned using affixes
130 local has_preffix = has_nick_prefix(body, first)
131 local has_suffix = has_nick_suffix(body, last)
105 132
106 -- Body only contains nickname or is between spaces, new lines or at the end/start of the body 133 -- @nickname: ...
107 if mention_delimiters:contains(body:sub(first - 1, first - 1)) and 134 if has_preffix and has_suffix then
108 mention_delimiters:contains(body:sub(last + 1, last + 1)) 135 mentions[first] = {bare_jid=bare_jid, first=first, last=last}
109 then
110 table.insert(mentions, {bare_jid=bare_jid, first=first, last=last})
111 else
112 -- Check if occupant is mentioned using affixes
113 local has_preffix = has_nick_prefix(body, first)
114 local has_suffix = has_nick_suffix(body, last)
115 136
116 -- @nickname: ... 137 -- @nickname ...
117 if has_preffix and has_suffix then 138 elseif has_preffix and not has_suffix then
118 table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) 139 if mention_delimiters:contains(body:sub(last + 1, last + 1)) then
140 mentions[first] = {bare_jid=bare_jid, first=first, last=last}
141 end
119 142
120 -- @nickname ... 143 -- nickname: ...
121 elseif has_preffix and not has_suffix then 144 elseif not has_preffix and has_suffix then
122 if mention_delimiters:contains(body:sub(last + 1, last + 1)) then 145 if mention_delimiters:contains(body:sub(first - 1, first - 1)) then
123 table.insert(mentions, {bare_jid=bare_jid, first=first, last=last}) 146 mentions[first] = {bare_jid=bare_jid, first=first, last=last}
124 end 147 end
125
126 -- nickname: ...
127 elseif not has_preffix and has_suffix then
128 if mention_delimiters:contains(body:sub(first - 1, first - 1)) then
129 table.insert(mentions, {bare_jid=bare_jid, first=first, last=last})
130 end 148 end
131 end 149 end
132 end 150 end
133 end 151 end
134 end 152 end
136 return mentions 154 return mentions
137 end 155 end
138 156
139 local function muc_inject_mentions(event) 157 local function muc_inject_mentions(event)
140 local room, stanza = event.room, event.stanza; 158 local room, stanza = event.room, event.stanza;
159 local body = stanza:get_child("body")
160
161 if not body then return; end
162
141 -- Inject mentions only if the room is configured for them 163 -- Inject mentions only if the room is configured for them
142 if not is_room_eligible(room.jid) then return; end 164 if not is_room_eligible(room.jid) then return; end
143 -- Only act on messages that do not include references.
144 -- If references are found, it is assumed the client has mentions support
145 if stanza:get_child("reference", reference_xmlns) then return; end
146 165
147 local mentions = search_mentions(room, stanza) 166 -- Only act on messages that do not include mentions
148 for _, mention in ipairs(mentions) do 167 -- unless configuration states otherwise.
168 local has_mentions, client_mentions = get_client_mentions(stanza)
169 if has_mentions and not append_mentions then return; end
170
171 local mentions = search_mentions(room, body:get_text(), client_mentions)
172 for _, mention in pairs(mentions) do
149 -- https://xmpp.org/extensions/xep-0372.html#usecase_mention 173 -- https://xmpp.org/extensions/xep-0372.html#usecase_mention
150 stanza:tag( 174 stanza:tag(
151 "reference", { 175 "reference", {
152 xmlns=reference_xmlns, 176 xmlns=reference_xmlns,
153 begin=tostring(mention.first - 1), -- count starts at 0 177 begin=tostring(mention.first - 1), -- count starts at 0