mod_cache_c2s_caps/mod_cache_c2s_caps.lua
changeset 2903 0273d7583373
child 2905 0fb44258d2cf
equal deleted inserted replaced
2902:9fd61234b6f0 2903:0273d7583373
       
     1 local st_iq = require "util.stanza".iq;
       
     2 local jid_split = require "util.jid".split;
       
     3 local uuid_gen = require "util.uuid".generate;
       
     4 local calculate_hash = require "util.caps".calculate_hash;
       
     5 
       
     6 -- Map of jid..node, to avoid querying the same client multiple times for the same value.
       
     7 local in_flight_iqs = {}
       
     8 
       
     9 -- Some clients (*ahem* poezio…) don’t include the @node in their result iq.
       
    10 local iq_node_map = {}
       
    11 
       
    12 local function iq_result_handler(event)
       
    13 	local origin, stanza = event.origin, event.stanza;
       
    14 	local from = stanza.attr.from;
       
    15 	local id = stanza.attr.id;
       
    16 
       
    17 	local query = stanza:get_child("query", "http://jabber.org/protocol/disco#info");
       
    18 
       
    19 	local node_string = query.attr.node;
       
    20 	local node_query = iq_node_map[from..id];
       
    21 	if node_string == nil then
       
    22 		node_string = node_query;
       
    23 		query.attr.node = node_query;
       
    24 	end
       
    25 	iq_node_map[from..id] = nil;
       
    26 	in_flight_iqs[from..node_string] = nil;
       
    27 
       
    28 	if node_string ~= node_query then
       
    29 		module:log("debug", "Wrong node for our disco#info query, expected %s, received %s", node_string, node_query);
       
    30 		return;
       
    31 	end
       
    32 
       
    33 	local node, ver = node_query:match("([^#]+)#([^#]+)");
       
    34 	local hash = calculate_hash(query)
       
    35 	if ver ~= hash then
       
    36 		module:log("debug", "Wrong hash for disco#info: %s ~= %s", ver, hash);
       
    37 	end
       
    38 
       
    39 	origin.caps_cache = query;
       
    40 	module:log("info", "Stored caps %s", ver);
       
    41 	module:fire_event("c2s-capabilities-changed", { origin = origin });
       
    42 	return true;
       
    43 end
       
    44 
       
    45 local function iq_error_handler(event)
       
    46 	local origin = event.origin;
       
    47 	origin.caps_cache = nil;
       
    48 	module:fire_event("c2s-capabilities-changed", { origin = origin });
       
    49 end
       
    50 
       
    51 local function presence_stanza_handler(event)
       
    52 	local origin, stanza = event.origin, event.stanza;
       
    53 
       
    54 	local from = stanza.attr.from;
       
    55 	if stanza.attr.to ~= nil then
       
    56 		return;
       
    57 	end
       
    58 
       
    59 	local caps = stanza:get_child("c", "http://jabber.org/protocol/caps");
       
    60 	if caps == nil then
       
    61 		module:log("debug", "Presence without caps received, skipping");
       
    62 		return;
       
    63 	end
       
    64 
       
    65 	local hash = caps.attr.hash;
       
    66 	local node = caps.attr.node;
       
    67 	local ver = caps.attr.ver;
       
    68 	if not hash or not node or not ver then
       
    69 		return;
       
    70 	end
       
    71 	if hash ~= "sha-1" then
       
    72 		module:log("warn", "Non-SHA-1 caps received: %s", hash);
       
    73 		return;
       
    74 	end
       
    75 
       
    76 	local node_query = node.."#"..ver;
       
    77 	if (origin.caps_cache and origin.caps_cache.attr.node == node_query) or in_flight_iqs[from..node_query] ~= nil then
       
    78 		module:log("debug", "Already requested these caps, skipping");
       
    79 		return;
       
    80 	end
       
    81 
       
    82 	module:log("debug", "Received presence with SHA-1 caps %s, querying disco#info", node_query);
       
    83 
       
    84 	local id = uuid_gen();
       
    85 	iq_node_map[from..id] = node_query
       
    86 	local iq = st_iq({ type = "get", from = module.host, to = from, id = id })
       
    87 		:tag("query", { xmlns = "http://jabber.org/protocol/disco#info", node = node_query });
       
    88 	module:hook("iq-result/host/"..id, iq_result_handler);
       
    89 	module:hook("iq-error/host/"..id, iq_error_handler);
       
    90 	module:send(iq);
       
    91 
       
    92 	in_flight_iqs[from..node_query] = true;
       
    93 end
       
    94 
       
    95 -- Handle only non-directed presences for now.
       
    96 module:hook("pre-presence/bare", presence_stanza_handler);