# HG changeset patch # User Matthew Wild # Date 1530123551 -3600 # Node ID e98cef597393b6efd0af9a670e590af73b7eae7b # Parent ff59e4a1a600ea6d5100e364878a069d6a7d1664 plugins.disco: Fix to use util.caps instead of broken hacky implementation diff -r ff59e4a1a600 -r e98cef597393 plugins/disco.lua --- a/plugins/disco.lua Wed Jun 27 19:18:06 2018 +0100 +++ b/plugins/disco.lua Wed Jun 27 19:19:11 2018 +0100 @@ -9,6 +9,7 @@ local verse = require "verse"; local b64 = require("mime").b64; local sha1 = require("util.hashes").sha1; +local calculate_hash = require "util.caps".calculate_hash; local xmlns_caps = "http://jabber.org/protocol/caps"; local xmlns_disco = "http://jabber.org/protocol/disco"; @@ -54,60 +55,32 @@ stream.caps = {} stream.caps.node = 'http://code.matthewwild.co.uk/verse/' - local function cmp_identity(item1, item2) - if item1.category < item2.category then - return true; - elseif item2.category < item1.category then - return false; - end - if item1.type < item2.type then - return true; - elseif item2.type < item1.type then - return false; + local function build_self_disco_info_stanza(query_node) + local node = stream.disco.info[query_node or false]; + if query_node and query_node == stream.caps.node .. "#" .. stream.caps.hash then + node = stream.disco.info[false]; end - if (not item1['xml:lang'] and item2['xml:lang']) or - (item2['xml:lang'] and item1['xml:lang'] < item2['xml:lang']) then - return true - end - return false - end - - local function cmp_feature(item1, item2) - return item1.var < item2.var - end + local identities, features = node.identities, node.features - local function calculate_hash(node) - local identities = stream.disco.info[node or false].identities; - table.sort(identities, cmp_identity) - local features = {}; - for var in pairs(stream.disco.info[node or false].features) do - features[#features+1] = { var = var }; + -- construct the response + local result = verse.stanza("query", { + xmlns = xmlns_disco_info, + node = query_node, + }); + for _,identity in pairs(identities) do + result:tag('identity', identity):up() end - table.sort(features, cmp_feature) - local S = {}; - for key,identity in pairs(identities) do - S[#S+1] = table.concat({ - identity.category, identity.type or '', - identity['xml:lang'] or '', identity.name or '' - }, '/'); + for feature in pairs(features) do + result:tag('feature', { var = feature }):up() end - for key,feature in pairs(features) do - S[#S+1] = feature.var - end - S[#S+1] = ''; - S = table.concat(S,'<'); - -- FIXME: make sure S is utf8-encoded - --stream:debug("Computed hash string: "..S); - --stream:debug("Computed hash string (sha1): "..sha1(S, true)); - --stream:debug("Computed hash string (sha1+b64): "..b64(sha1(S))); - return (b64(sha1(S))) + return result; end setmetatable(stream.caps, { __call = function (...) -- vararg: allow calling as function or member -- retrieve the c stanza to insert into the -- presence stanza - local hash = calculate_hash() + local hash = calculate_hash(build_self_disco_info_stanza()) stream.caps.hash = hash; -- TODO proper caching.... some day return verse.stanza('c', { @@ -296,24 +269,8 @@ stream:hook("iq/"..xmlns_disco_info, function (stanza) local query = stanza.tags[1]; if stanza.attr.type == 'get' and query.name == "query" then - local query_node = query.attr.node; - local node = stream.disco.info[query_node or false]; - if query_node and query_node == stream.caps.node .. "#" .. stream.caps.hash then - node = stream.disco.info[false]; - end - local identities, features = node.identities, node.features - - -- construct the response - local result = verse.reply(stanza):tag("query", { - xmlns = xmlns_disco_info, - node = query_node, - }); - for _,identity in pairs(identities) do - result:tag('identity', identity):up() - end - for feature in pairs(features) do - result:tag('feature', { var = feature }):up() - end + local query_tag = build_self_disco_info_stanza(query.attr.node); + local result = verse.reply(stanza):add_child(query_tag); stream:send(result); return true end @@ -342,17 +299,28 @@ stream:hook("ready", function () if initial_disco_started then return; end initial_disco_started = true; + + -- Using the disco cache, fires events for each identity of a given JID + local function scan_identities_for_service(service_jid) + local service_disco_info = stream.disco.cache[service_jid]; + if service_disco_info then + for identity in pairs(service_disco_info.identities) do + local category, type = identity:match("^(.*)/(.*)$"); + print(service_jid, category, type) + stream:event("disco/service-discovered/"..category, { + type = type, jid = service_jid; + }); + end + end + end + + stream:disco_info(stream.host, nil, function () + scan_identities_for_service(stream.host); + end); + stream:disco_local_services(function (services) for _, service in ipairs(services) do - local service_disco_info = stream.disco.cache[service.jid]; - if service_disco_info then - for identity in pairs(service_disco_info.identities) do - local category, type = identity:match("^(.*)/(.*)$"); - stream:event("disco/service-discovered/"..category, { - type = type, jid = service.jid; - }); - end - end + scan_identities_for_service(service.jid); end stream:event("ready"); end);