Mercurial > prosody-hg
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); |
