3 local setmetatable = setmetatable;
4 local st = require "util.stanza";
6 local get_filtered_presence do
7 local presence_filters = {
8 ["http://jabber.org/protocol/muc"] = true;
9 ["http://jabber.org/protocol/muc#user"] = true;
11 local function presence_filter(tag)
12 if presence_filters[tag.attr.xmlns] then
17 function get_filtered_presence(stanza)
18 return st.clone(stanza):maptags(presence_filter);
22 local occupant_mt = {};
23 occupant_mt.__index = occupant_mt;
25 local function new_occupant(bare_real_jid, nick)
27 bare_jid = bare_real_jid;
28 nick = nick; -- in-room jid
29 sessions = {}; -- hash from real_jid to presence stanzas. stanzas should not be modified
31 jid = nil; -- Primary session
35 -- Deep copy an occupant
36 local function copy_occupant(occupant)
38 for full_jid, presence_stanza in pairs(occupant.sessions) do
39 -- Don't keep unavailable presences, as they'll accumulate; unless they're the primary session
40 if presence_stanza.attr.type ~= "unavailable" or full_jid == occupant.jid then
41 sessions[full_jid] = presence_stanza;
45 bare_jid = occupant.bare_jid;
53 -- finds another session to be the primary (there might not be one)
54 function occupant_mt:choose_new_primary()
55 for jid, pr in self:each_session() do
56 if pr.attr.type ~= "unavailable" then
63 function occupant_mt:set_session(real_jid, presence_stanza, replace_primary)
64 local pr = get_filtered_presence(presence_stanza);
65 pr.attr.from = self.nick;
66 pr.attr.to = real_jid;
68 self.sessions[real_jid] = pr;
69 if replace_primary then
71 elseif self.jid == nil or (pr.attr.type == "unavailable" and self.jid == real_jid) then
72 -- Only leave an unavailable presence as primary when there are no other options
73 self.jid = self:choose_new_primary() or real_jid;
77 function occupant_mt:remove_session(real_jid)
78 -- Delete original session
79 self.sessions[real_jid] = nil;
80 if self.jid == real_jid then
81 self.jid = self:choose_new_primary();
85 function occupant_mt:each_session()
86 return pairs(self.sessions)
89 function occupant_mt:get_presence(real_jid)
90 return self.sessions[real_jid or self.jid]