Merge 0.10->trunk
[prosody.git] / plugins / muc / occupant.lib.lua
index b4b1239055623b0922c433ad5911b44667e81adf..d59252e2824c69f3ea70b2b207a69f2f513462eb 100644 (file)
@@ -2,21 +2,10 @@ local next = next;
 local pairs = pairs;
 local setmetatable = setmetatable;
 local st = require "util.stanza";
+local util = module:require "muc/util";
 
-local get_filtered_presence do
-       local presence_filters = {
-               ["http://jabber.org/protocol/muc"] = true;
-               ["http://jabber.org/protocol/muc#user"] = true;
-       }
-       local function presence_filter(tag)
-               if presence_filters[tag.attr.xmlns] then
-                       return nil;
-               end
-               return tag;
-       end
-       function get_filtered_presence(stanza)
-               return st.clone(stanza):maptags(presence_filter);
-       end
+local function get_filtered_presence(stanza)
+       return util.filter_muc_x(st.clone(stanza));
 end
 
 local occupant_mt = {};
@@ -36,7 +25,8 @@ end
 local function copy_occupant(occupant)
        local sessions = {};
        for full_jid, presence_stanza in pairs(occupant.sessions) do
-               if presence_stanza.attr.type ~= "unavailable" then
+               -- Don't keep unavailable presences, as they'll accumulate; unless they're the primary session
+               if presence_stanza.attr.type ~= "unavailable" or full_jid == occupant.jid then
                        sessions[full_jid] = presence_stanza;
                end
        end
@@ -49,24 +39,35 @@ local function copy_occupant(occupant)
        }, occupant_mt);
 end
 
+-- finds another session to be the primary (there might not be one)
+function occupant_mt:choose_new_primary()
+       for jid, pr in self:each_session() do
+               if pr.attr.type == nil then
+                       return jid;
+               end
+       end
+       return nil;
+end
+
 function occupant_mt:set_session(real_jid, presence_stanza, replace_primary)
        local pr = get_filtered_presence(presence_stanza);
        pr.attr.from = self.nick;
        pr.attr.to = real_jid;
 
        self.sessions[real_jid] = pr;
-       if replace_primary or self.jid == nil then
+       if replace_primary then
                self.jid = real_jid;
+       elseif self.jid == nil or (pr.attr.type == "unavailable" and self.jid == real_jid) then
+               -- Only leave an unavailable presence as primary when there are no other options
+               self.jid = self:choose_new_primary() or real_jid;
        end
 end
 
 function occupant_mt:remove_session(real_jid)
        -- Delete original session
-       local presence_stanza = self.sessions[real_jid];
        self.sessions[real_jid] = nil;
        if self.jid == real_jid then
-               -- find another session to be the primary (might be nil)
-               self.jid = next(self.sessions);
+               self.jid = self:choose_new_primary();
        end
 end