diff mod_delegation/mod_delegation.lua @ 1716:29dfdfc767b4

mod_delegation: service discovery extensions (xep-0128) management
author Goffi <goffi@goffi.org>
date Sat, 18 Apr 2015 00:13:09 +0200
parents 241c061bb953
children e22cd2205fc1
line wrap: on
line diff
--- a/mod_delegation/mod_delegation.lua	Fri Apr 17 21:22:35 2015 +0200
+++ b/mod_delegation/mod_delegation.lua	Sat Apr 18 00:13:09 2015 +0200
@@ -26,6 +26,7 @@
 local _DELEGATION_NS = 'urn:xmpp:delegation:1'
 local _FORWARDED_NS = 'urn:xmpp:forward:0'
 local _DISCO_NS = 'http://jabber.org/protocol/disco#info'
+local _DATA_NS = 'jabber:x:data'
 local _ORI_ID_PREFIX = "IQ_RESULT_"
 
 local _MAIN_SEP = '::'
@@ -259,6 +260,21 @@
 
 -- disabling internal features/identities
 
+local function find_form_type(stanza)
+	local form_type = nil
+	for field in stanza.childtags('field', 'jabber:x:data') do
+		if field.attr.var=='FORM_TYPE' and field.attr.type=='hidden' then
+			local value = field:get_child('value')
+			if not value then
+				module:log("warn", "No value found in FORM_TYPE field: "..tostring(stanza))
+			else
+				form_type=value.get_text()
+			end
+		end
+	end
+	return form_type
+end
+
 -- modules whose features/identities are managed by delegation
 local disabled_modules = set.new()
 local disabled_identities = set.new()
@@ -294,11 +310,25 @@
 	end
 end
 
+local function extension_added(event)
+	local source, stanza = event.source, event.item
+	local form_type = find_form_type(stanza)
+	if not form_type then return; end
+
+	for namespace, _ in pairs(ns_delegations) do
+		if source ~= module and string.sub(form_type, 1, #namespace) == namespace then
+			module:log("debug", "Removing extension which is delegated: %s", tostring(stanza))
+			source:remove_item("extension", stanza)
+		end
+	end
+end
+
 -- for disco nesting (see ยง 7.2) we need to remove internal features
 -- we use handle_items as it allow to remove already added features
 -- and catch the ones which can come later
 module:handle_items("feature", feature_added, function(_) end)
 module:handle_items("identity", identity_added, function(_) end, false)
+module:handle_items("extension", extension_added, function(_) end)
 
 
 -- managing entity features/identities collection
@@ -306,6 +336,7 @@
 local disco_error
 local bare_features = set.new()
 local bare_identities = {}
+local bare_extensions = {}
 
 local function disco_result(event)
 	-- parse result from disco nesting request
@@ -365,6 +396,13 @@
 			end
 		end
 	end
+	for extension in query:childtags("x", _DATA_NS) do
+		if main then
+			module:add_extension(extension)
+		else
+			table.insert(bare_extensions, extension)
+		end
+	end
 end
 
 function disco_error(event)
@@ -398,7 +436,7 @@
 
 module:hook("account-disco-info", function(event)
 	-- this event is called when a disco info request is done on a bare jid
-	-- we get the final reply and filter delegated features/identities
+	-- we get the final reply and filter delegated features/identities/extensions
 	local reply = event.reply;
 	reply.tags[1]:maptags(function(child)
 		if child.name == 'feature' then
@@ -420,14 +458,28 @@
 					return nil
 				end
 			end
+		elseif child.name == 'x' and child.attr.xmlns == _DATA_NS then
+			local form_type = find_form_type(child)
+			if form_type then
+				for namespace, _ in pairs(ns_delegations) do
+					if string.sub(form_type, 1, #namespace) == namespace then
+						module:log("debug", "Removing extension which is delegated: %s", tostring(child))
+						return nil
+					end
+				end
+			end
+
 		end
 		return child
 	end)
 	for feature in bare_features:items() do
-		reply:tag('feature', {var=feature}):up();
+		reply:tag('feature', {var=feature}):up()
 	end
 	for _, item in ipairs(bare_identities) do
-		reply:tag('identity', {category=item.category, type=item.type, name=item.name}):up();
+		reply:tag('identity', {category=item.category, type=item.type, name=item.name}):up()
+	end
+	for _, stanza in ipairs(bare_extensions) do
+		reply:add_child(stanza)
 	end
 
 end, -2^32);