mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-09-19 06:09:32 +02:00
Re-work data form API
Apply builder pattern to form fields and replace getVariable() with getFieldName(). Refer to the field name as "field name" instead of "variable" everyone, just as XEP-0004 does. Improve the high-level form API: introduce FilledForm and FillableForm which perform stronger validation and consistency checks. Also add FormFieldRegistry to enable processing of 'submit' forms where the form field types are omitted. Smack also now does omit the form field type declaration on 'submit' type forms, as it is allowed by XEP-0004.
This commit is contained in:
parent
3270c113c5
commit
77e26fc575
|
@ -51,6 +51,7 @@ Smack Extensions and currently supported XEPs of smack-extensions
|
|||
| Result Set Management | [XEP-0059](https://xmpp.org/extensions/xep-0059.html) | n/a | Page through and otherwise manage the receipt of large result sets |
|
||||
| [PubSub](pubsub.md) | [XEP-0060](https://xmpp.org/extensions/xep-0060.html) | n/a | Generic publish and subscribe functionality. |
|
||||
| SOCKS5 Bytestreams | [XEP-0065](https://xmpp.org/extensions/xep-0065.html) | n/a | Out-of-band bytestream between any two XMPP entities. |
|
||||
| Field Standardization for Data Forms | [XEP-0068](https://xmpp.org/extensions/xep-0068.html) | n/a | Standardized field variables used in the context of jabber:x:data forms. |
|
||||
| [XHTML-IM](xhtml.md) | [XEP-0071](https://xmpp.org/extensions/xep-0071.html) | n/a | Allows send and receiving formatted messages using XHTML. |
|
||||
| In-Band Registration | [XEP-0077](https://xmpp.org/extensions/xep-0077.html) | n/a | In-band registration with XMPP services. |
|
||||
| Advanced Message Processing | [XEP-0079](https://xmpp.org/extensions/xep-0079.html) | n/a | Enables entities to request, and servers to perform, advanced processing of XMPP message stanzas. |
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2019 Florian Schmaus
|
||||
* Copyright 2019-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,6 +30,10 @@ public class SmackParsingException extends Exception {
|
|||
super(exception);
|
||||
}
|
||||
|
||||
public SmackParsingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public static class SmackTextParseException extends SmackParsingException {
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -18,9 +18,12 @@ package org.jivesoftware.smack.util;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CollectionUtil {
|
||||
|
@ -59,6 +62,20 @@ public class CollectionUtil {
|
|||
return new ArrayList<>(collection);
|
||||
}
|
||||
|
||||
public static <T> List<T> cloneAndSeal(Collection<? extends T> collection) {
|
||||
if (collection == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ArrayList<T> clone = newListWith(collection);
|
||||
return Collections.unmodifiableList(clone);
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> cloneAndSeal(Map<K, V> map) {
|
||||
Map<K, V> clone = new HashMap<>(map);
|
||||
return Collections.unmodifiableMap(clone);
|
||||
}
|
||||
|
||||
public static <T> Set<T> newSetWith(Collection<? extends T> collection) {
|
||||
if (collection == null) {
|
||||
return null;
|
||||
|
|
|
@ -20,8 +20,10 @@ package org.jivesoftware.smack.util;
|
|||
import java.io.IOException;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -591,4 +593,11 @@ public class StringUtils {
|
|||
}
|
||||
return appendable.append('\n');
|
||||
}
|
||||
|
||||
public static final String PORTABLE_NEWLINE_REGEX = "\\r?\\n";
|
||||
|
||||
public static List<String> splitLinesPortable(String input) {
|
||||
String[] lines = input.split(PORTABLE_NEWLINE_REGEX);
|
||||
return Arrays.asList(lines);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,10 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
|
|||
.build();
|
||||
}
|
||||
|
||||
public XmlEnvironment getXmlEnvironment() {
|
||||
return effectiveXmlEnvironment;
|
||||
}
|
||||
|
||||
public XmlStringBuilder escapedElement(String name, String escapedContent) {
|
||||
assert escapedContent != null;
|
||||
openElement(name);
|
||||
|
@ -493,6 +497,13 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
|
|||
return this;
|
||||
}
|
||||
|
||||
public XmlStringBuilder optAppend(Collection<? extends Element> elements) {
|
||||
if (elements != null) {
|
||||
append(elements);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public XmlStringBuilder optTextChild(CharSequence sqc, NamedElement parentElement) {
|
||||
if (sqc == null) {
|
||||
return closeEmptyElement();
|
||||
|
|
|
@ -278,8 +278,9 @@ public final class MamManager extends Manager {
|
|||
if (dataForm != null) {
|
||||
return dataForm;
|
||||
}
|
||||
dataForm = getNewMamForm();
|
||||
dataForm.addFields(formFields.values());
|
||||
DataForm.Builder dataFormBuilder = getNewMamForm();
|
||||
dataFormBuilder.addFields(formFields.values());
|
||||
dataForm = dataFormBuilder.build();
|
||||
return dataForm;
|
||||
}
|
||||
|
||||
|
@ -330,7 +331,7 @@ public final class MamManager extends Manager {
|
|||
}
|
||||
|
||||
FormField formField = getWithFormField(withJid);
|
||||
formFields.put(formField.getVariable(), formField);
|
||||
formFields.put(formField.getFieldName(), formField);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -341,9 +342,9 @@ public final class MamManager extends Manager {
|
|||
}
|
||||
|
||||
FormField formField = FormField.builder(FORM_FIELD_START)
|
||||
.addValue(start)
|
||||
.setValue(start)
|
||||
.build();
|
||||
formFields.put(formField.getVariable(), formField);
|
||||
formFields.put(formField.getFieldName(), formField);
|
||||
|
||||
FormField endFormField = formFields.get(FORM_FIELD_END);
|
||||
if (endFormField != null) {
|
||||
|
@ -369,9 +370,9 @@ public final class MamManager extends Manager {
|
|||
}
|
||||
|
||||
FormField formField = FormField.builder(FORM_FIELD_END)
|
||||
.addValue(end)
|
||||
.setValue(end)
|
||||
.build();
|
||||
formFields.put(formField.getVariable(), formField);
|
||||
formFields.put(formField.getFieldName(), formField);
|
||||
|
||||
FormField startFormField = formFields.get(FORM_FIELD_START);
|
||||
if (startFormField != null) {
|
||||
|
@ -418,7 +419,7 @@ public final class MamManager extends Manager {
|
|||
}
|
||||
|
||||
public Builder withAdditionalFormField(FormField formField) {
|
||||
formFields.put(formField.getVariable(), formField);
|
||||
formFields.put(formField.getFieldName(), formField);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -483,7 +484,7 @@ public final class MamManager extends Manager {
|
|||
|
||||
private static FormField getWithFormField(Jid withJid) {
|
||||
return FormField.builder(FORM_FIELD_WITH)
|
||||
.addValue(withJid.toString())
|
||||
.setValue(withJid.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -718,9 +719,9 @@ public final class MamManager extends Manager {
|
|||
throw new SmackException.FeatureNotSupportedException(ADVANCED_CONFIG_NODE, archiveAddress);
|
||||
}
|
||||
|
||||
private static DataForm getNewMamForm() {
|
||||
FormField field = FormField.hiddenFormType(MamElements.NAMESPACE);
|
||||
DataForm form = new DataForm(DataForm.Type.submit);
|
||||
private static DataForm.Builder getNewMamForm() {
|
||||
FormField field = FormField.buildHiddenFormType(MamElements.NAMESPACE);
|
||||
DataForm.Builder form = DataForm.builder();
|
||||
form.addField(field);
|
||||
return form;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.jivesoftware.smack.packet.IQ;
|
|||
|
||||
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.TextSingleFormField;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
@ -98,24 +99,23 @@ public class EnablePushNotificationsIQ extends IQ {
|
|||
xml.rightAngleBracket();
|
||||
|
||||
if (publishOptions != null) {
|
||||
DataForm dataForm = new DataForm(DataForm.Type.submit);
|
||||
DataForm.Builder dataForm = DataForm.builder();
|
||||
|
||||
// TODO: Shouldn't this use some potentially existing PubSub API? Also FORM_TYPE fields are usually of type
|
||||
// 'hidden', but the examples in XEP-0357 do also not set the value to hidden and FORM_TYPE itself appears
|
||||
// to be more convention than specification.
|
||||
FormField.Builder formTypeField = FormField.builder("FORM_TYPE");
|
||||
formTypeField.addValue(PubSub.NAMESPACE + "#publish-options");
|
||||
dataForm.addField(formTypeField.build());
|
||||
FormField formTypeField = FormField.buildHiddenFormType(PubSub.NAMESPACE + "#publish-options");
|
||||
dataForm.addField(formTypeField);
|
||||
|
||||
Iterator<Map.Entry<String, String>> publishOptionsIterator = publishOptions.entrySet().iterator();
|
||||
while (publishOptionsIterator.hasNext()) {
|
||||
Map.Entry<String, String> pairVariableValue = publishOptionsIterator.next();
|
||||
FormField.Builder field = FormField.builder(pairVariableValue.getKey());
|
||||
field.addValue(pairVariableValue.getValue());
|
||||
TextSingleFormField.Builder field = FormField.builder(pairVariableValue.getKey());
|
||||
field.setValue(pairVariableValue.getValue());
|
||||
dataForm.addField(field.build());
|
||||
}
|
||||
|
||||
xml.append(dataForm);
|
||||
xml.append(dataForm.build());
|
||||
}
|
||||
|
||||
return xml;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -34,7 +34,7 @@ import org.jxmpp.util.XmppDateTime;
|
|||
public class FiltersTest extends MamTest {
|
||||
|
||||
private static String getMamXMemberWith(List<String> fieldsNames, List<? extends CharSequence> fieldsValues) {
|
||||
String xml = "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>" + "<value>"
|
||||
String xml = "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE'>" + "<value>"
|
||||
+ MamElements.NAMESPACE + "</value>" + "</field>";
|
||||
|
||||
for (int i = 0; i < fieldsNames.size() && i < fieldsValues.size(); i++) {
|
||||
|
|
|
@ -85,7 +85,7 @@ public class MamQueryIQProviderTest {
|
|||
assertEquals(fields2.get(1).getType(), FormField.Type.jid_single);
|
||||
assertEquals(fields2.get(2).getType(), FormField.Type.text_single);
|
||||
assertEquals(fields2.get(2).getValues(), new ArrayList<>());
|
||||
assertEquals(fields2.get(4).getVariable(), "urn:example:xmpp:free-text-search");
|
||||
assertEquals(fields2.get(4).getFieldName(), "urn:example:xmpp:free-text-search");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,8 @@ public class MamTest extends SmackTestSuite {
|
|||
IllegalArgumentException, InvocationTargetException {
|
||||
Method methodGetNewMamForm = MamManager.class.getDeclaredMethod("getNewMamForm");
|
||||
methodGetNewMamForm.setAccessible(true);
|
||||
return (DataForm) methodGetNewMamForm.invoke(mamManager);
|
||||
DataForm.Builder dataFormBuilder = (DataForm.Builder) methodGetNewMamForm.invoke(mamManager);
|
||||
return dataFormBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||
public class PagingTest extends MamTest {
|
||||
|
||||
private static final String pagingStanza = "<iq id='sarasa' type='set'>" + "<query xmlns='urn:xmpp:mam:1' queryid='testid'>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE'>"
|
||||
+ "<value>urn:xmpp:mam:1</value>" + "</field>" + "</x>" + "<set xmlns='http://jabber.org/protocol/rsm'>"
|
||||
+ "<max>10</max>" + "</set>" + "</query>" + "</iq>";
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.jxmpp.jid.impl.JidCreate;
|
|||
public class QueryArchiveTest extends MamTest {
|
||||
|
||||
private static final String mamSimpleQueryIQ = "<iq id='sarasa' type='set'>" + "<query xmlns='urn:xmpp:mam:1' queryid='testid'>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>" + "<value>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE'>" + "<value>"
|
||||
+ MamElements.NAMESPACE + "</value>" + "</field>" + "</x>" + "</query>" + "</iq>";
|
||||
|
||||
private static final String mamQueryResultExample = "<message to='hag66@shakespeare.lit/pda' from='coven@chat.shakespeare.lit' id='iasd207'>"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2019 Florian Schmaus
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test;
|
|||
public class ResultsLimitTest extends MamTest {
|
||||
|
||||
private static final String resultsLimitStanza = "<iq id='sarasa' type='set'>" + "<query xmlns='urn:xmpp:mam:1' queryid='testid'>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>" + "<value>"
|
||||
+ "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE'>" + "<value>"
|
||||
+ MamElements.NAMESPACE + "</value>" + "</field>" + "</x>" + "<set xmlns='http://jabber.org/protocol/rsm'>"
|
||||
+ "<max>10</max>" + "</set>" + "</query>" + "</iq>";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2019 Florian Schmaus
|
||||
* Copyright 2016 Fernando Ramirez, 2018-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,16 +28,17 @@ import org.jivesoftware.smackx.xdata.FormField;
|
|||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.jxmpp.jid.JidTestUtil;
|
||||
|
||||
public class RetrieveFormFieldsTest extends MamTest {
|
||||
|
||||
private static final String retrieveFormFieldStanza = "<iq id='sarasa' type='get'>" + "<query xmlns='" + MamElements.NAMESPACE
|
||||
+ "' queryid='testid'></query>" + "</iq>";
|
||||
|
||||
private static final String additionalFieldsStanza = "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>"
|
||||
private static final String additionalFieldsStanza = "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE'>"
|
||||
+ "<value>" + MamElements.NAMESPACE + "</value>" + "</field>"
|
||||
+ "<field var='urn:example:xmpp:free-text-search'>" + "<value>Hi</value>" + "</field>"
|
||||
+ "<field var='urn:example:xmpp:stanza-content' type='jid-single'>" + "<value>Hi2</value>" + "</field>"
|
||||
+ "<field var='urn:example:xmpp:stanza-content'>" + "<value>one@exampleone.org</value>" + "</field>"
|
||||
+ "</x>";
|
||||
|
||||
@Test
|
||||
|
@ -51,13 +52,11 @@ public class RetrieveFormFieldsTest extends MamTest {
|
|||
@Test
|
||||
public void checkAddAdditionalFieldsStanza() throws Exception {
|
||||
FormField field1 = FormField.builder("urn:example:xmpp:free-text-search")
|
||||
.setType(FormField.Type.text_single)
|
||||
.addValue("Hi")
|
||||
.setValue("Hi")
|
||||
.build();
|
||||
|
||||
FormField field2 = FormField.builder("urn:example:xmpp:stanza-content")
|
||||
.setType(FormField.Type.jid_single)
|
||||
.addValue("Hi2")
|
||||
FormField field2 = FormField.jidSingleBuilder("urn:example:xmpp:stanza-content")
|
||||
.setValue(JidTestUtil.BARE_JID_1)
|
||||
.build();
|
||||
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016-2019 Florian Schmaus
|
||||
* Copyright 2016-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,7 +29,7 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
|||
|
||||
import org.jivesoftware.smackx.commands.AdHocCommandManager;
|
||||
import org.jivesoftware.smackx.commands.RemoteCommand;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
@ -72,7 +72,7 @@ public class ServiceAdministrationManager extends Manager {
|
|||
RemoteCommand command = addUser();
|
||||
command.execute();
|
||||
|
||||
Form answerForm = command.getForm().createAnswerForm();
|
||||
FillableForm answerForm = new FillableForm(command.getForm());
|
||||
|
||||
answerForm.setAnswer("accountjid", userJid);
|
||||
answerForm.setAnswer("password", password);
|
||||
|
@ -101,7 +101,7 @@ public class ServiceAdministrationManager extends Manager {
|
|||
RemoteCommand command = deleteUser();
|
||||
command.execute();
|
||||
|
||||
Form answerForm = command.getForm().createAnswerForm();
|
||||
FillableForm answerForm = new FillableForm(command.getForm());
|
||||
|
||||
answerForm.setAnswer("accountjids", jidsToDelete);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2009 Jonas Ådahl, 2011-2019 Florian Schmaus
|
||||
* Copyright © 2009 Jonas Ådahl, 2011-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,11 +22,13 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.WeakHashMap;
|
||||
|
@ -49,7 +51,6 @@ import org.jivesoftware.smack.filter.PresenceTypeFilter;
|
|||
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
|
||||
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.PresenceBuilder;
|
||||
|
@ -601,7 +602,7 @@ public final class EntityCapsManager extends Manager {
|
|||
return false;
|
||||
|
||||
// step 3.5 check for well-formed packet extensions
|
||||
if (verifyPacketExtensions(info))
|
||||
if (!verifyPacketExtensions(info))
|
||||
return false;
|
||||
|
||||
String calculatedVer = generateVerificationString(info, hash).version;
|
||||
|
@ -613,27 +614,29 @@ public final class EntityCapsManager extends Manager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Verify that the given discovery info is not ill-formed.
|
||||
*
|
||||
* @param info TODO javadoc me please
|
||||
* @return true if the stanza extensions is ill-formed
|
||||
* @param info the discovery info to verify.
|
||||
* @return true if the stanza extensions is not ill-formed
|
||||
*/
|
||||
protected static boolean verifyPacketExtensions(DiscoverInfo info) {
|
||||
List<FormField> foundFormTypes = new LinkedList<>();
|
||||
for (ExtensionElement pe : info.getExtensions()) {
|
||||
if (pe.getNamespace().equals(DataForm.NAMESPACE)) {
|
||||
DataForm df = (DataForm) pe;
|
||||
for (FormField f : df.getFields()) {
|
||||
if (f.getVariable().equals("FORM_TYPE")) {
|
||||
for (FormField fft : foundFormTypes) {
|
||||
if (f.equals(fft))
|
||||
return true;
|
||||
}
|
||||
foundFormTypes.add(f);
|
||||
}
|
||||
}
|
||||
private static boolean verifyPacketExtensions(DiscoverInfo info) {
|
||||
Set<String> foundFormTypes = new HashSet<>();
|
||||
List<DataForm> dataForms = info.getExtensions(DataForm.class);
|
||||
for (DataForm dataForm : dataForms) {
|
||||
FormField formFieldTypeField = dataForm.getHiddenFormTypeField();
|
||||
if (formFieldTypeField == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String type = formFieldTypeField.getFirstValue();
|
||||
boolean noDuplicate = foundFormTypes.add(type);
|
||||
if (!noDuplicate) {
|
||||
// Ill-formed extension: duplicate forms (by form field type string).
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static CapsVersionAndHash generateVerificationString(DiscoverInfoView discoverInfo) {
|
||||
|
@ -718,12 +721,12 @@ public final class EntityCapsManager extends Manager {
|
|||
SortedSet<FormField> fs = new TreeSet<>(new Comparator<FormField>() {
|
||||
@Override
|
||||
public int compare(FormField f1, FormField f2) {
|
||||
return f1.getVariable().compareTo(f2.getVariable());
|
||||
return f1.getFieldName().compareTo(f2.getFieldName());
|
||||
}
|
||||
});
|
||||
|
||||
for (FormField f : extendedInfo.getFields()) {
|
||||
if (!f.getVariable().equals("FORM_TYPE")) {
|
||||
if (!f.getFieldName().equals("FORM_TYPE")) {
|
||||
fs.add(f);
|
||||
}
|
||||
}
|
||||
|
@ -739,7 +742,7 @@ public final class EntityCapsManager extends Manager {
|
|||
// 3. For each <value/> element, append the XML character data,
|
||||
// followed by the '<' character.
|
||||
for (FormField f : fs) {
|
||||
sb.append(f.getVariable());
|
||||
sb.append(f.getFieldName());
|
||||
sb.append('<');
|
||||
formFieldValuesToCaps(f.getValues(), sb);
|
||||
}
|
||||
|
@ -763,7 +766,7 @@ public final class EntityCapsManager extends Manager {
|
|||
return new CapsVersionAndHash(version, hash);
|
||||
}
|
||||
|
||||
private static void formFieldValuesToCaps(List<CharSequence> i, StringBuilder sb) {
|
||||
private static void formFieldValuesToCaps(List<? extends CharSequence> i, StringBuilder sb) {
|
||||
SortedSet<CharSequence> fvs = new TreeSet<>();
|
||||
fvs.addAll(i);
|
||||
for (CharSequence fv : fvs) {
|
||||
|
|
|
@ -24,7 +24,8 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
|||
import org.jivesoftware.smack.packet.StanzaError;
|
||||
|
||||
import org.jivesoftware.smackx.commands.packet.AdHocCommandData;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
@ -188,13 +189,8 @@ public abstract class AdHocCommand {
|
|||
* @return the form of the current stage to fill out or the result of the
|
||||
* execution.
|
||||
*/
|
||||
public Form getForm() {
|
||||
if (data.getForm() == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new Form(data.getForm());
|
||||
}
|
||||
public DataForm getForm() {
|
||||
return data.getForm();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,8 +201,8 @@ public abstract class AdHocCommand {
|
|||
* @param form the form of the current stage to fill out or the result of the
|
||||
* execution.
|
||||
*/
|
||||
protected void setForm(Form form) {
|
||||
data.setForm(form.getDataFormToSend());
|
||||
protected void setForm(DataForm form) {
|
||||
data.setForm(form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,7 +230,7 @@ public abstract class AdHocCommand {
|
|||
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||
* @throws InterruptedException if the calling thread was interrupted.
|
||||
*/
|
||||
public abstract void next(Form response) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException;
|
||||
public abstract void next(FillableForm response) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Completes the command execution with the information provided in the
|
||||
|
@ -250,7 +246,7 @@ public abstract class AdHocCommand {
|
|||
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||
* @throws InterruptedException if the calling thread was interrupted.
|
||||
*/
|
||||
public abstract void complete(Form response) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException;
|
||||
public abstract void complete(FillableForm response) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Goes to the previous stage. The requester is asking to re-send the
|
||||
|
|
|
@ -52,7 +52,8 @@ import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider;
|
|||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
@ -462,7 +463,8 @@ public final class AdHocCommandManager extends Manager {
|
|||
|
||||
if (Action.next.equals(action)) {
|
||||
command.incrementStage();
|
||||
command.next(new Form(requestData.getForm()));
|
||||
DataForm dataForm = requestData.getForm();
|
||||
command.next(new FillableForm(dataForm));
|
||||
if (command.isLastStage()) {
|
||||
// If it is the last stage then the command is
|
||||
// completed
|
||||
|
@ -475,7 +477,8 @@ public final class AdHocCommandManager extends Manager {
|
|||
}
|
||||
else if (Action.complete.equals(action)) {
|
||||
command.incrementStage();
|
||||
command.complete(new Form(requestData.getForm()));
|
||||
DataForm dataForm = requestData.getForm();
|
||||
command.complete(new FillableForm(dataForm));
|
||||
response.setStatus(Status.completed);
|
||||
// Remove the completed session
|
||||
executingCommands.remove(sessionId);
|
||||
|
|
|
@ -23,7 +23,8 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
|||
import org.jivesoftware.smack.packet.IQ;
|
||||
|
||||
import org.jivesoftware.smackx.commands.packet.AdHocCommandData;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
@ -80,8 +81,8 @@ public class RemoteCommand extends AdHocCommand {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void complete(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.complete, form);
|
||||
public void complete(FillableForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.complete, form.getDataFormToSubmit());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,13 +101,13 @@ public class RemoteCommand extends AdHocCommand {
|
|||
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||
* @throws InterruptedException if the calling thread was interrupted.
|
||||
*/
|
||||
public void execute(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.execute, form);
|
||||
public void execute(FillableForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.execute, form.getDataFormToSubmit());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.next, form);
|
||||
public void next(FillableForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
executeAction(Action.next, form.getDataFormToSubmit());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,7 +131,7 @@ public class RemoteCommand extends AdHocCommand {
|
|||
* @throws NotConnectedException if the XMPP connection is not connected.
|
||||
* @throws InterruptedException if the calling thread was interrupted.
|
||||
*/
|
||||
private void executeAction(Action action, Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
private void executeAction(Action action, DataForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
// TODO: Check that all the required fields of the form were filled, if
|
||||
// TODO: not throw the corresponding exception. This will make a faster response,
|
||||
// TODO: since the request is stopped before it's sent.
|
||||
|
@ -140,10 +141,7 @@ public class RemoteCommand extends AdHocCommand {
|
|||
data.setNode(getNode());
|
||||
data.setSessionID(sessionID);
|
||||
data.setAction(action);
|
||||
|
||||
if (form != null) {
|
||||
data.setForm(form.getDataFormToSend());
|
||||
}
|
||||
data.setForm(form);
|
||||
|
||||
AdHocCommandData responseData = null;
|
||||
try {
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.jivesoftware.smackx.filetransfer.FileTransferException.NoAcceptableTr
|
|||
import org.jivesoftware.smackx.filetransfer.FileTransferException.NoStreamMethodsOfferedException;
|
||||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.ListSingleFormField;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
@ -189,7 +190,7 @@ public final class FileTransferNegotiator extends Manager {
|
|||
public StreamNegotiator selectStreamNegotiator(
|
||||
FileTransferRequest request) throws NotConnectedException, NoStreamMethodsOfferedException, NoAcceptableTransferMechanisms, InterruptedException {
|
||||
StreamInitiation si = request.getStreamInitiation();
|
||||
FormField streamMethodField = getStreamMethodField(si
|
||||
ListSingleFormField streamMethodField = getStreamMethodField(si
|
||||
.getFeatureNegotiationForm());
|
||||
|
||||
if (streamMethodField == null) {
|
||||
|
@ -216,11 +217,11 @@ public final class FileTransferNegotiator extends Manager {
|
|||
return selectedStreamNegotiator;
|
||||
}
|
||||
|
||||
private static FormField getStreamMethodField(DataForm form) {
|
||||
return form.getField(STREAM_DATA_FIELD_NAME);
|
||||
private static ListSingleFormField getStreamMethodField(DataForm form) {
|
||||
return (ListSingleFormField) form.getField(STREAM_DATA_FIELD_NAME);
|
||||
}
|
||||
|
||||
private StreamNegotiator getNegotiator(final FormField field)
|
||||
private StreamNegotiator getNegotiator(final ListSingleFormField field)
|
||||
throws NoAcceptableTransferMechanisms {
|
||||
String variable;
|
||||
boolean isByteStream = false;
|
||||
|
@ -359,16 +360,15 @@ public final class FileTransferNegotiator extends Manager {
|
|||
}
|
||||
|
||||
private static DataForm createDefaultInitiationForm() {
|
||||
DataForm form = new DataForm(DataForm.Type.form);
|
||||
FormField.Builder fieldBuilder = FormField.builder();
|
||||
fieldBuilder.setFieldName(STREAM_DATA_FIELD_NAME)
|
||||
.setType(FormField.Type.list_single);
|
||||
DataForm.Builder form = DataForm.builder()
|
||||
.setType(DataForm.Type.form);
|
||||
ListSingleFormField.Builder fieldBuilder = FormField.listSingleBuilder(STREAM_DATA_FIELD_NAME);
|
||||
|
||||
if (!IBB_ONLY) {
|
||||
fieldBuilder.addOption(Bytestream.NAMESPACE);
|
||||
}
|
||||
fieldBuilder.addOption(DataPacketExtension.NAMESPACE);
|
||||
form.addField(fieldBuilder.build());
|
||||
return form;
|
||||
return form.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.jivesoftware.smack.util.EventManger.Callback;
|
|||
|
||||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.ListSingleFormField;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
@ -80,13 +81,13 @@ public abstract class StreamNegotiator extends Manager {
|
|||
response.setType(IQ.Type.result);
|
||||
response.setStanzaId(streamInitiationOffer.getStanzaId());
|
||||
|
||||
DataForm form = new DataForm(DataForm.Type.submit);
|
||||
FormField.Builder field = FormField.builder(
|
||||
DataForm.Builder form = DataForm.builder();
|
||||
ListSingleFormField.Builder field = FormField.listSingleBuilder(
|
||||
FileTransferNegotiator.STREAM_DATA_FIELD_NAME);
|
||||
field.addValue(namespace);
|
||||
field.setValue(namespace);
|
||||
form.addField(field.build());
|
||||
|
||||
response.setFeatureNegotiationForm(form);
|
||||
response.setFeatureNegotiationForm(form.build());
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.formtypes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.TextSingleFormField;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
public class FormFieldRegistry {
|
||||
|
||||
private static final Map<String, Map<String, FormField.Type>> REGISTRY = new HashMap<>();
|
||||
|
||||
private static final Map<String, FormField.Type> LOOKASIDE_REGISTRY = new HashMap<>();
|
||||
|
||||
private static final Map<String, String> FIELD_NAME_TO_FORM_TYPE = new HashMap<>();
|
||||
|
||||
static {
|
||||
register(FormField.FORM_TYPE, FormField.Type.hidden);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
public static synchronized void register(DataForm dataForm) {
|
||||
// TODO: Also allow forms of type 'result'?
|
||||
if (dataForm.getType() != DataForm.Type.form) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
String formType = null;
|
||||
TextSingleFormField hiddenFormTypeField = dataForm.getHiddenFormTypeField();
|
||||
if (hiddenFormTypeField != null) {
|
||||
formType = hiddenFormTypeField.getValue();
|
||||
}
|
||||
|
||||
for (FormField formField : dataForm.getFields()) {
|
||||
// Note that we can compare here by reference equality to skip the hidden form type field.
|
||||
if (formField == hiddenFormTypeField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String fieldName = formField.getFieldName();
|
||||
FormField.Type type = formField.getType();
|
||||
register(formType, fieldName, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void register(String formType, String fieldName, FormField.Type type) {
|
||||
if (formType == null) {
|
||||
FormFieldInformation formFieldInformation = lookup(fieldName);
|
||||
if (formFieldInformation != null) {
|
||||
if (Objects.equals(formType, formFieldInformation.formType)
|
||||
&& type.equals(formFieldInformation.formFieldType)) {
|
||||
// The field is already registered, nothing to do here.
|
||||
return;
|
||||
}
|
||||
|
||||
String message = "There is already a field with the name'" + fieldName
|
||||
+ "' registered with the field type '" + formFieldInformation.formFieldType
|
||||
+ "', while this tries to register the field with the type '" + type + '\'';
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
LOOKASIDE_REGISTRY.put(fieldName, type);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, FormField.Type> fieldNameToType = REGISTRY.get(formType);
|
||||
if (fieldNameToType == null) {
|
||||
fieldNameToType = new HashMap<>();
|
||||
REGISTRY.put(formType, fieldNameToType);
|
||||
} else {
|
||||
FormField.Type previousType = fieldNameToType.get(fieldName);
|
||||
if (previousType != null && previousType != type) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
fieldNameToType.put(fieldName, type);
|
||||
|
||||
FIELD_NAME_TO_FORM_TYPE.put(fieldName, formType);
|
||||
}
|
||||
|
||||
public static synchronized void register(String fieldName, FormField.Type type) {
|
||||
FormField.Type previousType = LOOKASIDE_REGISTRY.get(fieldName);
|
||||
if (previousType != null) {
|
||||
if (previousType == type) {
|
||||
// Nothing to do here.
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("There is already a field with the name '" + fieldName
|
||||
+ "' registered with type " + previousType
|
||||
+ ", while trying to register this field with type '" + type + "'");
|
||||
}
|
||||
|
||||
LOOKASIDE_REGISTRY.put(fieldName, type);
|
||||
}
|
||||
|
||||
public static synchronized FormField.Type lookup(String formType, String fieldName) {
|
||||
if (formType != null) {
|
||||
Map<String, FormField.Type> fieldNameToTypeMap = REGISTRY.get(formType);
|
||||
if (fieldNameToTypeMap != null) {
|
||||
FormField.Type type = fieldNameToTypeMap.get(fieldName);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
formType = FIELD_NAME_TO_FORM_TYPE.get(fieldName);
|
||||
if (formType != null) {
|
||||
FormField.Type type = lookup(formType, fieldName);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to lookaside registry.
|
||||
return LOOKASIDE_REGISTRY.get(fieldName);
|
||||
}
|
||||
|
||||
public static synchronized FormFieldInformation lookup(String fieldName) {
|
||||
String formType = FIELD_NAME_TO_FORM_TYPE.get(fieldName);
|
||||
FormField.Type type = lookup(formType, fieldName);
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FormFieldInformation(type, formType);
|
||||
}
|
||||
|
||||
public static final class FormFieldInformation {
|
||||
public final FormField.Type formFieldType;
|
||||
public final String formType;
|
||||
|
||||
|
||||
private FormFieldInformation(FormField.Type formFieldType, String formType) {
|
||||
this.formFieldType = formFieldType;
|
||||
this.formType = formType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Smack's implementation of XEP-0068: Field Standardization for Data Forms.
|
||||
*/
|
||||
package org.jivesoftware.smackx.formtypes;
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 Florian Schmaus
|
||||
* Copyright 2015-2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,17 +23,18 @@ import java.util.List;
|
|||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
|
||||
import org.jivesoftware.smackx.muc.MultiUserChatException.MucConfigurationNotSupportedException;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
import org.jivesoftware.smackx.xdata.form.FilledForm;
|
||||
import org.jivesoftware.smackx.xdata.form.Form;
|
||||
|
||||
import org.jxmpp.jid.Jid;
|
||||
import org.jxmpp.jid.util.JidUtil;
|
||||
|
||||
/**
|
||||
* Multi-User Chat configuration form manager is used to fill out and submit a {@link Form} used to
|
||||
* Multi-User Chat configuration form manager is used to fill out and submit a {@link FilledForm} used to
|
||||
* configure rooms.
|
||||
* <p>
|
||||
* Room configuration needs either be done right after the room is created and still locked. Or at
|
||||
|
@ -43,12 +44,17 @@ import org.jxmpp.jid.util.JidUtil;
|
|||
* </p>
|
||||
* <p>
|
||||
* The manager may not provide all possible configuration options. If you want direct access to the
|
||||
* configuraiton form, use {@link MultiUserChat#getConfigurationForm()} and
|
||||
* {@link MultiUserChat#sendConfigurationForm(Form)}.
|
||||
* configuration form, use {@link MultiUserChat#getConfigurationForm()} and
|
||||
* {@link MultiUserChat#sendConfigurationForm(FillableForm)}.
|
||||
* </p>
|
||||
*/
|
||||
public class MucConfigFormManager {
|
||||
/**
|
||||
|
||||
private static final String HASH_ROOMCONFIG = "#roomconfig";
|
||||
|
||||
public static final String FORM_TYPE = MultiUserChatConstants.NAMESPACE + HASH_ROOMCONFIG;
|
||||
|
||||
/**
|
||||
* The constant String {@value}.
|
||||
*
|
||||
* @see <a href="http://xmpp.org/extensions/xep-0045.html#owner">XEP-0045 § 10. Owner Use Cases</a>
|
||||
|
@ -73,7 +79,7 @@ public class MucConfigFormManager {
|
|||
public static final String MUC_ROOMCONFIG_ROOMSECRET = "muc#roomconfig_roomsecret";
|
||||
|
||||
private final MultiUserChat multiUserChat;
|
||||
private final Form answerForm;
|
||||
private final FillableForm answerForm;
|
||||
private final List<Jid> owners;
|
||||
|
||||
/**
|
||||
|
@ -94,20 +100,13 @@ public class MucConfigFormManager {
|
|||
|
||||
// Set the answer form
|
||||
Form configForm = multiUserChat.getConfigurationForm();
|
||||
this.answerForm = configForm.createAnswerForm();
|
||||
// Add the default answers to the form to submit
|
||||
for (FormField field : configForm.getFields()) {
|
||||
if (field.getType() == FormField.Type.hidden
|
||||
|| StringUtils.isNullOrEmpty(field.getVariable())) {
|
||||
continue;
|
||||
}
|
||||
answerForm.setDefaultAnswer(field.getVariable());
|
||||
}
|
||||
this.answerForm = configForm.getFillableForm();
|
||||
|
||||
// Set the local variables according to the fields found in the answer form
|
||||
if (answerForm.hasField(MUC_ROOMCONFIG_ROOMOWNERS)) {
|
||||
FormField roomOwnersFormField = answerForm.getDataForm().getField(MUC_ROOMCONFIG_ROOMOWNERS);
|
||||
if (roomOwnersFormField != null) {
|
||||
// Set 'owners' to the currently configured owners
|
||||
List<CharSequence> ownerStrings = answerForm.getField(MUC_ROOMCONFIG_ROOMOWNERS).getValues();
|
||||
List<? extends CharSequence> ownerStrings = roomOwnersFormField.getValues();
|
||||
owners = new ArrayList<>(ownerStrings.size());
|
||||
JidUtil.jidsFrom(ownerStrings, owners, null);
|
||||
}
|
||||
|
@ -244,7 +243,7 @@ public class MucConfigFormManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Submit the configuration as {@link Form} to the room.
|
||||
* Submit the configuration as {@link FilledForm} to the room.
|
||||
*
|
||||
* @throws NoResponseException if there was no response from the room.
|
||||
* @throws XMPPErrorException if there was an XMPP error returned.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
* Copyright 2003-2007 Jive Software. 2020 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -75,8 +75,10 @@ import org.jivesoftware.smackx.muc.packet.MUCItem;
|
|||
import org.jivesoftware.smackx.muc.packet.MUCOwner;
|
||||
import org.jivesoftware.smackx.muc.packet.MUCUser;
|
||||
import org.jivesoftware.smackx.muc.packet.MUCUser.Status;
|
||||
import org.jivesoftware.smackx.xdata.Form;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.TextSingleFormField;
|
||||
import org.jivesoftware.smackx.xdata.form.FillableForm;
|
||||
import org.jivesoftware.smackx.xdata.form.Form;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
||||
import org.jxmpp.jid.DomainBareJid;
|
||||