comparison mod_muc_inject_mentions/mod_muc_inject_mentions.lua @ 4163:320f6d374b5d

mod_muc_inject_mentions: Add new configuration setting to strip out prefixes from mentions
author Seve Ferrer <seve@delape.net>
date Wed, 30 Sep 2020 13:14:46 +0200
parents f7bc0e4ab4a2
children a82b0745383b
comparison
equal deleted inserted replaced
4162:f7bc0e4ab4a2 4163:320f6d374b5d
1 module:depends("muc"); 1 module:depends("muc");
2 2
3 local jid_resource = require "util.jid".resource; 3 local jid_resource = require "util.jid".resource;
4 local st = require "util.stanza";
4 5
5 local prefixes = module:get_option("muc_inject_mentions_prefixes", nil) 6 local prefixes = module:get_option("muc_inject_mentions_prefixes", nil)
6 local suffixes = module:get_option("muc_inject_mentions_suffixes", nil) 7 local suffixes = module:get_option("muc_inject_mentions_suffixes", nil)
7 local enabled_rooms = module:get_option("muc_inject_mentions_enabled_rooms", nil) 8 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) 9 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"}) 10 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", false) 11 local append_mentions = module:get_option("muc_inject_mentions_append_mentions", false)
12 local strip_out_prefixes = module:get_option("muc_inject_mentions_strip_out_prefixes", false)
11 13
12 14
13 local reference_xmlns = "urn:xmpp:reference:0" 15 local reference_xmlns = "urn:xmpp:reference:0"
14 16
17 local function add_mention(mentions, bare_jid, first, last, prefix_indices, has_prefix)
18 if strip_out_prefixes then
19 if has_prefix then
20 table.insert(prefix_indices, first-1)
21 end
22 first = first - #prefix_indices
23 last = last - #prefix_indices
24 end
25 mentions[first] = {bare_jid=bare_jid, first=first, last=last}
26 end
15 27
16 local function get_client_mentions(stanza) 28 local function get_client_mentions(stanza)
17 local has_mentions = false 29 local has_mentions = false
18 local client_mentions = {} 30 local client_mentions = {}
19 31
56 68
57 local function has_nick_prefix(body, first) 69 local function has_nick_prefix(body, first)
58 -- There are no configured prefixes 70 -- There are no configured prefixes
59 if not prefixes or #prefixes < 1 then return false end 71 if not prefixes or #prefixes < 1 then return false end
60 72
61 -- Preffix must have a space before it, 73 -- Prefix must have a space before it,
62 -- be the first character of the body 74 -- be the first character of the body
63 -- or be the first character after a new line 75 -- or be the first character after a new line
64 if not mention_delimiters:contains(body:sub(first - 2, first - 2)) then 76 if not mention_delimiters:contains(body:sub(first - 2, first - 2)) then
65 return false 77 return false
66 end 78 end
67 79
68 local preffix = body:sub(first - 1, first - 1) 80 local prefix = body:sub(first - 1, first - 1)
69 for _, _preffix in ipairs(prefixes) do 81 for _, _prefix in ipairs(prefixes) do
70 if preffix == _preffix then 82 if prefix == _prefix then
71 return true 83 return true
72 end 84 end
73 end 85 end
74 86
75 return false 87 return false
95 107
96 return false 108 return false
97 end 109 end
98 110
99 local function search_mentions(room, body, client_mentions) 111 local function search_mentions(room, body, client_mentions)
100 local mentions = {} 112 local mentions, prefix_indices = {}, {}
101 113
102 for _, occupant in pairs(room._occupants) do 114 for _, occupant in pairs(room._occupants) do
103 local nick = jid_resource(occupant.nick); 115 local nick = jid_resource(occupant.nick);
104 -- Check for multiple mentions to the same nickname in a message 116 -- Check for multiple mentions to the same nickname in a message
105 -- Hey @nick remember to... Ah, also @nick please let me know if... 117 -- Hey @nick remember to... Ah, also @nick please let me know if...
122 if not client_mentions[first] then 134 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 135 -- 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 136 if mention_delimiters:contains(body:sub(first - 1, first - 1)) and
125 mention_delimiters:contains(body:sub(last + 1, last + 1)) 137 mention_delimiters:contains(body:sub(last + 1, last + 1))
126 then 138 then
127 mentions[first] = {bare_jid=bare_jid, first=first, last=last} 139 add_mention(mentions, bare_jid, first, last, prefix_indices, false)
128 else 140 else
129 -- Check if occupant is mentioned using affixes 141 -- Check if occupant is mentioned using affixes
130 local has_preffix = has_nick_prefix(body, first) 142 local has_prefix = has_nick_prefix(body, first)
131 local has_suffix = has_nick_suffix(body, last) 143 local has_suffix = has_nick_suffix(body, last)
132 144
133 -- @nickname: ... 145 -- @nickname: ...
134 if has_preffix and has_suffix then 146 if has_prefix and has_suffix then
135 mentions[first] = {bare_jid=bare_jid, first=first, last=last} 147 add_mention(mentions, bare_jid, first, last, prefix_indices, has_prefix)
136 148
137 -- @nickname ... 149 -- @nickname ...
138 elseif has_preffix and not has_suffix then 150 elseif has_prefix and not has_suffix then
139 if mention_delimiters:contains(body:sub(last + 1, last + 1)) then 151 if mention_delimiters:contains(body:sub(last + 1, last + 1)) then
140 mentions[first] = {bare_jid=bare_jid, first=first, last=last} 152 add_mention(mentions, bare_jid, first, last, prefix_indices, has_prefix)
141 end 153 end
142 154
143 -- nickname: ... 155 -- nickname: ...
144 elseif not has_preffix and has_suffix then 156 elseif not has_prefix and has_suffix then
145 if mention_delimiters:contains(body:sub(first - 1, first - 1)) then 157 if mention_delimiters:contains(body:sub(first - 1, first - 1)) then
146 mentions[first] = {bare_jid=bare_jid, first=first, last=last} 158 add_mention(mentions, bare_jid, first, last, prefix_indices, has_prefix)
147 end 159 end
148 end 160 end
149 end 161 end
150 end 162 end
151 end 163 end
152 end 164 end
153 165
154 return mentions 166 return mentions, prefix_indices
155 end 167 end
156 168
157 local function muc_inject_mentions(event) 169 local function muc_inject_mentions(event)
158 local room, stanza = event.room, event.stanza; 170 local room, stanza = event.room, event.stanza;
159 local body = stanza:get_child("body") 171 local body = stanza:get_child("body")
166 -- Only act on messages that do not include mentions 178 -- Only act on messages that do not include mentions
167 -- unless configuration states otherwise. 179 -- unless configuration states otherwise.
168 local has_mentions, client_mentions = get_client_mentions(stanza) 180 local has_mentions, client_mentions = get_client_mentions(stanza)
169 if has_mentions and not append_mentions then return; end 181 if has_mentions and not append_mentions then return; end
170 182
171 local mentions = search_mentions(room, body:get_text(), client_mentions) 183 local body_text = body:get_text()
184 local mentions, prefix_indices = search_mentions(room, body_text, client_mentions)
172 for _, mention in pairs(mentions) do 185 for _, mention in pairs(mentions) do
173 -- https://xmpp.org/extensions/xep-0372.html#usecase_mention 186 -- https://xmpp.org/extensions/xep-0372.html#usecase_mention
174 stanza:tag( 187 stanza:tag(
175 "reference", { 188 "reference", {
176 xmlns=reference_xmlns, 189 xmlns=reference_xmlns,
179 type="mention", 192 type="mention",
180 uri="xmpp:" .. mention.bare_jid, 193 uri="xmpp:" .. mention.bare_jid,
181 } 194 }
182 ):up() 195 ):up()
183 end 196 end
197
198 if strip_out_prefixes then
199 local body_without_prefixes = ""
200 local from = 0
201 if #prefix_indices > 0 then
202 for _, prefix_index in ipairs(prefix_indices) do
203 body_without_prefixes = body_without_prefixes .. body_text:sub(from, prefix_index-1)
204 from = prefix_index + 1
205 end
206 body_without_prefixes = body_without_prefixes .. body_text:sub(from, #body_text)
207
208 -- Replace original body containing prefixes
209 stanza:maptags(
210 function(tag)
211 if tag.name ~= "body" then
212 return tag
213 end
214 return st.stanza("body"):text(body_without_prefixes)
215 end
216 )
217 end
218 end
184 end 219 end
185 220
186 module:hook("muc-occupant-groupchat", muc_inject_mentions) 221 module:hook("muc-occupant-groupchat", muc_inject_mentions)