32 local tostring = tostring; |
32 local tostring = tostring; |
33 local t_concat = table.concat; |
33 local t_concat = table.concat; |
34 local t_insert = table.insert; |
34 local t_insert = table.insert; |
35 local tonumber = tonumber; |
35 local tonumber = tonumber; |
36 local s_find = string.find; |
36 local s_find = string.find; |
|
37 local pairs = pairs; |
|
38 local ipairs = ipairs; |
37 |
39 |
38 local jid_split = require "util.jid".split; |
40 local jid_split = require "util.jid".split; |
39 local jid_prepped_split = require "util.jid".prepped_split; |
41 local jid_prepped_split = require "util.jid".prepped_split; |
40 local print = print; |
42 local print = print; |
41 local function checked_error_reply(origin, stanza) |
43 local function checked_error_reply(origin, stanza) |
102 local host_status = origin.hosts[from_host]; |
104 local host_status = origin.hosts[from_host]; |
103 if not host_status or not host_status.authed then -- remote server trying to impersonate some other server? |
105 if not host_status or not host_status.authed then -- remote server trying to impersonate some other server? |
104 log("warn", "Received a stanza claiming to be from %s, over a conn authed for %s!", from_host, origin.from_host); |
106 log("warn", "Received a stanza claiming to be from %s, over a conn authed for %s!", from_host, origin.from_host); |
105 return; -- FIXME what should we do here? does this work with subdomains? |
107 return; -- FIXME what should we do here? does this work with subdomains? |
106 end |
108 end |
|
109 end |
|
110 if origin.type == "c2s" and stanza.name == "presence" and 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 |
|
111 origin.directed = origin.directed or {}; |
|
112 origin.directed[to] = true; |
|
113 --t_insert(origin.directed, to); -- FIXME does it make more sense to add to_bare rather than to? |
107 end |
114 end |
108 if not to then |
115 if not to then |
109 core_handle_stanza(origin, stanza); |
116 core_handle_stanza(origin, stanza); |
110 elseif hosts[to] and hosts[to].type == "local" then -- directed at a local server |
117 elseif hosts[to] and hosts[to].type == "local" then -- directed at a local server |
111 core_handle_stanza(origin, stanza); |
118 core_handle_stanza(origin, stanza); |
120 elseif origin.type == "c2s" and stanza.name == "presence" and stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then |
127 elseif origin.type == "c2s" and stanza.name == "presence" and stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then |
121 handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
128 handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
122 elseif origin.type ~= "c2s" and stanza.name == "iq" and not resource then -- directed at bare JID |
129 elseif origin.type ~= "c2s" and stanza.name == "iq" and not resource then -- directed at bare JID |
123 core_handle_stanza(origin, stanza); |
130 core_handle_stanza(origin, stanza); |
124 else |
131 else |
125 if origin.type == "c2s" and stanza.name == "presence" and to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then |
|
126 origin.directed = origin.directed or {}; |
|
127 t_insert(origin.directed, to); -- FIXME does it make more sense to add to_bare rather than to? |
|
128 end |
|
129 core_route_stanza(origin, stanza); |
132 core_route_stanza(origin, stanza); |
130 end |
133 end |
131 else |
134 else |
132 core_handle_stanza(origin, stanza); |
135 core_handle_stanza(origin, stanza); |
133 end |
136 end |
175 |
178 |
176 -- Auto-detect origin if not specified |
179 -- Auto-detect origin if not specified |
177 origin = origin or hosts[from_host]; |
180 origin = origin or hosts[from_host]; |
178 if not origin then return false; end |
181 if not origin then return false; end |
179 |
182 |
|
183 if hosts[to] and hosts[to].type == "component" then -- hack to allow components to handle node@server/resource and server/resource |
|
184 return component_handle_stanza(origin, stanza); |
|
185 elseif hosts[to_bare] and hosts[to_bare].type == "component" then -- hack to allow components to handle node@server |
|
186 return component_handle_stanza(origin, stanza); |
|
187 elseif hosts[host] and hosts[host].type == "component" then -- directed at a component |
|
188 return component_handle_stanza(origin, stanza); |
|
189 end |
|
190 |
180 if stanza.name == "presence" and (stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable") then resource = nil; end |
191 if stanza.name == "presence" and (stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable") then resource = nil; end |
181 |
192 |
182 local host_session = hosts[host] |
193 local host_session = hosts[host] |
183 if host_session and host_session.type == "local" then |
194 if host_session and host_session.type == "local" then |
184 -- Local host |
195 -- Local host |
197 session.send(stanza); |
208 session.send(stanza); |
198 end |
209 end |
199 end |
210 end |
200 end |
211 end |
201 elseif stanza.name == "message" then -- select a resource to recieve message |
212 elseif stanza.name == "message" then -- select a resource to recieve message |
202 local priority = 0; |
213 stanza.attr.to = to_bare; |
203 local recipients = {}; |
214 if stanza.attr.type == 'headline' then |
204 for _, session in pairs(user.sessions) do -- find resource with greatest priority |
215 for _, session in pairs(user.sessions) do -- find resource with greatest priority |
205 local p = session.priority or -1; |
216 if session.presence and session.priority >= 0 then |
206 if p > priority then |
217 session.send(stanza); |
207 priority = p; |
218 end |
208 recipients = {session}; |
219 end |
209 elseif p == priority then |
220 else |
210 t_insert(recipients, session); |
221 local priority = 0; |
211 end |
222 local recipients = {}; |
212 end |
223 for _, session in pairs(user.sessions) do -- find resource with greatest priority |
213 local count = 0; |
224 if session.presence then |
214 for _, session in pairs(recipients) do |
225 local p = session.priority; |
215 session.send(stanza); |
226 if p > priority then |
216 count = count + 1; |
227 priority = p; |
217 end |
228 recipients = {session}; |
218 if count == 0 then |
229 elseif p == priority then |
219 offlinemanager.store(node, host, stanza); |
230 t_insert(recipients, session); |
220 -- TODO deal with storage errors |
231 end |
|
232 end |
|
233 end |
|
234 local count = 0; |
|
235 for _, session in ipairs(recipients) do |
|
236 session.send(stanza); |
|
237 count = count + 1; |
|
238 end |
|
239 if count == 0 and (stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type) then |
|
240 offlinemanager.store(node, host, stanza); |
|
241 -- TODO deal with storage errors |
|
242 end |
221 end |
243 end |
222 else |
244 else |
223 -- TODO send IQ error |
245 -- TODO send IQ error |
224 end |
246 end |
225 else |
247 else |
235 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
257 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza); |
236 else |
258 else |
237 -- TODO send unavailable presence or unsubscribed |
259 -- TODO send unavailable presence or unsubscribed |
238 end |
260 end |
239 elseif stanza.name == "message" then -- FIXME if full jid, then send out to resources with highest priority |
261 elseif stanza.name == "message" then -- FIXME if full jid, then send out to resources with highest priority |
|
262 stanza.attr.to = to_bare; -- TODO not in RFC, but seems obvious. Should discuss on the mailing list. |
240 if stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type then |
263 if stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type then |
241 offlinemanager.store(node, host, stanza); |
264 offlinemanager.store(node, host, stanza); |
242 -- FIXME don't store messages with only chat state notifications |
265 -- FIXME don't store messages with only chat state notifications |
243 end |
266 end |
244 -- TODO allow configuration of offline storage |
267 -- TODO allow configuration of offline storage |