1 -- Verse XMPP Library |
1 -- Verse XMPP Library |
2 -- Copyright (C) 2010 Hubert Chathi <hubert@uhoreg.ca> |
2 -- Copyright (C) 2010 Hubert Chathi <hubert@uhoreg.ca> |
3 -- Copyright (C) 2010 Matthew Wild <mwild1@gmail.com> |
3 -- Copyright (C) 2010 Matthew Wild <mwild1@gmail.com> |
4 -- |
4 -- |
5 -- This project is MIT/X11 licensed. Please see the |
5 -- This project is MIT/X11 licensed. Please see the |
6 -- COPYING file in the source package for more information. |
6 -- COPYING file in the source package for more information. |
7 -- |
7 -- |
8 |
8 |
9 local verse = require "verse"; |
9 local verse = require "verse"; |
133 function stream:add_disco_feature(feature, node) |
133 function stream:add_disco_feature(feature, node) |
134 local feature = feature.var or feature; |
134 local feature = feature.var or feature; |
135 self.disco.info[node or false].features[feature] = true; |
135 self.disco.info[node or false].features[feature] = true; |
136 stream:resend_presence(); |
136 stream:resend_presence(); |
137 end |
137 end |
138 |
138 |
139 function stream:remove_disco_feature(feature, node) |
139 function stream:remove_disco_feature(feature, node) |
140 local feature = feature.var or feature; |
140 local feature = feature.var or feature; |
141 self.disco.info[node or false].features[feature] = nil; |
141 self.disco.info[node or false].features[feature] = nil; |
142 stream:resend_presence(); |
142 stream:resend_presence(); |
143 end |
143 end |
179 if not cached_disco or not cached_disco.features then |
179 if not cached_disco or not cached_disco.features then |
180 return nil, "no-cache"; |
180 return nil, "no-cache"; |
181 end |
181 end |
182 return cached_disco.features[feature] or false; |
182 return cached_disco.features[feature] or false; |
183 end |
183 end |
184 |
184 |
185 function stream:get_local_services(category, type) |
185 function stream:get_local_services(category, type) |
186 local host_disco = self.disco.cache[self.host]; |
186 local host_disco = self.disco.cache[self.host]; |
187 if not(host_disco) or not(host_disco.items) then |
187 if not(host_disco) or not(host_disco.items) then |
188 return nil, "no-cache"; |
188 return nil, "no-cache"; |
189 end |
189 end |
190 |
190 |
191 local results = {}; |
191 local results = {}; |
192 for _, service in ipairs(host_disco.items) do |
192 for _, service in ipairs(host_disco.items) do |
193 if self:jid_has_identity(service.jid, category, type) then |
193 if self:jid_has_identity(service.jid, category, type) then |
194 table.insert(results, service.jid); |
194 table.insert(results, service.jid); |
195 end |
195 end |
196 end |
196 end |
197 return results; |
197 return results; |
198 end |
198 end |
199 |
199 |
200 function stream:disco_local_services(callback) |
200 function stream:disco_local_services(callback) |
201 self:disco_items(self.host, nil, function (items) |
201 self:disco_items(self.host, nil, function (items) |
202 if not items then |
202 if not items then |
203 return callback({}); |
203 return callback({}); |
204 end |
204 end |
207 n_items = n_items - 1; |
207 n_items = n_items - 1; |
208 if n_items == 0 then |
208 if n_items == 0 then |
209 return callback(items); |
209 return callback(items); |
210 end |
210 end |
211 end |
211 end |
212 |
212 |
213 for _, item in ipairs(items) do |
213 for _, item in ipairs(items) do |
214 if item.jid then |
214 if item.jid then |
215 n_items = n_items + 1; |
215 n_items = n_items + 1; |
216 self:disco_info(item.jid, nil, item_callback); |
216 self:disco_info(item.jid, nil, item_callback); |
217 end |
217 end |
219 if n_items == 0 then |
219 if n_items == 0 then |
220 return callback(items); |
220 return callback(items); |
221 end |
221 end |
222 end); |
222 end); |
223 end |
223 end |
224 |
224 |
225 function stream:disco_info(jid, node, callback) |
225 function stream:disco_info(jid, node, callback) |
226 local disco_request = verse.iq({ to = jid, type = "get" }) |
226 local disco_request = verse.iq({ to = jid, type = "get" }) |
227 :tag("query", { xmlns = xmlns_disco_info, node = node }); |
227 :tag("query", { xmlns = xmlns_disco_info, node = node }); |
228 self:send_iq(disco_request, function (result) |
228 self:send_iq(disco_request, function (result) |
229 if result.attr.type == "error" then |
229 if result.attr.type == "error" then |
230 return callback(nil, result:get_error()); |
230 return callback(nil, result:get_error()); |
231 end |
231 end |
232 |
232 |
233 local identities, features = {}, {}; |
233 local identities, features = {}, {}; |
234 |
234 |
235 for tag in result:get_child("query", xmlns_disco_info):childtags() do |
235 for tag in result:get_child("query", xmlns_disco_info):childtags() do |
236 if tag.name == "identity" then |
236 if tag.name == "identity" then |
237 identities[tag.attr.category.."/"..tag.attr.type] = tag.attr.name or true; |
237 identities[tag.attr.category.."/"..tag.attr.type] = tag.attr.name or true; |
238 elseif tag.name == "feature" then |
238 elseif tag.name == "feature" then |
239 features[tag.attr.var] = true; |
239 features[tag.attr.var] = true; |
240 end |
240 end |
241 end |
241 end |
242 |
242 |
243 |
243 |
244 if not self.disco.cache[jid] then |
244 if not self.disco.cache[jid] then |
245 self.disco.cache[jid] = { nodes = {} }; |
245 self.disco.cache[jid] = { nodes = {} }; |
246 end |
246 end |
247 |
247 |
256 self.disco.cache[jid].features = features; |
256 self.disco.cache[jid].features = features; |
257 end |
257 end |
258 return callback(self.disco.cache[jid]); |
258 return callback(self.disco.cache[jid]); |
259 end); |
259 end); |
260 end |
260 end |
261 |
261 |
262 function stream:disco_items(jid, node, callback) |
262 function stream:disco_items(jid, node, callback) |
263 local disco_request = verse.iq({ to = jid, type = "get" }) |
263 local disco_request = verse.iq({ to = jid, type = "get" }) |
264 :tag("query", { xmlns = xmlns_disco_items, node = node }); |
264 :tag("query", { xmlns = xmlns_disco_items, node = node }); |
265 self:send_iq(disco_request, function (result) |
265 self:send_iq(disco_request, function (result) |
266 if result.attr.type == "error" then |
266 if result.attr.type == "error" then |
274 jid = tag.attr.jid; |
274 jid = tag.attr.jid; |
275 node = tag.attr.node; |
275 node = tag.attr.node; |
276 }); |
276 }); |
277 end |
277 end |
278 end |
278 end |
279 |
279 |
280 if not self.disco.cache[jid] then |
280 if not self.disco.cache[jid] then |
281 self.disco.cache[jid] = { nodes = {} }; |
281 self.disco.cache[jid] = { nodes = {} }; |
282 end |
282 end |
283 |
283 |
284 if node then |
284 if node then |
285 if not self.disco.cache[jid].nodes[node] then |
285 if not self.disco.cache[jid].nodes[node] then |
286 self.disco.cache[jid].nodes[node] = { nodes = {} }; |
286 self.disco.cache[jid].nodes[node] = { nodes = {} }; |
287 end |
287 end |
288 self.disco.cache[jid].nodes[node].items = disco_items; |
288 self.disco.cache[jid].nodes[node].items = disco_items; |
290 self.disco.cache[jid].items = disco_items; |
290 self.disco.cache[jid].items = disco_items; |
291 end |
291 end |
292 return callback(disco_items); |
292 return callback(disco_items); |
293 end); |
293 end); |
294 end |
294 end |
295 |
295 |
296 stream:hook("iq/"..xmlns_disco_info, function (stanza) |
296 stream:hook("iq/"..xmlns_disco_info, function (stanza) |
297 local query = stanza.tags[1]; |
297 local query = stanza.tags[1]; |
298 if stanza.attr.type == 'get' and query.name == "query" then |
298 if stanza.attr.type == 'get' and query.name == "query" then |
299 local query_node = query.attr.node; |
299 local query_node = query.attr.node; |
300 local node = stream.disco.info[query_node or false]; |
300 local node = stream.disco.info[query_node or false]; |
335 end |
335 end |
336 stream:send(result); |
336 stream:send(result); |
337 return true |
337 return true |
338 end |
338 end |
339 end); |
339 end); |
340 |
340 |
341 local initial_disco_started; |
341 local initial_disco_started; |
342 stream:hook("ready", function () |
342 stream:hook("ready", function () |
343 if initial_disco_started then return; end |
343 if initial_disco_started then return; end |
344 initial_disco_started = true; |
344 initial_disco_started = true; |
345 stream:disco_local_services(function (services) |
345 stream:disco_local_services(function (services) |
356 end |
356 end |
357 stream:event("ready"); |
357 stream:event("ready"); |
358 end); |
358 end); |
359 return true; |
359 return true; |
360 end, 50); |
360 end, 50); |
361 |
361 |
362 stream:hook("presence-out", function (presence) |
362 stream:hook("presence-out", function (presence) |
363 if not presence:get_child("c", xmlns_caps) then |
363 if not presence:get_child("c", xmlns_caps) then |
364 presence:reset():add_child(stream:caps()):reset(); |
364 presence:reset():add_child(stream:caps()):reset(); |
365 end |
365 end |
366 end, 10); |
366 end, 10); |