Merge 0.10->trunk
[prosody.git] / plugins / muc / occupant.lib.lua
1 local pairs = pairs;
2 local setmetatable = setmetatable;
3 local st = require "util.stanza";
4 local util = module:require "muc/util";
5
6 local function get_filtered_presence(stanza)
7         return util.filter_muc_x(st.clone(stanza));
8 end
9
10 local occupant_mt = {};
11 occupant_mt.__index = occupant_mt;
12
13 local function new_occupant(bare_real_jid, nick)
14         return setmetatable({
15                 bare_jid = bare_real_jid;
16                 nick = nick; -- in-room jid
17                 sessions = {}; -- hash from real_jid to presence stanzas. stanzas should not be modified
18                 role = nil;
19                 jid = nil; -- Primary session
20         }, occupant_mt);
21 end
22
23 -- Deep copy an occupant
24 local function copy_occupant(occupant)
25         local sessions = {};
26         for full_jid, presence_stanza in pairs(occupant.sessions) do
27                 -- Don't keep unavailable presences, as they'll accumulate; unless they're the primary session
28                 if presence_stanza.attr.type ~= "unavailable" or full_jid == occupant.jid then
29                         sessions[full_jid] = presence_stanza;
30                 end
31         end
32         return setmetatable({
33                 bare_jid = occupant.bare_jid;
34                 nick = occupant.nick;
35                 sessions = sessions;
36                 role = occupant.role;
37                 jid = occupant.jid;
38         }, occupant_mt);
39 end
40
41 -- finds another session to be the primary (there might not be one)
42 function occupant_mt:choose_new_primary()
43         for jid, pr in self:each_session() do
44                 if pr.attr.type == nil then
45                         return jid;
46                 end
47         end
48         return nil;
49 end
50
51 function occupant_mt:set_session(real_jid, presence_stanza, replace_primary)
52         local pr = get_filtered_presence(presence_stanza);
53         pr.attr.from = self.nick;
54         pr.attr.to = real_jid;
55
56         self.sessions[real_jid] = pr;
57         if replace_primary then
58                 self.jid = real_jid;
59         elseif self.jid == nil or (pr.attr.type == "unavailable" and self.jid == real_jid) then
60                 -- Only leave an unavailable presence as primary when there are no other options
61                 self.jid = self:choose_new_primary() or real_jid;
62         end
63 end
64
65 function occupant_mt:remove_session(real_jid)
66         -- Delete original session
67         self.sessions[real_jid] = nil;
68         if self.jid == real_jid then
69                 self.jid = self:choose_new_primary();
70         end
71 end
72
73 function occupant_mt:each_session()
74         return pairs(self.sessions)
75 end
76
77 function occupant_mt:get_presence(real_jid)
78         return self.sessions[real_jid or self.jid]
79 end
80
81 return {
82         new = new_occupant;
83         copy = copy_occupant;
84         mt = occupant_mt;
85 }