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