Mercurial > prosody-modules
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 |