1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2025-12-07 21:51:07 +01:00

[DataFormProvider] Retrieve field types from <reported/> if possible

Fixes SMACK-902.
This commit is contained in:
Florian Schmaus 2021-01-29 20:13:54 +01:00
parent 9ab50c374d
commit 070aa8e28e
3 changed files with 161 additions and 7 deletions

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2020 Florian Schmaus.
* Copyright 2003-2007 Jive Software, 2020-2021 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -538,6 +538,8 @@ public final class DataForm implements ExtensionElement {
private final List<? extends FormField> fields;
private Map<String, FormField> fieldMap;
public ReportedData(List<? extends FormField> fields) {
this.fields = Collections.unmodifiableList(fields);
}
@ -561,6 +563,18 @@ public final class DataForm implements ExtensionElement {
return fields;
}
public FormField getField(String name) {
if (fieldMap == null) {
fieldMap = new HashMap<>(fields.size());
for (FormField field : fields) {
String fieldName = field.getFieldName();
fieldMap.put(fieldName, field);
}
}
return fieldMap.get(name);
}
@Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment);

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software 2020 Florian Schmaus.
* Copyright 2003-2007 Jive Software 2020-2021 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -70,6 +70,7 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
dataForm.setType(dataFormType);
String formType = null;
DataForm.ReportedData reportedData = null;
outerloop: while (true) {
XmlPullParser.Event eventType = parser.next();
@ -86,6 +87,8 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
dataForm.setTitle(parser.nextText());
break;
case "field":
// Note that we parse this form field without any potential reportedData. We only use reportedData
// to lookup form field types of fields under <item/>.
FormField formField = parseField(parser, elementXmlEnvironment, formType);
TextSingleFormField hiddenFormTypeField = formField.asHiddenFormTypeFieldIfPossible();
@ -99,12 +102,15 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
dataForm.addField(formField);
break;
case "item":
DataForm.Item item = parseItem(parser, elementXmlEnvironment, formType);
DataForm.Item item = parseItem(parser, elementXmlEnvironment, formType, reportedData);
dataForm.addItem(item);
break;
case "reported":
DataForm.ReportedData reported = parseReported(parser, elementXmlEnvironment, formType);
dataForm.setReportedData(reported);
if (reportedData != null) {
throw new SmackParsingException("Data form with multiple <reported/> elements");
}
reportedData = parseReported(parser, elementXmlEnvironment, formType);
dataForm.setReportedData(reportedData);
break;
// See XEP-133 Example 32 for a corner case where the data form contains this extension.
case RosterPacket.ELEMENT:
@ -135,6 +141,11 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
private static FormField parseField(XmlPullParser parser, XmlEnvironment xmlEnvironment, String formType)
throws XmlPullParserException, IOException, SmackParsingException {
return parseField(parser, xmlEnvironment, formType, null);
}
private static FormField parseField(XmlPullParser parser, XmlEnvironment xmlEnvironment, String formType, DataForm.ReportedData reportedData)
throws XmlPullParserException, IOException, SmackParsingException {
final int initialDepth = parser.getDepth();
final String fieldName = parser.getAttributeValue("var");
@ -186,6 +197,16 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
}
}
// Data forms of type 'result' may contain <reported/> and <item/> elements. If this is the case, then the type
// of the <field/>s within the <item/> elements is determined by the information found in <reported/>. See
// XEP-0004 § 3.4 and SMACK-902
if (type == null && reportedData != null) {
FormField reportedFormField = reportedData.getField(fieldName);
if (reportedFormField != null) {
type = reportedFormField.getType();
}
}
if (type == null) {
// If no field type was explicitly provided, then we need to lookup the
// field's type in the registry.
@ -301,7 +322,8 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
return builder;
}
private static DataForm.Item parseItem(XmlPullParser parser, XmlEnvironment xmlEnvironment, String formType)
private static DataForm.Item parseItem(XmlPullParser parser, XmlEnvironment xmlEnvironment, String formType,
DataForm.ReportedData reportedData)
throws XmlPullParserException, IOException, SmackParsingException {
final int initialDepth = parser.getDepth();
List<FormField> fields = new ArrayList<>();
@ -312,7 +334,8 @@ public class DataFormProvider extends ExtensionElementProvider<DataForm> {
String name = parser.getName();
switch (name) {
case "field":
FormField field = parseField(parser, XmlEnvironment.from(parser, xmlEnvironment), formType);
FormField field = parseField(parser, XmlEnvironment.from(parser, xmlEnvironment), formType,
reportedData);
fields.add(field);
break;
}