32 local _PRESENCE_MANAGED = set.new({'managed_entity', 'roster'}) |
32 local _PRESENCE_MANAGED = set.new({'managed_entity', 'roster'}) |
33 local _TO_CHECK = {roster=_ALLOWED_ROSTER, message=_ALLOWED_MESSAGE, presence=_ALLOWED_PRESENCE} |
33 local _TO_CHECK = {roster=_ALLOWED_ROSTER, message=_ALLOWED_MESSAGE, presence=_ALLOWED_PRESENCE} |
34 local _PRIV_ENT_NS = 'urn:xmpp:privilege:1' |
34 local _PRIV_ENT_NS = 'urn:xmpp:privilege:1' |
35 local _FORWARDED_NS = 'urn:xmpp:forward:0' |
35 local _FORWARDED_NS = 'urn:xmpp:forward:0' |
36 |
36 |
|
37 local last_presence = nil -- cache used to avoid to send several times the same stanza (see § 7 #2) |
|
38 |
37 |
39 |
38 module:log("debug", "Loading privileged entity module "); |
40 module:log("debug", "Loading privileged entity module "); |
39 |
41 |
40 |
42 |
41 --> Permissions management <-- |
43 --> Permissions management <-- |
56 session.send(message) |
58 session.send(message) |
57 end |
59 end |
58 |
60 |
59 function set_presence_perm_set(to_jid, perms) |
61 function set_presence_perm_set(to_jid, perms) |
60 -- fill the global presence sets according to perms |
62 -- fill the global presence sets according to perms |
61 if perms.presence == 'managed_entity' then |
63 if _PRESENCE_MANAGED:contains(perms.presence) then |
62 presence_man_ent:add(to_jid) |
64 presence_man_ent:add(to_jid) |
63 elseif perms.presence == 'roster' then |
65 end |
64 presence_man_ent:add(to_jid) -- roster imply managed_entity |
66 if perms.presence == 'roster' then |
65 presence_roster:add(to_jid) |
67 presence_roster:add(to_jid) |
66 end |
68 end |
67 end |
69 end |
68 |
70 |
69 function advertise_presences(session, to_jid, perms) |
71 function advertise_presences(session, to_jid, perms) |
308 end); |
310 end); |
309 |
311 |
310 |
312 |
311 --> presence permission <-- |
313 --> presence permission <-- |
312 |
314 |
|
315 function same_tags(tag1, tag2) |
|
316 -- check if two tags are equivalent |
|
317 |
|
318 if tag1.name ~= tag2.name then return false; end |
|
319 |
|
320 if #tag1 ~= #tag2 then return false; end |
|
321 |
|
322 for name, value in pairs(tag1.attr) do |
|
323 if tag2.attr[name] ~= value then return false; end |
|
324 end |
|
325 |
|
326 for i=1,#tag1 do |
|
327 if type(tag1[i]) == "string" then |
|
328 if tag1[i] ~= tag2[i] then return false; end |
|
329 else |
|
330 if not same_tags(tag1[i], tag2[i]) then return false; end |
|
331 end |
|
332 end |
|
333 |
|
334 return true |
|
335 end |
|
336 |
|
337 function same_presences(presence1, presence2) |
|
338 -- check that 2 <presence/> stanzas are equivalent (except for "to" attribute) |
|
339 -- /!\ if the id change but everything else is equivalent, this method return false |
|
340 -- this behaviour may change in the future |
|
341 if presence1.attr.from ~= presence2.attr.from or presence1.attr.id ~= presence2.attr.id |
|
342 or presence1.attr.type ~= presence2.attr.type then |
|
343 return false |
|
344 end |
|
345 |
|
346 if presence1.attr.id and presence1.attr.id == presence2.attr.id then return true; end |
|
347 |
|
348 if #presence1 ~= #presence2 then return false; end |
|
349 |
|
350 for i=1,#presence1 do |
|
351 if type(presence1[i]) == "string" then |
|
352 if presence1[i] ~= presence2[i] then return false; end |
|
353 else |
|
354 if not same_tags(presence1[i], presence2[i]) then return false; end |
|
355 end |
|
356 end |
|
357 |
|
358 return true |
|
359 end |
|
360 |
|
361 function forward_presence(presence, to_jid) |
|
362 presence_fwd = st.clone(presence) |
|
363 presence_fwd.attr.to = to_jid |
|
364 module:log("debug", "presence forwarded to "..to_jid..": "..tostring(presence_fwd)) |
|
365 module:send(presence_fwd) |
|
366 last_presence = presence -- we keep the presence in cache |
|
367 end |
|
368 |
313 module:hook("presence/bare", function(event) |
369 module:hook("presence/bare", function(event) |
314 if presence_man_ent:empty() then return; end |
370 if presence_man_ent:empty() and presence_roster:empty() then return; end |
315 local session, stanza = event.origin, event.stanza; |
371 |
316 if stanza.attr.to then return; end |
372 local session, stanza = event.origin, event.stanza; |
317 if stanza.attr.type == nil or stanza.attr.type == "unavailable" then |
373 if stanza.attr.type == nil or stanza.attr.type == "unavailable" then |
318 for entity in presence_man_ent:items() do |
374 if not stanza.attr.to then |
319 if stanza.attr.from ~= entity then |
375 for entity in presence_man_ent:items() do |
320 presence_fwd = st.clone(stanza) |
376 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end |
321 presence_fwd.attr.to = entity |
377 end |
322 module:log("debug", "presence forwarded to "..entity..": "..tostring(presence_fwd)) |
378 else -- directed presence |
323 prosody.core_route_stanza(nil, presence_fwd) |
379 -- we ignore directed presences from our own host, as we already have them |
324 end |
380 _, from_host = jid.split(stanza.attr.from) |
325 end |
381 if hosts[from_host] then return; end |
326 end |
382 |
327 end, 150); |
383 -- we don't send several time the same presence, as recommended in §7 #2 |
|
384 if last_presence and same_presences(last_presence, stanza) then |
|
385 return |
|
386 end |
|
387 |
|
388 for entity in presence_roster:items() do |
|
389 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end |
|
390 end |
|
391 end |
|
392 end |
|
393 end, 150) |