Software /
code /
prosody-modules
Comparison
mod_mam/mod_mam.lua @ 2516:248054199d0f
mod_mam: Add support for XEP-0313 v0.6
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Mon, 20 Feb 2017 01:59:33 +0100 |
parent | 2515:4cb549622862 |
child | 2644:0f44d04d0d18 |
comparison
equal
deleted
inserted
replaced
2515:4cb549622862 | 2516:248054199d0f |
---|---|
3 -- | 3 -- |
4 -- This file is MIT/X11 licensed. | 4 -- This file is MIT/X11 licensed. |
5 | 5 |
6 local xmlns_mam0 = "urn:xmpp:mam:0"; | 6 local xmlns_mam0 = "urn:xmpp:mam:0"; |
7 local xmlns_mam1 = "urn:xmpp:mam:1"; | 7 local xmlns_mam1 = "urn:xmpp:mam:1"; |
8 local xmlns_mam2 = "urn:xmpp:mam:2"; | |
8 local xmlns_delay = "urn:xmpp:delay"; | 9 local xmlns_delay = "urn:xmpp:delay"; |
9 local xmlns_forward = "urn:xmpp:forward:0"; | 10 local xmlns_forward = "urn:xmpp:forward:0"; |
11 local xmlns_st_id = "urn:xmpp:sid:0"; | |
10 | 12 |
11 local um = require "core.usermanager"; | 13 local um = require "core.usermanager"; |
12 local st = require "util.stanza"; | 14 local st = require "util.stanza"; |
13 local rsm = module:require "rsm"; | 15 local rsm = module:require "rsm"; |
14 local get_prefs = module:require"mamprefs".get; | 16 local get_prefs = module:require"mamprefs".get; |
15 local set_prefs = module:require"mamprefs".set; | 17 local set_prefs = module:require"mamprefs".set; |
16 local prefs_to_stanza = module:require"mamprefsxml".tostanza; | 18 local prefs_to_stanza = module:require"mamprefsxml".tostanza; |
17 local prefs_from_stanza = module:require"mamprefsxml".fromstanza; | 19 local prefs_from_stanza = module:require"mamprefsxml".fromstanza; |
18 local jid_bare = require "util.jid".bare; | 20 local jid_bare = require "util.jid".bare; |
19 local jid_split = require "util.jid".split; | 21 local jid_split = require "util.jid".split; |
22 local jid_prepped_split = require "util.jid".prepped_split; | |
20 local dataform = require "util.dataforms".new; | 23 local dataform = require "util.dataforms".new; |
21 local host = module.host; | 24 local host = module.host; |
22 | 25 |
23 local rm_load_roster = require "core.rostermanager".load_roster; | 26 local rm_load_roster = require "core.rostermanager".load_roster; |
24 | 27 |
76 return true; | 79 return true; |
77 end | 80 end |
78 | 81 |
79 module:hook("iq/self/"..xmlns_mam0..":prefs", handle_prefs); | 82 module:hook("iq/self/"..xmlns_mam0..":prefs", handle_prefs); |
80 module:hook("iq/self/"..xmlns_mam1..":prefs", handle_prefs); | 83 module:hook("iq/self/"..xmlns_mam1..":prefs", handle_prefs); |
84 module:hook("iq/self/"..xmlns_mam2..":prefs", handle_prefs); | |
81 | 85 |
82 local query_form = dataform { | 86 local query_form = dataform { |
83 { name = "FORM_TYPE"; type = "hidden"; value = xmlns_mam0; }; | 87 { name = "FORM_TYPE"; type = "hidden"; value = xmlns_mam0; }; |
84 { name = "with"; type = "jid-single"; }; | 88 { name = "with"; type = "jid-single"; }; |
85 { name = "start"; type = "text-single" }; | 89 { name = "start"; type = "text-single" }; |
95 return true; | 99 return true; |
96 end | 100 end |
97 | 101 |
98 module:hook("iq-get/self/"..xmlns_mam0..":query", handle_get_form); | 102 module:hook("iq-get/self/"..xmlns_mam0..":query", handle_get_form); |
99 module:hook("iq-get/self/"..xmlns_mam1..":query", handle_get_form); | 103 module:hook("iq-get/self/"..xmlns_mam1..":query", handle_get_form); |
104 module:hook("iq-get/self/"..xmlns_mam2..":query", handle_get_form); | |
100 | 105 |
101 -- Handle archive queries | 106 -- Handle archive queries |
102 local function handle_mam_query(event) | 107 local function handle_mam_query(event) |
103 local origin, stanza = event.origin, event.stanza; | 108 local origin, stanza = event.origin, event.stanza; |
104 local xmlns_mam = stanza.tags[1].attr.xmlns; | 109 local xmlns_mam = stanza.tags[1].attr.xmlns; |
219 origin.send(fin); | 224 origin.send(fin); |
220 return true; | 225 return true; |
221 end | 226 end |
222 module:hook("iq-set/self/"..xmlns_mam0..":query", handle_mam_query); | 227 module:hook("iq-set/self/"..xmlns_mam0..":query", handle_mam_query); |
223 module:hook("iq-set/self/"..xmlns_mam1..":query", handle_mam_query); | 228 module:hook("iq-set/self/"..xmlns_mam1..":query", handle_mam_query); |
229 module:hook("iq-set/self/"..xmlns_mam2..":query", handle_mam_query); | |
224 | 230 |
225 local function has_in_roster(user, who) | 231 local function has_in_roster(user, who) |
226 local roster = rm_load_roster(user, host); | 232 local roster = rm_load_roster(user, host); |
227 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); | 233 module:log("debug", "%s has %s in roster? %s", user, who, roster[who] and "yes" or "no"); |
228 return roster[who]; | 234 return roster[who]; |
259 local orig_type = stanza.attr.type or "normal"; | 265 local orig_type = stanza.attr.type or "normal"; |
260 local orig_from = stanza.attr.from; | 266 local orig_from = stanza.attr.from; |
261 local orig_to = stanza.attr.to or orig_from; | 267 local orig_to = stanza.attr.to or orig_from; |
262 -- Stanza without 'to' are treated as if it was to their own bare jid | 268 -- Stanza without 'to' are treated as if it was to their own bare jid |
263 | 269 |
270 -- Whos storage do we put it in? | |
271 local store_user = c2s and origin.username or jid_split(orig_to); | |
272 -- And who are they chatting with? | |
273 local with = jid_bare(c2s and orig_to or orig_from); | |
274 | |
275 -- Filter out <stanza-id> that claim to be from us | |
276 stanza:maptags(function (tag) | |
277 if tag.name == "stanza-id" and tag.attr.xmlns == xmlns_st_id then | |
278 local by_user, by_host, res = jid_prepped_split(tag.attr.by); | |
279 if not res and by_host == module.host and by_user == store_user then | |
280 return nil; | |
281 end | |
282 end | |
283 return tag; | |
284 end); | |
285 | |
264 -- We store chat messages or normal messages that have a body | 286 -- We store chat messages or normal messages that have a body |
265 if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body")) ) then | 287 if not(orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body")) ) then |
266 log("debug", "Not archiving stanza: %s (type)", stanza:top_tag()); | 288 log("debug", "Not archiving stanza: %s (type)", stanza:top_tag()); |
267 return; | 289 return; |
268 end | 290 end |
274 log("debug", "Not archiving stanza: %s (hint)", stanza:top_tag()); | 296 log("debug", "Not archiving stanza: %s (hint)", stanza:top_tag()); |
275 return; | 297 return; |
276 end | 298 end |
277 end | 299 end |
278 | 300 |
279 -- Whos storage do we put it in? | |
280 local store_user = c2s and origin.username or jid_split(orig_to); | |
281 -- And who are they chatting with? | |
282 local with = jid_bare(c2s and orig_to or orig_from); | |
283 | |
284 -- Check with the users preferences | 301 -- Check with the users preferences |
285 if shall_store(store_user, with) then | 302 if shall_store(store_user, with) then |
286 log("debug", "Archiving stanza: %s", stanza:top_tag()); | 303 log("debug", "Archiving stanza: %s", stanza:top_tag()); |
287 | 304 |
288 -- And stash it | 305 -- And stash it |
289 local ok = archive:append(store_user, nil, stanza, time_now(), with); | 306 local ok = archive:append(store_user, nil, stanza, time_now(), with); |
290 if ok then | 307 if ok then |
291 local id = ok; | 308 local id = ok; |
309 stanza:tag("stanza-id", { xmlns = xmlns_st_id, by = store_user.."@"..host, id = id }):up(); | |
292 if cleanup then cleanup[store_user] = true; end | 310 if cleanup then cleanup[store_user] = true; end |
293 module:fire_event("archive-message-added", { origin = origin, stanza = stanza, for_user = store_user, id = id }); | 311 module:fire_event("archive-message-added", { origin = origin, stanza = stanza, for_user = store_user, id = id }); |
294 end | 312 end |
295 else | 313 else |
296 log("debug", "Not archiving stanza: %s (prefs)", stanza:top_tag()); | 314 log("debug", "Not archiving stanza: %s (prefs)", stanza:top_tag()); |
298 end | 316 end |
299 | 317 |
300 local function c2s_message_handler(event) | 318 local function c2s_message_handler(event) |
301 return message_handler(event, true); | 319 return message_handler(event, true); |
302 end | 320 end |
321 | |
322 local function strip_stanza_id(event) | |
323 local strip_by = jid_bare(event.origin.full_jid); | |
324 event.stanza:maptags(function(tag) | |
325 if not ( tag.attr.xmlns == xmlns_st_id and tag.attr.by == strip_by ) then | |
326 return tag; | |
327 end | |
328 end); | |
329 end | |
330 | |
331 module:hook("pre-message/bare", strip_stanza_id, 0.01); | |
332 module:hook("pre-message/full", strip_stanza_id, 0.01); | |
303 | 333 |
304 local cleanup_after = module:get_option_string("archive_expires_after", "1w"); | 334 local cleanup_after = module:get_option_string("archive_expires_after", "1w"); |
305 local cleanup_interval = module:get_option_number("archive_cleanup_interval", 4 * 60 * 60); | 335 local cleanup_interval = module:get_option_number("archive_cleanup_interval", 4 * 60 * 60); |
306 if cleanup_after ~= "never" then | 336 if cleanup_after ~= "never" then |
307 local day = 86400; | 337 local day = 86400; |
364 module:add_feature(xmlns_mam0); -- COMPAT with XEP-0313 v 0.1 | 394 module:add_feature(xmlns_mam0); -- COMPAT with XEP-0313 v 0.1 |
365 | 395 |
366 module:hook("account-disco-info", function(event) | 396 module:hook("account-disco-info", function(event) |
367 (event.reply or event.stanza):tag("feature", {var=xmlns_mam0}):up(); | 397 (event.reply or event.stanza):tag("feature", {var=xmlns_mam0}):up(); |
368 (event.reply or event.stanza):tag("feature", {var=xmlns_mam1}):up(); | 398 (event.reply or event.stanza):tag("feature", {var=xmlns_mam1}):up(); |
399 (event.reply or event.stanza):tag("feature", {var=xmlns_mam2}):up(); | |
400 (event.reply or event.stanza):tag("feature", {var=xmlns_st_id}):up(); | |
369 end); | 401 end); |
370 | 402 |