author | Matthew Wild <mwild1@gmail.com> |
Fri, 29 May 2009 18:03:48 +0100 | |
changeset 1217 | 844ef764ef0e |
parent 1211 | d60e68855176 |
child 1245 | be5fe60bd866 |
permissions | -rw-r--r-- |
1009 | 1 |
-- Prosody IM v0.4 |
2 |
-- Copyright (C) 2008-2009 Matthew Wild |
|
3 |
-- Copyright (C) 2008-2009 Waqas Hussain |
|
4 |
-- |
|
5 |
-- This project is MIT/X11 licensed. Please see the |
|
6 |
-- COPYING file in the source package for more information. |
|
7 |
-- |
|
8 |
||
1210
342f401f354c
mod_presence: Use logger supplied by modulemanager
Matthew Wild <mwild1@gmail.com>
parents:
1209
diff
changeset
|
9 |
local log = module._log; |
1009 | 10 |
|
11 |
local require = require; |
|
12 |
local pairs, ipairs = pairs, ipairs; |
|
13 |
local t_concat = table.concat; |
|
14 |
local s_find = string.find; |
|
15 |
local tonumber = tonumber; |
|
16 |
||
17 |
local st = require "util.stanza"; |
|
18 |
local jid_split = require "util.jid".split; |
|
19 |
local jid_bare = require "util.jid".bare; |
|
20 |
local hosts = hosts; |
|
21 |
||
22 |
local rostermanager = require "core.rostermanager"; |
|
23 |
local sessionmanager = require "core.sessionmanager"; |
|
24 |
local offlinemanager = require "core.offlinemanager"; |
|
25 |
||
1044
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
26 |
local _core_route_stanza = core_route_stanza; |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
27 |
local core_route_stanza; |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
28 |
function core_route_stanza(origin, stanza) |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
29 |
if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
30 |
local node, host = jid_split(stanza.attr.to); |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
31 |
host = hosts[host]; |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
32 |
if host and host.type == "local" then |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
33 |
handle_inbound_presence_subscriptions_and_probes(origin, stanza, jid_bare(stanza.attr.from), jid_bare(stanza.attr.to), core_route_stanza); |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
34 |
return; |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
35 |
end |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
36 |
end |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
37 |
_core_route_stanza(origin, stanza); |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
38 |
end |
41a0c76127f4
mod_presence: Fix for local presence subscriptions and probes
Waqas Hussain <waqas20@gmail.com>
parents:
1023
diff
changeset
|
39 |
|
1009 | 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 |
|
54 |
||
55 |
function handle_normal_presence(origin, stanza, core_route_stanza) |
|
56 |
if origin.roster then |
|
57 |
for jid in pairs(origin.roster) do -- broadcast to all interested contacts |
|
58 |
local subscription = origin.roster[jid].subscription; |
|
59 |
if subscription == "both" or subscription == "from" then |
|
60 |
stanza.attr.to = jid; |
|
61 |
core_route_stanza(origin, stanza); |
|
62 |
end |
|
63 |
end |
|
64 |
local node, host = jid_split(stanza.attr.from); |
|
65 |
for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources |
|
1057
2677f5a4e66b
mod_presence: Broadcast a user's presence to only the user's 'available' resources
Waqas Hussain <waqas20@gmail.com>
parents:
1044
diff
changeset
|
66 |
if res ~= origin and res.presence then -- to resource |
1009 | 67 |
stanza.attr.to = res.full_jid; |
68 |
core_route_stanza(origin, stanza); |
|
69 |
end |
|
70 |
end |
|
71 |
if stanza.attr.type == nil and not origin.presence then -- initial presence |
|
72 |
local probe = st.presence({from = origin.full_jid, type = "probe"}); |
|
73 |
for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to |
|
74 |
local subscription = origin.roster[jid].subscription; |
|
75 |
if subscription == "both" or subscription == "to" then |
|
76 |
probe.attr.to = jid; |
|
77 |
core_route_stanza(origin, probe); |
|
78 |
end |
|
79 |
end |
|
80 |
for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources |
|
81 |
if res ~= origin and res.presence then |
|
82 |
res.presence.attr.to = origin.full_jid; |
|
83 |
core_route_stanza(res, res.presence); |
|
84 |
res.presence.attr.to = nil; |
|
85 |
end |
|
86 |
end |
|
87 |
if origin.roster.pending then -- resend incoming subscription requests |
|
88 |
for jid in pairs(origin.roster.pending) do |
|
89 |
origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original? |
|
90 |
end |
|
91 |
end |
|
92 |
local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host}); |
|
93 |
for jid, item in pairs(origin.roster) do -- resend outgoing subscription requests |
|
94 |
if item.ask then |
|
95 |
request.attr.to = jid; |
|
96 |
core_route_stanza(origin, request); |
|
97 |
end |
|
98 |
end |
|
99 |
local offline = offlinemanager.load(node, host); |
|
100 |
if offline then |
|
101 |
for _, msg in ipairs(offline) do |
|
102 |
origin.send(msg); -- FIXME do we need to modify to/from in any way? |
|
103 |
end |
|
104 |
offlinemanager.deleteAll(node, host); |
|
105 |
end |
|
106 |
end |
|
107 |
origin.priority = 0; |
|
108 |
if stanza.attr.type == "unavailable" then |
|
109 |
origin.presence = nil; |
|
110 |
if origin.directed then |
|
111 |
local old_from = stanza.attr.from; |
|
112 |
stanza.attr.from = origin.full_jid; |
|
113 |
for jid in pairs(origin.directed) do |
|
114 |
stanza.attr.to = jid; |
|
115 |
core_route_stanza(origin, stanza); |
|
116 |
end |
|
117 |
stanza.attr.from = old_from; |
|
118 |
origin.directed = nil; |
|
119 |
end |
|
120 |
else |
|
121 |
origin.presence = stanza; |
|
122 |
local priority = stanza:child_with_name("priority"); |
|
123 |
if priority and #priority > 0 then |
|
124 |
priority = t_concat(priority); |
|
125 |
if s_find(priority, "^[+-]?[0-9]+$") then |
|
126 |
priority = tonumber(priority); |
|
127 |
if priority < -128 then priority = -128 end |
|
128 |
if priority > 127 then priority = 127 end |
|
129 |
origin.priority = priority; |
|
130 |
end |
|
131 |
end |
|
132 |
end |
|
133 |
stanza.attr.to = nil; -- reset it |
|
134 |
else |
|
1211
d60e68855176
mod_presence: Lower some log levels to their correct values
Matthew Wild <mwild1@gmail.com>
parents:
1210
diff
changeset
|
135 |
log("warn", "presence recieved from client with no roster"); |
1009 | 136 |
end |
137 |
end |
|
138 |
||
139 |
function send_presence_of_available_resources(user, host, jid, recipient_session, core_route_stanza) |
|
140 |
local h = hosts[host]; |
|
141 |
local count = 0; |
|
142 |
if h and h.type == "local" then |
|
143 |
local u = h.sessions[user]; |
|
144 |
if u then |
|
145 |
for k, session in pairs(u.sessions) do |
|
146 |
local pres = session.presence; |
|
147 |
if pres then |
|
148 |
pres.attr.to = jid; |
|
149 |
core_route_stanza(session, pres); |
|
150 |
pres.attr.to = nil; |
|
151 |
count = count + 1; |
|
152 |
end |
|
153 |
end |
|
154 |
end |
|
155 |
end |
|
1211
d60e68855176
mod_presence: Lower some log levels to their correct values
Matthew Wild <mwild1@gmail.com>
parents:
1210
diff
changeset
|
156 |
log("debug", "broadcasted presence of "..count.." resources from "..user.."@"..host.." to "..jid); |
1009 | 157 |
return count; |
158 |
end |
|
159 |
||
160 |
function handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza) |
|
161 |
local node, host = jid_split(from_bare); |
|
162 |
local st_from, st_to = stanza.attr.from, stanza.attr.to; |
|
163 |
stanza.attr.from, stanza.attr.to = from_bare, to_bare; |
|
164 |
log("debug", "outbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare); |
|
165 |
if stanza.attr.type == "subscribe" then |
|
166 |
-- 1. route stanza |
|
167 |
-- 2. roster push (subscription = none, ask = subscribe) |
|
168 |
if rostermanager.set_contact_pending_out(node, host, to_bare) then |
|
169 |
rostermanager.roster_push(node, host, to_bare); |
|
170 |
end -- else file error |
|
171 |
core_route_stanza(origin, stanza); |
|
172 |
elseif stanza.attr.type == "unsubscribe" then |
|
173 |
-- 1. route stanza |
|
174 |
-- 2. roster push (subscription = none or from) |
|
175 |
if rostermanager.unsubscribe(node, host, to_bare) then |
|
176 |
rostermanager.roster_push(node, host, to_bare); -- FIXME do roster push when roster has in fact not changed? |
|
177 |
end -- else file error |
|
178 |
core_route_stanza(origin, stanza); |
|
179 |
elseif stanza.attr.type == "subscribed" then |
|
180 |
-- 1. route stanza |
|
181 |
-- 2. roster_push () |
|
182 |
-- 3. send_presence_of_available_resources |
|
183 |
if rostermanager.subscribed(node, host, to_bare) then |
|
184 |
rostermanager.roster_push(node, host, to_bare); |
|
185 |
end |
|
186 |
core_route_stanza(origin, stanza); |
|
187 |
send_presence_of_available_resources(node, host, to_bare, origin, core_route_stanza); |
|
188 |
elseif stanza.attr.type == "unsubscribed" then |
|
189 |
-- 1. route stanza |
|
190 |
-- 2. roster push (subscription = none or to) |
|
191 |
if rostermanager.unsubscribed(node, host, to_bare) then |
|
192 |
rostermanager.roster_push(node, host, to_bare); |
|
193 |
end |
|
194 |
core_route_stanza(origin, stanza); |
|
195 |
end |
|
196 |
stanza.attr.from, stanza.attr.to = st_from, st_to; |
|
197 |
end |
|
198 |
||
199 |
function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza) |
|
200 |
local node, host = jid_split(to_bare); |
|
201 |
local st_from, st_to = stanza.attr.from, stanza.attr.to; |
|
202 |
stanza.attr.from, stanza.attr.to = from_bare, to_bare; |
|
203 |
log("debug", "inbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare); |
|
204 |
if stanza.attr.type == "probe" then |
|
205 |
if rostermanager.is_contact_subscribed(node, host, from_bare) then |
|
206 |
if 0 == send_presence_of_available_resources(node, host, from_bare, origin, core_route_stanza) then |
|
207 |
-- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too) |
|
208 |
end |
|
209 |
else |
|
210 |
core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="unsubscribed"})); |
|
211 |
end |
|
212 |
elseif stanza.attr.type == "subscribe" then |
|
213 |
if rostermanager.is_contact_subscribed(node, host, from_bare) then |
|
214 |
core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed |
|
215 |
-- Sending presence is not clearly stated in the RFC, but it seems appropriate |
|
216 |
if 0 == send_presence_of_available_resources(node, host, from_bare, origin, core_route_stanza) then |
|
217 |
-- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too) |
|
218 |
end |
|
219 |
else |
|
220 |
if not rostermanager.is_contact_pending_in(node, host, from_bare) then |
|
221 |
if rostermanager.set_contact_pending_in(node, host, from_bare) then |
|
222 |
sessionmanager.send_to_available_resources(node, host, stanza); |
|
223 |
end -- TODO else return error, unable to save |
|
224 |
end |
|
225 |
end |
|
226 |
elseif stanza.attr.type == "unsubscribe" then |
|
227 |
if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then |
|
228 |
rostermanager.roster_push(node, host, from_bare); |
|
229 |
end |
|
230 |
elseif stanza.attr.type == "subscribed" then |
|
231 |
if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then |
|
232 |
rostermanager.roster_push(node, host, from_bare); |
|
233 |
end |
|
234 |
elseif stanza.attr.type == "unsubscribed" then |
|
235 |
if rostermanager.process_inbound_subscription_cancellation(node, host, from_bare) then |
|
236 |
rostermanager.roster_push(node, host, from_bare); |
|
237 |
end |
|
238 |
end -- discard any other type |
|
239 |
stanza.attr.from, stanza.attr.to = st_from, st_to; |
|
240 |
end |
|
241 |
||
242 |
local function presence_handler(data) |
|
243 |
local origin, stanza = data.origin, data.stanza; |
|
244 |
local to = stanza.attr.to; |
|
245 |
local node, host = jid_split(to); |
|
246 |
local to_bare = jid_bare(to); |
|
247 |
local from_bare = jid_bare(stanza.attr.from); |
|
248 |
if origin.type == "c2s" then |
|
249 |
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 |
|
250 |
origin.directed = origin.directed or {}; |
|
1150
d71a8f28f18b
mod_presence: Added a FIXME comment about directed presence
Waqas Hussain <waqas20@gmail.com>
parents:
1147
diff
changeset
|
251 |
origin.directed[to] = true; -- FIXME does it make more sense to add to_bare rather than to? |
1009 | 252 |
end |
1019
8d750336e517
mod_presence: Fix incorrect internal routing for probes and subscriptions
Waqas Hussain <waqas20@gmail.com>
parents:
1011
diff
changeset
|
253 |
if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then |
1009 | 254 |
handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
255 |
elseif not to then |
|
1011
beb039827c9f
Stopped using presencemanager in stanza_router
Waqas Hussain <waqas20@gmail.com>
parents:
1009
diff
changeset
|
256 |
handle_normal_presence(origin, stanza, core_route_stanza); |
1009 | 257 |
else |
258 |
core_route_stanza(origin, stanza); |
|
259 |
end |
|
260 |
elseif (origin.type == "s2sin" or origin.type == "component") and hosts[host] then |
|
1019
8d750336e517
mod_presence: Fix incorrect internal routing for probes and subscriptions
Waqas Hussain <waqas20@gmail.com>
parents:
1011
diff
changeset
|
261 |
if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then |
1009 | 262 |
handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
263 |
else |
|
264 |
core_route_stanza(origin, stanza); |
|
265 |
end |
|
266 |
end |
|
1147
513c1d071045
mod_presence: return true from the presence handler
Waqas Hussain <waqas20@gmail.com>
parents:
1057
diff
changeset
|
267 |
return true; |
1009 | 268 |
end |
269 |
||
270 |
local add_handler = require "core.eventmanager2".add_handler; |
|
271 |
local remove_handler = require "core.eventmanager2".remove_handler; |
|
272 |
||
273 |
add_handler(module:get_host().."/presence", presence_handler); |
|
274 |
module.unload = function() |
|
275 |
remove_handler(module:get_host().."/presence", presence_handler); |
|
276 |
end |