Software /
code /
prosody
Comparison
core/stanza_router.lua @ 118:76ac96c53ee5
Merge roster & presence from waqas
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 22 Oct 2008 23:12:26 +0100 |
parent | 113:9026fdad1531 |
child | 119:b48a573608e8 |
comparison
equal
deleted
inserted
replaced
99:ba08b8a4eeef | 118:76ac96c53ee5 |
---|---|
7 | 7 |
8 local log = require "util.logger".init("stanzarouter") | 8 local log = require "util.logger".init("stanzarouter") |
9 | 9 |
10 local st = require "util.stanza"; | 10 local st = require "util.stanza"; |
11 local send = require "core.sessionmanager".send_to_session; | 11 local send = require "core.sessionmanager".send_to_session; |
12 | 12 local user_exists = require "core.usermanager".user_exists; |
13 require "util.jid" | 13 |
14 local jid_split = jid.split; | 14 local jid_split = require "util.jid".split; |
15 local print = print; | |
15 | 16 |
16 function core_process_stanza(origin, stanza) | 17 function core_process_stanza(origin, stanza) |
17 log("debug", "Received: "..tostring(stanza)) | 18 log("debug", "Received: "..tostring(stanza)) |
18 -- TODO verify validity of stanza (as well as JID validity) | 19 -- TODO verify validity of stanza (as well as JID validity) |
19 if stanza.name == "iq" and not(#stanza.tags == 1 and stanza.tags[1].attr.xmlns) then | 20 if stanza.name == "iq" and not(#stanza.tags == 1 and stanza.tags[1].attr.xmlns) then |
20 error("Invalid IQ"); | 21 if stanza.attr.type == "set" or stanza.attr.type == "get" then |
22 error("Invalid IQ"); | |
23 elseif #stanza.tags > 1 or not(stanza.attr.type == "error" or stanza.attr.type == "result") then | |
24 error("Invalid IQ"); | |
25 end | |
21 end | 26 end |
22 | 27 |
23 if origin.type == "c2s" and not origin.full_jid | 28 if origin.type == "c2s" and not origin.full_jid |
24 and not(stanza.name == "iq" and stanza.tags[1].name == "bind" | 29 and not(stanza.name == "iq" and stanza.tags[1].name == "bind" |
25 and stanza.tags[1].attr.xmlns == "urn:ietf:params:xml:ns:xmpp-bind") then | 30 and stanza.tags[1].attr.xmlns == "urn:ietf:params:xml:ns:xmpp-bind") then |
26 error("Client MUST bind resource after auth"); | 31 error("Client MUST bind resource after auth"); |
27 end | 32 end |
28 | 33 |
34 local to = stanza.attr.to; | |
35 stanza.attr.from = origin.full_jid; -- quick fix to prevent impersonation (FIXME this would be incorrect when the origin is not c2s) | |
36 -- TODO also, stazas should be returned to their original state before the function ends | |
29 | 37 |
30 local to = stanza.attr.to; | 38 -- TODO presence subscriptions |
31 stanza.attr.from = origin.full_jid -- quick fix to prevent impersonation | 39 if not to then |
32 | 40 if stanza.name == "presence" and origin.roster then |
33 if not to or (hosts[to] and hosts[to].type == "local") then | 41 if stanza.attr.type == nil or stanza.attr.type == "available" or stanza.attr.type == "unavailable" then |
42 --stanza.attr.from = origin.full_jid; | |
43 for jid in pairs(origin.roster) do -- broadcast to all interested contacts | |
44 local subscription = origin.roster[jid].subscription; | |
45 if subscription == "both" or subscription == "from" then | |
46 stanza.attr.to = jid; | |
47 core_route_stanza(origin, stanza); | |
48 end | |
49 end | |
50 --[[local node, host = jid_split(stanza.attr.from); | |
51 for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources | |
52 if res.full_jid then | |
53 res = user.sessions[k]; | |
54 break; | |
55 end | |
56 end]] | |
57 if not origin.presence then -- presence probes on initial presence | |
58 local probe = st.presence({from = origin.full_jid, type = "probe"}); | |
59 for jid in pairs(origin.roster) do | |
60 local subscription = origin.roster[jid].subscription; | |
61 if subscription == "both" or subscription == "to" then | |
62 probe.attr.to = jid; | |
63 core_route_stanza(origin, probe); | |
64 end | |
65 end | |
66 end | |
67 origin.presence = stanza; | |
68 stanza.attr.to = nil; -- reset it | |
69 else | |
70 -- TODO error, bad type | |
71 end | |
72 else | |
73 core_handle_stanza(origin, stanza); | |
74 end | |
75 elseif hosts[to] and hosts[to].type == "local" then | |
34 core_handle_stanza(origin, stanza); | 76 core_handle_stanza(origin, stanza); |
35 elseif to and stanza.name == "iq" and not select(3, jid_split(to)) then | 77 elseif stanza.name == "iq" and not select(3, jid_split(to)) then |
36 core_handle_stanza(origin, stanza); | 78 core_handle_stanza(origin, stanza); |
37 elseif origin.type == "c2s" then | 79 elseif origin.type == "c2s" then |
38 core_route_stanza(origin, stanza); | 80 core_route_stanza(origin, stanza); |
39 end | 81 end |
40 end | 82 end |
41 | 83 |
42 function core_handle_stanza(origin, stanza) | 84 function core_handle_stanza(origin, stanza) |
43 -- Handlers | 85 -- Handlers |
44 if origin.type == "c2s" or origin.type == "c2s_unauthed" then | 86 if origin.type == "c2s" or origin.type == "c2s_unauthed" then |
45 local session = origin; | 87 local session = origin; |
46 stanza.attr.from = session.full_jid; | |
47 | 88 |
48 log("debug", "Routing stanza"); | 89 log("debug", "Routing stanza"); |
49 -- Stanza has no to attribute | 90 -- Stanza has no to attribute |
50 --local to_node, to_host, to_resource = jid_split(stanza.attr.to); | 91 --local to_node, to_host, to_resource = jid_split(stanza.attr.to); |
51 --if not to_host then error("Invalid destination JID: "..string.format("{ %q, %q, %q } == %q", to_node or "", to_host or "", to_resource or "", stanza.attr.to or "nil")); end | 92 --if not to_host then error("Invalid destination JID: "..string.format("{ %q, %q, %q } == %q", to_node or "", to_host or "", to_resource or "", stanza.attr.to or "nil")); end |
54 log("debug", "Routing stanza to local"); | 95 log("debug", "Routing stanza to local"); |
55 handle_stanza(session, stanza); | 96 handle_stanza(session, stanza); |
56 end | 97 end |
57 end | 98 end |
58 | 99 |
100 function is_authorized_to_see_presence(origin, username, host) | |
101 local roster = datamanager.load(username, host, "roster") or {}; | |
102 local item = roster[origin.username.."@"..origin.host]; | |
103 return item and (item.subscription == "both" or item.subscription == "from"); | |
104 end | |
105 | |
59 function core_route_stanza(origin, stanza) | 106 function core_route_stanza(origin, stanza) |
60 -- Hooks | 107 -- Hooks |
61 --- ...later | 108 --- ...later |
62 | 109 |
63 -- Deliver | 110 -- Deliver |
64 local node, host, resource = jid_split(stanza.attr.to); | 111 local to = stanza.attr.to; |
112 local node, host, resource = jid_split(to); | |
113 | |
114 if stanza.name == "presence" and stanza.attr.type == "probe" then resource = nil; end | |
115 | |
65 local host_session = hosts[host] | 116 local host_session = hosts[host] |
66 if host_session and host_session.type == "local" then | 117 if host_session and host_session.type == "local" then |
67 -- Local host | 118 -- Local host |
68 local user = host_session.sessions[node]; | 119 local user = host_session.sessions[node]; |
69 if user then | 120 if user then |
70 local res = user.sessions[resource]; | 121 local res = user.sessions[resource]; |
71 -- TODO do something about presence broadcast | |
72 if not res then | 122 if not res then |
73 -- if we get here, resource was not specified or was unavailable | 123 -- if we get here, resource was not specified or was unavailable |
74 for k in pairs(user.sessions) do | 124 if stanza.name == "presence" then |
75 res = user.sessions[k]; | 125 if stanza.attr.type == "probe" then |
76 break; | 126 if is_authorized_to_see_presence(origin, node, host) then |
77 end | 127 for k in pairs(user.sessions) do -- return presence for all resources |
78 -- TODO find resource with greatest priority | 128 if user.sessions[k].presence then |
79 end | 129 local pres = user.sessions[k].presence; |
80 stanza.attr.to = res.full_jid; | 130 pres.attr.to = origin.full_jid; |
81 send(res, stanza); -- Yay \o/ | 131 pres.attr.from = user.sessions[k].full_jid; |
132 send(origin, pres); | |
133 pres.attr.to = nil; | |
134 pres.attr.from = nil; | |
135 end | |
136 end | |
137 else | |
138 send(origin, st.presence({from = user.."@"..host, to = origin.username.."@"..origin.host, type = "unsubscribed"})); | |
139 end | |
140 else | |
141 for k in pairs(user.sessions) do -- presence broadcast to all user resources | |
142 if user.sessions[k].full_jid then | |
143 stanza.attr.to = user.sessions[k].full_jid; | |
144 send(user.sessions[k], stanza); | |
145 end | |
146 end | |
147 end | |
148 elseif stanza.name == "message" then -- select a resource to recieve message | |
149 for k in pairs(user.sessions) do | |
150 if user.sessions[k].full_jid then | |
151 res = user.sessions[k]; | |
152 break; | |
153 end | |
154 end | |
155 -- TODO find resource with greatest priority | |
156 send(res, stanza); | |
157 else | |
158 -- TODO send IQ error | |
159 end | |
160 else | |
161 stanza.attr.to = res.full_jid; | |
162 send(res, stanza); -- Yay \o/ | |
163 end | |
82 else | 164 else |
83 -- user not found | 165 -- user not online |
84 send(origin, st.error_reply(stanza, "cancel", "service-unavailable")); | 166 if user_exists(node, host) then |
167 if stanza.name == "presence" then | |
168 if stanza.attr.type == "probe" and is_authorized_to_see_presence(origin, node, host) then -- FIXME what to do for not c2s? | |
169 -- TODO send last recieved unavailable presence | |
170 else | |
171 -- TODO send unavailable presence | |
172 end | |
173 elseif stanza.name == "message" then | |
174 -- TODO send message error, or store offline messages | |
175 elseif stanza.name == "iq" then | |
176 -- TODO send IQ error | |
177 end | |
178 else -- user does not exist | |
179 -- TODO we would get here for nodeless JIDs too. Do something fun maybe? Echo service? Let plugins use xmpp:server/resource addresses? | |
180 if stanza.name == "presence" then | |
181 if stanza.attr.type == "probe" then | |
182 send(origin, st.presence({from = user.."@"..host, to = origin.username.."@"..origin.host, type = "unsubscribed"})); | |
183 end | |
184 -- else ignore | |
185 else | |
186 send(origin, st.error_reply(stanza, "cancel", "service-unavailable")); | |
187 end | |
188 end | |
85 end | 189 end |
86 else | 190 else |
87 -- Remote host | 191 -- Remote host |
88 if host_session then | 192 if host_session then |
89 -- Send to session | 193 -- Send to session |
90 else | 194 else |
91 -- Need to establish the connection | 195 -- Need to establish the connection |
92 end | 196 end |
93 end | 197 end |
198 stanza.attr.to = to; -- reset | |
94 end | 199 end |
95 | 200 |
96 function handle_stanza_nodest(stanza) | 201 function handle_stanza_nodest(stanza) |
97 if stanza.name == "iq" then | 202 if stanza.name == "iq" then |
98 handle_stanza_iq_no_to(session, stanza); | 203 handle_stanza_iq_no_to(session, stanza); |