Software /
code /
verse
Comparison
plugins/disco.lua @ 423:e98cef597393
plugins.disco: Fix to use util.caps instead of broken hacky implementation
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 27 Jun 2018 19:19:11 +0100 (2018-06-27) |
parent | 392:cdea6a28369e |
child | 429:46897d7769c3 |
comparison
equal
deleted
inserted
replaced
422:ff59e4a1a600 | 423:e98cef597393 |
---|---|
7 -- | 7 -- |
8 | 8 |
9 local verse = require "verse"; | 9 local verse = require "verse"; |
10 local b64 = require("mime").b64; | 10 local b64 = require("mime").b64; |
11 local sha1 = require("util.hashes").sha1; | 11 local sha1 = require("util.hashes").sha1; |
12 local calculate_hash = require "util.caps".calculate_hash; | |
12 | 13 |
13 local xmlns_caps = "http://jabber.org/protocol/caps"; | 14 local xmlns_caps = "http://jabber.org/protocol/caps"; |
14 local xmlns_disco = "http://jabber.org/protocol/disco"; | 15 local xmlns_disco = "http://jabber.org/protocol/disco"; |
15 local xmlns_disco_info = xmlns_disco.."#info"; | 16 local xmlns_disco_info = xmlns_disco.."#info"; |
16 local xmlns_disco_items = xmlns_disco.."#items"; | 17 local xmlns_disco_items = xmlns_disco.."#items"; |
52 }; | 53 }; |
53 | 54 |
54 stream.caps = {} | 55 stream.caps = {} |
55 stream.caps.node = 'http://code.matthewwild.co.uk/verse/' | 56 stream.caps.node = 'http://code.matthewwild.co.uk/verse/' |
56 | 57 |
57 local function cmp_identity(item1, item2) | 58 local function build_self_disco_info_stanza(query_node) |
58 if item1.category < item2.category then | 59 local node = stream.disco.info[query_node or false]; |
59 return true; | 60 if query_node and query_node == stream.caps.node .. "#" .. stream.caps.hash then |
60 elseif item2.category < item1.category then | 61 node = stream.disco.info[false]; |
61 return false; | 62 end |
62 end | 63 local identities, features = node.identities, node.features |
63 if item1.type < item2.type then | 64 |
64 return true; | 65 -- construct the response |
65 elseif item2.type < item1.type then | 66 local result = verse.stanza("query", { |
66 return false; | 67 xmlns = xmlns_disco_info, |
67 end | 68 node = query_node, |
68 if (not item1['xml:lang'] and item2['xml:lang']) or | 69 }); |
69 (item2['xml:lang'] and item1['xml:lang'] < item2['xml:lang']) then | 70 for _,identity in pairs(identities) do |
70 return true | 71 result:tag('identity', identity):up() |
71 end | 72 end |
72 return false | 73 for feature in pairs(features) do |
73 end | 74 result:tag('feature', { var = feature }):up() |
74 | 75 end |
75 local function cmp_feature(item1, item2) | 76 return result; |
76 return item1.var < item2.var | |
77 end | |
78 | |
79 local function calculate_hash(node) | |
80 local identities = stream.disco.info[node or false].identities; | |
81 table.sort(identities, cmp_identity) | |
82 local features = {}; | |
83 for var in pairs(stream.disco.info[node or false].features) do | |
84 features[#features+1] = { var = var }; | |
85 end | |
86 table.sort(features, cmp_feature) | |
87 local S = {}; | |
88 for key,identity in pairs(identities) do | |
89 S[#S+1] = table.concat({ | |
90 identity.category, identity.type or '', | |
91 identity['xml:lang'] or '', identity.name or '' | |
92 }, '/'); | |
93 end | |
94 for key,feature in pairs(features) do | |
95 S[#S+1] = feature.var | |
96 end | |
97 S[#S+1] = ''; | |
98 S = table.concat(S,'<'); | |
99 -- FIXME: make sure S is utf8-encoded | |
100 --stream:debug("Computed hash string: "..S); | |
101 --stream:debug("Computed hash string (sha1): "..sha1(S, true)); | |
102 --stream:debug("Computed hash string (sha1+b64): "..b64(sha1(S))); | |
103 return (b64(sha1(S))) | |
104 end | 77 end |
105 | 78 |
106 setmetatable(stream.caps, { | 79 setmetatable(stream.caps, { |
107 __call = function (...) -- vararg: allow calling as function or member | 80 __call = function (...) -- vararg: allow calling as function or member |
108 -- retrieve the c stanza to insert into the | 81 -- retrieve the c stanza to insert into the |
109 -- presence stanza | 82 -- presence stanza |
110 local hash = calculate_hash() | 83 local hash = calculate_hash(build_self_disco_info_stanza()) |
111 stream.caps.hash = hash; | 84 stream.caps.hash = hash; |
112 -- TODO proper caching.... some day | 85 -- TODO proper caching.... some day |
113 return verse.stanza('c', { | 86 return verse.stanza('c', { |
114 xmlns = xmlns_caps, | 87 xmlns = xmlns_caps, |
115 hash = 'sha-1', | 88 hash = 'sha-1', |
294 end | 267 end |
295 | 268 |
296 stream:hook("iq/"..xmlns_disco_info, function (stanza) | 269 stream:hook("iq/"..xmlns_disco_info, function (stanza) |
297 local query = stanza.tags[1]; | 270 local query = stanza.tags[1]; |
298 if stanza.attr.type == 'get' and query.name == "query" then | 271 if stanza.attr.type == 'get' and query.name == "query" then |
299 local query_node = query.attr.node; | 272 local query_tag = build_self_disco_info_stanza(query.attr.node); |
300 local node = stream.disco.info[query_node or false]; | 273 local result = verse.reply(stanza):add_child(query_tag); |
301 if query_node and query_node == stream.caps.node .. "#" .. stream.caps.hash then | |
302 node = stream.disco.info[false]; | |
303 end | |
304 local identities, features = node.identities, node.features | |
305 | |
306 -- construct the response | |
307 local result = verse.reply(stanza):tag("query", { | |
308 xmlns = xmlns_disco_info, | |
309 node = query_node, | |
310 }); | |
311 for _,identity in pairs(identities) do | |
312 result:tag('identity', identity):up() | |
313 end | |
314 for feature in pairs(features) do | |
315 result:tag('feature', { var = feature }):up() | |
316 end | |
317 stream:send(result); | 274 stream:send(result); |
318 return true | 275 return true |
319 end | 276 end |
320 end); | 277 end); |
321 | 278 |
340 | 297 |
341 local initial_disco_started; | 298 local initial_disco_started; |
342 stream:hook("ready", function () | 299 stream:hook("ready", function () |
343 if initial_disco_started then return; end | 300 if initial_disco_started then return; end |
344 initial_disco_started = true; | 301 initial_disco_started = true; |
302 | |
303 -- Using the disco cache, fires events for each identity of a given JID | |
304 local function scan_identities_for_service(service_jid) | |
305 local service_disco_info = stream.disco.cache[service_jid]; | |
306 if service_disco_info then | |
307 for identity in pairs(service_disco_info.identities) do | |
308 local category, type = identity:match("^(.*)/(.*)$"); | |
309 print(service_jid, category, type) | |
310 stream:event("disco/service-discovered/"..category, { | |
311 type = type, jid = service_jid; | |
312 }); | |
313 end | |
314 end | |
315 end | |
316 | |
317 stream:disco_info(stream.host, nil, function () | |
318 scan_identities_for_service(stream.host); | |
319 end); | |
320 | |
345 stream:disco_local_services(function (services) | 321 stream:disco_local_services(function (services) |
346 for _, service in ipairs(services) do | 322 for _, service in ipairs(services) do |
347 local service_disco_info = stream.disco.cache[service.jid]; | 323 scan_identities_for_service(service.jid); |
348 if service_disco_info then | |
349 for identity in pairs(service_disco_info.identities) do | |
350 local category, type = identity:match("^(.*)/(.*)$"); | |
351 stream:event("disco/service-discovered/"..category, { | |
352 type = type, jid = service.jid; | |
353 }); | |
354 end | |
355 end | |
356 end | 324 end |
357 stream:event("ready"); | 325 stream:event("ready"); |
358 end); | 326 end); |
359 return true; | 327 return true; |
360 end, 50); | 328 end, 50); |