mod_rest: Add JSON mapping of XEP-0128: Service Discovery Extensions
Example XEP-0157 payload:
{
"disco" : {
"extensions" : {
"http://jabber.org/network/serverinfo" : {
"abuse-addresses" : [
"mailto:abuse@shakespeare.lit",
"xmpp:abuse@shakespeare.lit"
],
"admin-addresses" : [
"mailto:admin@shakespeare.lit",
"xmpp:admin@shakespeare.lit"
],
"feedback-addresses" : [
"http://shakespeare.lit/feedback.php",
"mailto:feedback@shakespeare.lit",
"xmpp:feedback@shakespeare.lit"
],
"sales-addresses" : [
"xmpp:bard@shakespeare.lit"
],
"security-addresses" : [
"xmpp:security@shakespeare.lit"
],
"support-addresses" : [
"http://shakespeare.lit/support.php",
"xmpp:support@shakespeare.lit"
]
}
}
}
}
--- a/mod_rest/README.markdown Sat Mar 21 18:05:22 2020 +0100
+++ b/mod_rest/README.markdown Mon Mar 23 19:03:04 2020 +0100
@@ -375,6 +375,11 @@
items list query. The response contain an array of items like
`{"jid":"xmpp.address.here","name":"Description of item"}`.
+`extensions`
+: Map of extended feature discovery (see [XEP-0128]) data with
+ `FORM_DATA` fields as the keys pointing at maps with the rest of the
+ data.
+
#### Ad-Hoc Commands
Used to execute arbitrary commands on supporting entities.
--- a/mod_rest/jsonmap.lib.lua Sat Mar 21 18:05:22 2020 +0100
+++ b/mod_rest/jsonmap.lib.lua Mon Mar 23 19:03:04 2020 +0100
@@ -75,7 +75,7 @@
disco = {
type = "func", xmlns = "http://jabber.org/protocol/disco#info", tagname = "query",
st2json = function (s) --> array of features
- local identities, features = array(), array();
+ local identities, features, extensions = array(), array(), {};
for tag in s:childtags() do
if tag.name == "identity" and tag.attr.category and tag.attr.type then
identities:push({ category = tag.attr.category, type = tag.attr.type, name = tag.attr.name });
@@ -83,7 +83,16 @@
features:push(tag.attr.var);
end
end
- return { node = s.attr.node, identities = identities, features = features, };
+ for form in s:childtags("x", "jabber:x:data") do
+ local jform = field_mappings.formdata.st2json(form);
+ local form_type = jform["FORM_TYPE"];
+ if jform then
+ jform["FORM_TYPE"] = nil;
+ extensions[form_type] = jform;
+ end
+ end
+ if next(extensions) == nil then extensions = nil; end
+ return { node = s.attr.node, identities = identities, features = features, extensions = extensions };
end;
json2st = function (s)
if type(s) == "table" and s ~= json.null then
@@ -98,6 +107,12 @@
disco:tag("feature", { var = feature }):up();
end
end
+ if s.extensions then
+ for form_type, extension in pairs(s.extensions) do
+ extension["FORM_TYPE"] = form_type;
+ disco:add_child(field_mappings.formdata.json2st(extension));
+ end
+ end
return disco;
else
return st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info", });
@@ -324,10 +339,28 @@
-- Simpler mapping of dataform from JSON map
formdata = { type = "func", xmlns = "jabber:x:data", tagname = "",
- st2json = function ()
- -- Tricky to do in a generic way without each form layout
- -- In the future, some well-known layouts might be understood
- return nil, "not-implemented";
+ st2json = function (s)
+ local r = {};
+ for field in s:childtags("field") do
+ if field.attr.var then
+ local values = array();
+ for value in field:childtags("value") do
+ values:push(value:get_text());
+ end
+ if field.attr.type == "list-single" or field.attr.type == "list-multi" then
+ r[field.attr.var] = values;
+ elseif field.attr.type == "text-multi" then
+ r[field.attr.var] = values:concat("\n");
+ elseif field.attr.type == "boolean" then
+ r[field.attr.var] = values[1] == "1" or values[1] == "true";
+ elseif field.attr.type then
+ r[field.attr.var] = values[1] or json.null;
+ else -- type is optional, no way to know if multiple or single value is expected
+ r[field.attr.var] = values;
+ end
+ end
+ end
+ return r;
end,
json2st = function (s, t)
local form = st.stanza("x", { xmlns = "jabber:x:data", type = t });