comparison plugins/mod_presence.lua @ 1487:66f18c18befa

Merge with main branch.
author Tobias Markmann <tm@ayena.de>
date Sun, 05 Jul 2009 19:05:25 +0200
parents 93d3295fb064
children 0d1aff918303
comparison
equal deleted inserted replaced
1486:3e04efa8af7e 1487:66f18c18befa
8 8
9 local log = module._log; 9 local log = module._log;
10 10
11 local require = require; 11 local require = require;
12 local pairs, ipairs = pairs, ipairs; 12 local pairs, ipairs = pairs, ipairs;
13 local t_concat = table.concat; 13 local t_concat, t_insert = table.concat, table.insert;
14 local s_find = string.find; 14 local s_find = string.find;
15 local tonumber = tonumber; 15 local tonumber = tonumber;
16 16
17 local st = require "util.stanza"; 17 local st = require "util.stanza";
18 local jid_split = require "util.jid".split; 18 local jid_split = require "util.jid".split;
33 handle_inbound_presence_subscriptions_and_probes(origin, stanza, jid_bare(stanza.attr.from), jid_bare(stanza.attr.to), core_route_stanza); 33 handle_inbound_presence_subscriptions_and_probes(origin, stanza, jid_bare(stanza.attr.from), jid_bare(stanza.attr.to), core_route_stanza);
34 return; 34 return;
35 end 35 end
36 end 36 end
37 _core_route_stanza(origin, stanza); 37 _core_route_stanza(origin, stanza);
38 end
39
40 function handle_presence(origin, stanza, from_bare, to_bare, core_route_stanza, inbound)
41 local type = stanza.attr.type;
42 if type and type ~= "unavailable" and type ~= "error" then
43 if inbound then
44 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
45 else
46 handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
47 end
48 elseif not inbound and not stanza.attr.to then
49 handle_normal_presence(origin, stanza, core_route_stanza);
50 else
51 core_route_stanza(origin, stanza);
52 end
53 end 38 end
54 39
55 local function select_top_resources(user) 40 local function select_top_resources(user)
56 local priority = 0; 41 local priority = 0;
57 local recipients = {}; 42 local recipients = {};
74 user.top_resources = select_top_resources(user); 59 user.top_resources = select_top_resources(user);
75 if #user.top_resources == 0 then user.top_resources = nil; end 60 if #user.top_resources == 0 then user.top_resources = nil; end
76 end 61 end
77 62
78 function handle_normal_presence(origin, stanza, core_route_stanza) 63 function handle_normal_presence(origin, stanza, core_route_stanza)
79 if origin.roster then 64 local roster = origin.roster;
80 for jid in pairs(origin.roster) do -- broadcast to all interested contacts 65 local node, host = origin.username, origin.host;
81 local subscription = origin.roster[jid].subscription; 66 for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
82 if subscription == "both" or subscription == "from" then 67 if res ~= origin and res.presence then -- to resource
68 stanza.attr.to = res.full_jid;
69 core_route_stanza(origin, stanza);
70 end
71 end
72 for jid, item in pairs(roster) do -- broadcast to all interested contacts
73 if item.subscription == "both" or item.subscription == "from" then
74 stanza.attr.to = jid;
75 core_route_stanza(origin, stanza);
76 end
77 end
78 if stanza.attr.type == nil and not origin.presence then -- initial presence
79 local probe = st.presence({from = origin.full_jid, type = "probe"});
80 for jid, item in pairs(roster) do -- probe all contacts we are subscribed to
81 if item.subscription == "both" or item.subscription == "to" then
82 probe.attr.to = jid;
83 core_route_stanza(origin, probe);
84 end
85 end
86 for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
87 if res ~= origin and res.presence then
88 res.presence.attr.to = origin.full_jid;
89 core_route_stanza(res, res.presence);
90 res.presence.attr.to = nil;
91 end
92 end
93 if roster.pending then -- resend incoming subscription requests
94 for jid in pairs(roster.pending) do
95 origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original?
96 end
97 end
98 local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host});
99 for jid, item in pairs(roster) do -- resend outgoing subscription requests
100 if item.ask then
101 request.attr.to = jid;
102 core_route_stanza(origin, request);
103 end
104 end
105 local offline = offlinemanager.load(node, host);
106 if offline then
107 for _, msg in ipairs(offline) do
108 origin.send(msg); -- FIXME do we need to modify to/from in any way?
109 end
110 offlinemanager.deleteAll(node, host);
111 end
112 end
113 if stanza.attr.type == "unavailable" then
114 origin.presence = nil;
115 if origin.priority then
116 origin.priority = nil;
117 recalc_resource_map(origin);
118 end
119 if origin.directed then
120 for jid in pairs(origin.directed) do
83 stanza.attr.to = jid; 121 stanza.attr.to = jid;
84 core_route_stanza(origin, stanza); 122 core_route_stanza(origin, stanza);
85 end 123 end
86 end 124 origin.directed = nil;
87 local node, host = jid_split(stanza.attr.from); 125 end
88 for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources 126 else
89 if res ~= origin and res.presence then -- to resource 127 origin.presence = stanza;
90 stanza.attr.to = res.full_jid; 128 local priority = stanza:child_with_name("priority");
91 core_route_stanza(origin, stanza); 129 if priority and #priority > 0 then
92 end 130 priority = t_concat(priority);
93 end 131 if s_find(priority, "^[+-]?[0-9]+$") then
94 if stanza.attr.type == nil and not origin.presence then -- initial presence 132 priority = tonumber(priority);
95 local probe = st.presence({from = origin.full_jid, type = "probe"}); 133 if priority < -128 then priority = -128 end
96 for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to 134 if priority > 127 then priority = 127 end
97 local subscription = origin.roster[jid].subscription;
98 if subscription == "both" or subscription == "to" then
99 probe.attr.to = jid;
100 core_route_stanza(origin, probe);
101 end
102 end
103 for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
104 if res ~= origin and res.presence then
105 res.presence.attr.to = origin.full_jid;
106 core_route_stanza(res, res.presence);
107 res.presence.attr.to = nil;
108 end
109 end
110 if origin.roster.pending then -- resend incoming subscription requests
111 for jid in pairs(origin.roster.pending) do
112 origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original?
113 end
114 end
115 local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host});
116 for jid, item in pairs(origin.roster) do -- resend outgoing subscription requests
117 if item.ask then
118 request.attr.to = jid;
119 core_route_stanza(origin, request);
120 end
121 end
122 local offline = offlinemanager.load(node, host);
123 if offline then
124 for _, msg in ipairs(offline) do
125 origin.send(msg); -- FIXME do we need to modify to/from in any way?
126 end
127 offlinemanager.deleteAll(node, host);
128 end
129 end
130 if stanza.attr.type == "unavailable" then
131 origin.presence = nil;
132 if origin.priority then
133 origin.priority = nil;
134 recalc_resource_map(origin);
135 end
136 if origin.directed then
137 local old_from = stanza.attr.from;
138 stanza.attr.from = origin.full_jid;
139 for jid in pairs(origin.directed) do
140 stanza.attr.to = jid;
141 core_route_stanza(origin, stanza);
142 end
143 stanza.attr.from = old_from;
144 origin.directed = nil;
145 end
146 else
147 origin.presence = stanza;
148 local priority = stanza:child_with_name("priority");
149 if priority and #priority > 0 then
150 priority = t_concat(priority);
151 if s_find(priority, "^[+-]?[0-9]+$") then
152 priority = tonumber(priority);
153 if priority < -128 then priority = -128 end
154 if priority > 127 then priority = 127 end
155 else priority = 0; end
156 else priority = 0; end 135 else priority = 0; end
157 if origin.priority ~= priority then 136 else priority = 0; end
158 origin.priority = priority; 137 if origin.priority ~= priority then
159 recalc_resource_map(origin); 138 origin.priority = priority;
160 end 139 recalc_resource_map(origin);
161 end 140 end
162 stanza.attr.to = nil; -- reset it 141 end
163 else 142 stanza.attr.to = nil; -- reset it
164 log("warn", "presence recieved from client with no roster");
165 end
166 end 143 end
167 144
168 function send_presence_of_available_resources(user, host, jid, recipient_session, core_route_stanza) 145 function send_presence_of_available_resources(user, host, jid, recipient_session, core_route_stanza)
169 local h = hosts[host]; 146 local h = hosts[host];
170 local count = 0; 147 local count = 0;
266 end 243 end
267 end -- discard any other type 244 end -- discard any other type
268 stanza.attr.from, stanza.attr.to = st_from, st_to; 245 stanza.attr.from, stanza.attr.to = st_from, st_to;
269 end 246 end
270 247
271 local function presence_handler(data)
272 local origin, stanza = data.origin, data.stanza;
273 local to = stanza.attr.to;
274 local node, host = jid_split(to);
275 local to_bare = jid_bare(to);
276 local from_bare = jid_bare(stanza.attr.from);
277 if origin.type == "c2s" then
278 if to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then -- directed presence
279 origin.directed = origin.directed or {};
280 origin.directed[to] = true; -- FIXME does it make more sense to add to_bare rather than to?
281 end
282 if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
283 handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
284 elseif not to then
285 handle_normal_presence(origin, stanza, core_route_stanza);
286 else
287 core_route_stanza(origin, stanza);
288 end
289 elseif (origin.type == "s2sin" or origin.type == "component") and hosts[host] then
290 if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
291 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
292 else
293 core_route_stanza(origin, stanza);
294 end
295 end
296 return true;
297 end
298
299 prosody.events.add_handler(module:get_host().."/presence", presence_handler);
300 module.unload = function()
301 prosody.events.remove_handler(module:get_host().."/presence", presence_handler);
302 end
303
304 local outbound_presence_handler = function(data) 248 local outbound_presence_handler = function(data)
305 -- outbound presence recieved 249 -- outbound presence recieved
306 local origin, stanza = data.origin, data.stanza; 250 local origin, stanza = data.origin, data.stanza;
307 251
308 local to = stanza.attr.to; 252 local to = stanza.attr.to;
369 -- TODO fire post processing event 313 -- TODO fire post processing event
370 session.send(stanza); 314 session.send(stanza);
371 end -- resource not online, discard 315 end -- resource not online, discard
372 return true; 316 return true;
373 end); 317 end);
318
319 module:hook("resource-unbind", function(event)
320 local session, err = event.session, event.error;
321 -- Send unavailable presence
322 if session.presence then
323 local pres = st.presence{ type = "unavailable" };
324 if not(err) or err == "closed" then err = "connection closed"; end
325 pres:tag("status"):text("Disconnected: "..err):up();
326 session:dispatch_stanza(pres);
327 elseif session.directed then
328 local pres = st.presence{ type = "unavailable" };
329 if not(err) or err == "closed" then err = "connection closed"; end
330 pres:tag("status"):text("Disconnected: "..err):up();
331 for jid in pairs(session.directed) do
332 pres.attr.to = jid;
333 core_route_stanza(session, pres);
334 end
335 session.directed = nil;
336 end
337 end);