1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-29 23:42:06 +01:00

Compare commits

..

No commits in common. "658905e1ba90fb402352de79bf146f8d6faac157" and "d9f45e03f3cc5b55db3fcc48e8440c6cb9b641a1" have entirely different histories.

24 changed files with 89 additions and 424 deletions

View file

@ -86,7 +86,6 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|-----------------------------------------------------------|--------------------------------------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------| |-----------------------------------------------------------|--------------------------------------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------|
| Message Carbons | [XEP-0280](https://xmpp.org/extensions/xep-0280.html) | n/a | Keep all IM clients for a user engaged in a conversation, by carbon-copy outbound messages to all interested resources. | | Message Carbons | [XEP-0280](https://xmpp.org/extensions/xep-0280.html) | n/a | Keep all IM clients for a user engaged in a conversation, by carbon-copy outbound messages to all interested resources. |
| [Message Archive Management](mam.md) | [XEP-0313](https://xmpp.org/extensions/xep-0313.html) | n/a | Query and control an archive of messages stored on a server. | | [Message Archive Management](mam.md) | [XEP-0313](https://xmpp.org/extensions/xep-0313.html) | n/a | Query and control an archive of messages stored on a server. |
| Data Forms XML Element | [XEP-0315](https://xmpp.org/extensions/xep-0315.html) | n/a | Allows to include XML-data in XEP-0004 data forms. |
| [Internet of Things - Sensor Data](iot.md) | [XEP-0323](https://xmpp.org/extensions/xep-0323.html) | n/a | Sensor data interchange over XMPP. | | [Internet of Things - Sensor Data](iot.md) | [XEP-0323](https://xmpp.org/extensions/xep-0323.html) | n/a | Sensor data interchange over XMPP. |
| [Internet of Things - Provisioning](iot.md) | [XEP-0324](https://xmpp.org/extensions/xep-0324.html) | n/a | Provisioning, access rights and user privileges for the Internet of Things. | | [Internet of Things - Provisioning](iot.md) | [XEP-0324](https://xmpp.org/extensions/xep-0324.html) | n/a | Provisioning, access rights and user privileges for the Internet of Things. |
| [Internet of Things - Control](iot.md) | [XEP-0325](https://xmpp.org/extensions/xep-0325.html) | n/a | Describes how to control devices or actuators in an XMPP-based sensor network. | | [Internet of Things - Control](iot.md) | [XEP-0325](https://xmpp.org/extensions/xep-0325.html) | n/a | Describes how to control devices or actuators in an XMPP-based sensor network. |

View file

@ -17,8 +17,6 @@
package org.jivesoftware.smack; package org.jivesoftware.smack;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -52,18 +50,6 @@ import org.jivesoftware.smack.util.Objects;
*/ */
public final class SmackConfiguration { public final class SmackConfiguration {
public static final String SMACK_URL_STRING = "https://igniterealtime.org/projects/smack";
public static final URL SMACK_URL;
static {
try {
SMACK_URL = new URL(SMACK_URL_STRING);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
private static int defaultPacketReplyTimeout = 5000; private static int defaultPacketReplyTimeout = 5000;
private static int packetCollectorSize = 5000; private static int packetCollectorSize = 5000;

View file

@ -261,8 +261,6 @@ public abstract class IQ extends Stanza {
} }
protected final void initializeAsResultFor(IQ request) { protected final void initializeAsResultFor(IQ request) {
assert this != request;
if (!(request.getType() == Type.get || request.getType() == Type.set)) { if (!(request.getType() == Type.get || request.getType() == Type.set)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML()); "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());

View file

@ -22,10 +22,6 @@ import java.io.StringWriter;
public class ExceptionUtil { public class ExceptionUtil {
public static String getStackTrace(Throwable throwable) { public static String getStackTrace(Throwable throwable) {
if (throwable == null) {
return null;
}
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter); PrintWriter printWriter = new PrintWriter(stringWriter);

View file

@ -16,30 +16,13 @@
*/ */
package org.jivesoftware.smack.util; package org.jivesoftware.smack.util;
import java.util.logging.Logger;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.FullyQualifiedElement; import org.jivesoftware.smack.packet.FullyQualifiedElement;
public class XmppElementUtil { public class XmppElementUtil {
public static final Logger LOGGER = Logger.getLogger(XmppElementUtil.class.getName());
public static QName getQNameFor(Class<? extends FullyQualifiedElement> fullyQualifiedElement) { public static QName getQNameFor(Class<? extends FullyQualifiedElement> fullyQualifiedElement) {
try {
Object qnameObject = fullyQualifiedElement.getField("QNAME").get(null);
if (QName.class.isAssignableFrom(qnameObject.getClass())) {
return (QName) qnameObject;
}
LOGGER.warning("The QNAME field of " + fullyQualifiedElement + " is not of type QNAME.");
} catch (NoSuchFieldException e) {
LOGGER.finer("The class " + fullyQualifiedElement + " has no static QNAME field. Consider adding one.");
// Proceed to fallback strategy.
} catch (IllegalArgumentException | IllegalAccessException | SecurityException e) {
throw new IllegalArgumentException(e);
}
String element, namespace; String element, namespace;
try { try {
element = (String) fullyQualifiedElement.getField("ELEMENT").get(null); element = (String) fullyQualifiedElement.getField("ELEMENT").get(null);

View file

@ -16,12 +16,10 @@
*/ */
package org.jivesoftware.smack.packet; package org.jivesoftware.smack.packet;
import org.jivesoftware.smack.SmackConfiguration;
public class TestIQ extends SimpleIQ { public class TestIQ extends SimpleIQ {
public TestIQ() { public TestIQ() {
this(SmackConfiguration.SMACK_URL_STRING, "test-iq"); this("https://igniterealtime.org/projects/smack", "test-iq");
} }
public TestIQ(String element, String namespace) { public TestIQ(String element, String namespace) {

View file

@ -22,13 +22,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
@ -48,9 +50,8 @@ import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException; import org.jivesoftware.smack.xml.XmlPullParserException;
import com.jamesmurty.utils.XMLBuilder; import com.jamesmurty.utils.XMLBuilder;
import org.junit.Ignore;
import org.junit.jupiter.api.Disabled; import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@ -427,7 +428,7 @@ public class PacketParserUtilsTest {
} }
// TODO: Re-enable once we throw an exception on duplicate body elements. // TODO: Re-enable once we throw an exception on duplicate body elements.
@Disabled @Ignore
@Test @Test
public void duplicateMessageBodiesTest() public void duplicateMessageBodiesTest()
throws FactoryConfigurationError, XmlPullParserException, IOException, Exception { throws FactoryConfigurationError, XmlPullParserException, IOException, Exception {
@ -459,7 +460,7 @@ public class PacketParserUtilsTest {
assertXmlNotSimilar(control, message.toXML().toString()); assertXmlNotSimilar(control, message.toXML().toString());
} }
@Disabled @Ignore
@Test @Test
public void duplicateMessageBodiesTest2() public void duplicateMessageBodiesTest2()
throws FactoryConfigurationError, XmlPullParserException, IOException, Exception { throws FactoryConfigurationError, XmlPullParserException, IOException, Exception {
@ -678,7 +679,7 @@ public class PacketParserUtilsTest {
* *
* @throws Exception * @throws Exception
*/ */
@Test @Test(expected = XmlPullParserException.class)
public void invalidMessageBodyContainingTagTest() throws Exception { public void invalidMessageBodyContainingTagTest() throws Exception {
String control = XMLBuilder.create("message") String control = XMLBuilder.create("message")
.namespace(StreamOpen.CLIENT_NAMESPACE) .namespace(StreamOpen.CLIENT_NAMESPACE)
@ -694,14 +695,14 @@ public class PacketParserUtilsTest {
.t("Bad Message Body") .t("Bad Message Body")
.asString(outputProperties); .asString(outputProperties);
assertThrows(XmlPullParserException.class, () -> Message message = PacketParserUtils.parseMessage(TestUtils.getMessageParser(control));
PacketParserUtils.parseMessage(TestUtils.getMessageParser(control))
); fail("Should throw exception. Instead got message: " + message.toXML().toString());
} }
@Test @Test
public void invalidXMLInMessageBody() throws Exception { public void invalidXMLInMessageBody() throws Exception {
final String validControl = XMLBuilder.create("message") String validControl = XMLBuilder.create("message")
.namespace(StreamOpen.CLIENT_NAMESPACE) .namespace(StreamOpen.CLIENT_NAMESPACE)
.a("from", "romeo@montague.lit/orchard") .a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony") .a("to", "juliet@capulet.lit/balcony")
@ -712,20 +713,41 @@ public class PacketParserUtilsTest {
.t("Good Message Body") .t("Good Message Body")
.asString(outputProperties); .asString(outputProperties);
assertThrows(XmlPullParserException.class, () -> { // XPP3 writes "end tag", StAX writes "end-tag".
Supplier<Stream<String>> expectedContentOfExceptionMessage = () -> Stream.of("end tag", "end-tag");
String invalidControl = validControl.replace("Good Message Body", "Bad </span> Body"); String invalidControl = validControl.replace("Good Message Body", "Bad </span> Body");
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
});
assertThrows(XmlPullParserException.class, () -> { try {
String invalidControl = validControl.replace("Good Message Body", "Bad </body> Body");
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl)); PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
}); fail("Exception should be thrown");
} catch (XmlPullParserException e) {
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
assertThrows(XmlPullParserException.class, () -> { invalidControl = validControl.replace("Good Message Body", "Bad </body> Body");
String invalidControl = validControl.replace("Good Message Body", "Bad </message> Body");
try {
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl)); PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
}); fail("Exception should be thrown");
} catch (XmlPullParserException e) {
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
invalidControl = validControl.replace("Good Message Body", "Bad </message> Body");
try {
PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl));
fail("Exception should be thrown");
} catch (XmlPullParserException e) {
String exceptionMessage = e.getMessage();
boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected));
assertTrue(expectedContentFound);
}
} }
@Test @Test
@ -869,18 +891,15 @@ public class PacketParserUtilsTest {
return otherLanguage; return otherLanguage;
} }
@Test @Test(expected = IllegalArgumentException.class)
public void descriptiveTextNullLangPassedMap() throws Exception { public void descriptiveTextNullLangPassedMap() throws Exception {
final String text = "Dummy descriptive text"; final String text = "Dummy descriptive text";
Map<String, String> texts = new HashMap<>(); Map<String, String> texts = new HashMap<>();
texts.put(null, text); texts.put(null, text);
assertThrows(IllegalArgumentException.class, () ->
StanzaError StanzaError
.getBuilder(StanzaError.Condition.internal_server_error) .getBuilder(StanzaError.Condition.internal_server_error)
.setDescriptiveTexts(texts) .setDescriptiveTexts(texts)
.build() .build();
);
} }
@Test @Test

View file

@ -1,28 +0,0 @@
/**
*
* Copyright 2019 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.xmlelement;
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProviderManager;
import org.jivesoftware.smackx.xmlelement.provider.DataFormsXmlElementProvider;
public class DataFormsXmlElementManager {
static {
FormFieldChildElementProviderManager.addFormFieldChildElementProvider(new DataFormsXmlElementProvider());
}
}

View file

@ -1,74 +0,0 @@
/**
*
* Copyright 2019 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.xmlelement.element;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.StandardExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.FormFieldChildElement;
public class DataFormsXmlElement implements FormFieldChildElement {
public static final String ELEMENT = "wrapper";
public static final String NAMESPACE = "urn:xmpp:xml-element";
public static final QName QNAME = new QName(NAMESPACE, ELEMENT);
private final StandardExtensionElement payload;
public DataFormsXmlElement(StandardExtensionElement payload) {
this.payload = payload;
}
@Override
public QName getQName() {
return QNAME;
}
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment);
if (payload == null) {
return xml.closeEmptyElement();
}
xml.rightAngleBracket();
xml.append(payload.toXML());
xml.closeElement(this);
return xml;
}
public static DataFormsXmlElement from(FormField formField) {
return (DataFormsXmlElement) formField.getFormFieldChildElement(QNAME);
}
}

View file

@ -1,21 +0,0 @@
/**
*
* Copyright 2019 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.
*/
/**
* Element classes for XEP-0315: Data Forms XML Element.
*/
package org.jivesoftware.smackx.xmlelement.element;

View file

@ -1,21 +0,0 @@
/**
*
* Copyright 2019 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.
*/
/**
* Smacks implementation of XEP-0315: Data Forms XML Element.
*/
package org.jivesoftware.smackx.xmlelement;

View file

@ -1,54 +0,0 @@
/**
*
* Copyright 2019 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.xmlelement.provider;
import java.io.IOException;
import javax.xml.namespace.QName;
import org.jivesoftware.smack.packet.StandardExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.parsing.SmackParsingException;
import org.jivesoftware.smack.parsing.StandardExtensionElementProvider;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProvider;
import org.jivesoftware.smackx.xmlelement.element.DataFormsXmlElement;
public class DataFormsXmlElementProvider extends FormFieldChildElementProvider<DataFormsXmlElement> {
@Override
public QName getQName() {
return DataFormsXmlElement.QNAME;
}
@Override
public DataFormsXmlElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
throws IOException, XmlPullParserException, SmackParsingException {
XmlPullParser.TagEvent tagEvent = parser.nextTag();
final StandardExtensionElement standardExtensionElement;
if (tagEvent == XmlPullParser.TagEvent.START_ELEMENT) {
standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser);
} else {
standardExtensionElement = null;
}
return new DataFormsXmlElement(standardExtensionElement);
}
}

View file

@ -1,21 +0,0 @@
/**
*
* Copyright 2019 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.
*/
/**
* Provider classes for XEP-0315: Data Forms XML Element.
*/
package org.jivesoftware.smackx.xmlelement.provider;

View file

@ -7,6 +7,5 @@
<className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className> <className>org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager</className>
<className>org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager</className> <className>org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager</className>
<className>org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager</className> <className>org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager</className>
<className>org.jivesoftware.smackx.xmlelement.DataFormsXmlElementManager</className>
</startupClasses> </startupClasses>
</smack> </smack>

View file

@ -36,7 +36,6 @@ import java.util.logging.Logger;
import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.StanzaListener;
@ -93,7 +92,7 @@ public final class EntityCapsManager extends Manager {
*/ */
private static final String DEFAULT_HASH = StringUtils.SHA1; private static final String DEFAULT_HASH = StringUtils.SHA1;
private static String DEFAULT_ENTITY_NODE = SmackConfiguration.SMACK_URL_STRING; private static String DEFAULT_ENTITY_NODE = "http://www.igniterealtime.org/projects/smack";
protected static EntityCapsPersistentCache persistentCache; protected static EntityCapsPersistentCache persistentCache;

View file

@ -203,7 +203,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable<DiscoverInfo> {
* @param node the node attribute that supplements the 'jid' attribute * @param node the node attribute that supplements the 'jid' attribute
*/ */
public void setNode(String node) { public void setNode(String node) {
this.node = StringUtils.requireNullOrNotEmpty(node, "The node can not be the empty string"); this.node = node;
} }
/** /**

View file

@ -25,7 +25,6 @@ import java.util.WeakHashMap;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
@ -194,7 +193,7 @@ public final class PrivateDataManager extends Manager {
@Override @Override
public String getNamespace() { public String getNamespace() {
return SmackConfiguration.SMACK_URL_STRING; return "https://igniterealtime.org/projects/smack/";
} }
@Override @Override

View file

@ -46,10 +46,6 @@ import org.jivesoftware.smackx.shim.packet.Header;
import org.jivesoftware.smackx.shim.packet.HeadersExtension; import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
public abstract class Node { public abstract class Node {
protected final PubSubManager pubSubManager; protected final PubSubManager pubSubManager;
protected final String id; protected final String id;
@ -390,45 +386,12 @@ public abstract class Node {
* @throws NotConnectedException * @throws NotConnectedException
* @throws InterruptedException * @throws InterruptedException
*/ */
public Subscription subscribe(Jid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public Subscription subscribe(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub pubSub = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId())); PubSub pubSub = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId()));
PubSub reply = sendPubsubPacket(pubSub); PubSub reply = sendPubsubPacket(pubSub);
return reply.getExtension(PubSubElementType.SUBSCRIPTION); return reply.getExtension(PubSubElementType.SUBSCRIPTION);
} }
/**
* The user subscribes to the node using the supplied jid. The
* bare jid portion of this one must match the jid for the connection.
*
* Please note that the {@link Subscription.State} should be checked
* on return since more actions may be required by the caller.
* {@link Subscription.State#pending} - The owner must approve the subscription
* request before messages will be received.
* {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
* the caller must configure the subscription before messages will be received. If it is false
* the caller can configure it but is not required to do so.
*
* @param jidString The jid to subscribe as.
* @return The subscription
* @throws XMPPErrorException
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
* @throws IllegalArgumentException if the provided string is not a valid JID.
* @deprecated use {@link #subscribe(Jid)} instead.
*/
@Deprecated
// TODO: Remove in Smack 4.5.
public Subscription subscribe(String jidString) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
Jid jid;
try {
jid = JidCreate.from(jidString);
} catch (XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
return subscribe(jid);
}
/** /**
* The user subscribes to the node using the supplied jid and subscription * The user subscribes to the node using the supplied jid and subscription
* options. The bare jid portion of this one must match the jid for the * options. The bare jid portion of this one must match the jid for the
@ -451,49 +414,13 @@ public abstract class Node {
* @throws NotConnectedException * @throws NotConnectedException
* @throws InterruptedException * @throws InterruptedException
*/ */
public Subscription subscribe(Jid jid, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public Subscription subscribe(String jid, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId())); PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId()));
request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm)); request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
PubSub reply = sendPubsubPacket(request); PubSub reply = sendPubsubPacket(request);
return reply.getExtension(PubSubElementType.SUBSCRIPTION); return reply.getExtension(PubSubElementType.SUBSCRIPTION);
} }
/**
* The user subscribes to the node using the supplied jid and subscription
* options. The bare jid portion of this one must match the jid for the
* connection.
*
* Please note that the {@link Subscription.State} should be checked
* on return since more actions may be required by the caller.
* {@link Subscription.State#pending} - The owner must approve the subscription
* request before messages will be received.
* {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
* the caller must configure the subscription before messages will be received. If it is false
* the caller can configure it but is not required to do so.
*
* @param jidString The jid to subscribe as.
* @param subForm
*
* @return The subscription
* @throws XMPPErrorException
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
* @throws IllegalArgumentException if the provided string is not a valid JID.
* @deprecated use {@link #subscribe(Jid, SubscribeForm)} instead.
*/
@Deprecated
// TODO: Remove in Smack 4.5.
public Subscription subscribe(String jidString, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
Jid jid;
try {
jid = JidCreate.from(jidString);
} catch (XmppStringprepException e) {
throw new IllegalArgumentException(e);
}
return subscribe(jid, subForm);
}
/** /**
* Remove the subscription related to the specified JID. This will only * Remove the subscription related to the specified JID. This will only
* work if there is only 1 subscription. If there are multiple subscriptions, * work if there is only 1 subscription. If there are multiple subscriptions,

View file

@ -37,7 +37,6 @@ import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StanzaError; import org.jivesoftware.smack.packet.StanzaError;
import org.jivesoftware.smack.packet.StanzaError.Condition; import org.jivesoftware.smack.packet.StanzaError.Condition;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo; import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
@ -269,7 +268,6 @@ public final class PubSubManager extends Manager {
* @throws NotAPubSubNodeException * @throws NotAPubSubNodeException
*/ */
public Node getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAPubSubNodeException { public Node getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAPubSubNodeException {
StringUtils.requireNotNullNorEmpty(id, "The node ID can not be null or the empty string");
Node node = nodeMap.get(id); Node node = nodeMap.get(id);
if (node == null) { if (node == null) {

View file

@ -16,39 +16,42 @@
*/ */
package org.jivesoftware.smackx.pubsub; package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.jid.Jid;
/** /**
* Represents a request to subscribe to a node. * Represents a request to subscribe to a node.
* *
* @author Robin Collier * @author Robin Collier
*/ */
public class SubscribeExtension extends NodeExtension { public class SubscribeExtension extends NodeExtension {
protected final Jid jid; protected String jid;
public SubscribeExtension(Jid subscribeJid) { public SubscribeExtension(String subscribeJid) {
super(PubSubElementType.SUBSCRIBE); super(PubSubElementType.SUBSCRIBE);
jid = subscribeJid; jid = subscribeJid;
} }
public SubscribeExtension(Jid subscribeJid, String nodeId) { public SubscribeExtension(String subscribeJid, String nodeId) {
super(PubSubElementType.SUBSCRIBE, nodeId); super(PubSubElementType.SUBSCRIBE, nodeId);
jid = subscribeJid; jid = subscribeJid;
} }
public Jid getJid() { public String getJid() {
return jid; return jid;
} }
@Override @Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment); StringBuilder builder = new StringBuilder("<");
xml.optAttribute("node", getNode()); builder.append(getElementName());
xml.attribute("jid", getJid());
xml.closeEmptyElement(); if (getNode() != null) {
return xml; builder.append(" node='");
builder.append(getNode());
builder.append('\'');
}
builder.append(" jid='");
builder.append(getJid());
builder.append("'/>");
return builder.toString();
} }
} }

View file

@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.List; import java.util.List;
@ -520,24 +521,17 @@ public class Socks5ByteStreamManagerTest {
* @throws InterruptedException * @throws InterruptedException
* @throws SmackException * @throws SmackException
* @throws XMPPException * @throws XMPPException
* @throws XmppStringprepException
*/ */
@Test @Test
public void shouldFailIfInitiatorCannotConnectToSocks5Proxy() public void shouldFailIfInitiatorCannotConnectToSocks5Proxy()
throws SmackException, InterruptedException, XMPPException, XmppStringprepException { throws SmackException, InterruptedException, XMPPException {
final Protocol protocol = new Protocol(); final Protocol protocol = new Protocol();
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID); final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
final String sessionID = "session_id_shouldFailIfInitiatorCannotConnectToSocks5Proxy"; final String sessionID = "session_id_shouldFailIfInitiatorCannotConnectToSocks5Proxy";
// TODO: The following two variables should be named initatorProxyJid and initiatorProxyAddress.
final DomainBareJid proxyJID = JidCreate.domainBareFrom("s5b-proxy.initiator.org");
// Use an TEST-NET-1 address from RFC 5737 to act as black hole.
final String proxyAddress = "192.0.2.1";
// get Socks5ByteStreamManager for connection // get Socks5ByteStreamManager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection); Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
byteStreamManager.setAnnounceLocalStreamHost(false); byteStreamManager.setAnnounceLocalStreamHost(false);
byteStreamManager.setProxyConnectionTimeout(3000);
/** /**
* create responses in the order they should be queried specified by the XEP-0065 * create responses in the order they should be queried specified by the XEP-0065
@ -608,9 +602,8 @@ public class Socks5ByteStreamManagerTest {
// initiator can't connect to proxy because it is not running // initiator can't connect to proxy because it is not running
protocol.verifyAll(); protocol.verifyAll();
Throwable actualCause = e.getCause(); Throwable actualCause = e.getCause().getCause();
assertEquals("Unexpected throwable: " + actualCause + '.' + ExceptionUtil.getStackTrace(actualCause), assertEquals("Unexpected throwable: " + actualCause + '.' + ExceptionUtil.getStackTrace(actualCause), ConnectException.class, actualCause.getClass());
TimeoutException.class, actualCause.getClass());
} }
/** /**

View file

@ -23,8 +23,6 @@ dependencies {
// (ab)uses @Before from org.junit // (ab)uses @Before from org.junit
compile "org.junit.vintage:junit-vintage-engine:$junitVersion" compile "org.junit.vintage:junit-vintage-engine:$junitVersion"
compile 'junit:junit:4.12' compile 'junit:junit:4.12'
// Add Junit 5 API for e.g. assertThrows()
implementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests" testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests"
} }

View file

@ -18,13 +18,14 @@ package org.jivesoftware.smackx.pubsub;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.StandardExtensionElement;
import org.jivesoftware.smack.packet.StanzaError; import org.jivesoftware.smack.packet.StanzaError;
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
@ -68,6 +69,8 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest {
try { try {
LeafNode leafNode = (LeafNode) node; LeafNode leafNode = (LeafNode) node;
leafNode.publish(); leafNode.publish();
List<Item> items = leafNode.getItems();
assertTrue(items.isEmpty());
} }
finally { finally {
pubSubManagerOne.deleteNode(nodename); pubSubManagerOne.deleteNode(nodename);
@ -92,7 +95,6 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest {
public void transientNotificationOnlyNodeWithItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public void transientNotificationOnlyNodeWithItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
final String nodename = "sinttest-transient-notificationonly-withitem-nodename-" + testRunId; final String nodename = "sinttest-transient-notificationonly-withitem-nodename-" + testRunId;
final String itemId = "sinttest-transient-notificationonly-withitem-itemid-" + testRunId; final String itemId = "sinttest-transient-notificationonly-withitem-itemid-" + testRunId;
ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration();
ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm());
// Configure the node as "Notification-Only Node". // Configure the node as "Notification-Only Node".
@ -100,23 +102,12 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest {
// Configure the node as "transient" (set persistent_items to 'false') // Configure the node as "transient" (set persistent_items to 'false')
config.setPersistentItems(false); config.setPersistentItems(false);
Node node = pubSubManagerOne.createNode(nodename, config); Node node = pubSubManagerOne.createNode(nodename, config);
// Add a dummy payload. If there is no payload, but just an item ID, then ejabberd will *not* return an error,
// which I believe to be non-compliant behavior (although, granted, the XEP is not very clear about this). A user
// which sends an empty item with ID to an node that is configured to be notification-only and transient probably
// does something wrong, as the item's ID will never appear anywhere. Hence it would be nice if the user would be
// made aware of this issue by returning an error. Sadly ejabberd does not do so.
// See also https://github.com/processone/ejabberd/issues/2864#issuecomment-500741915
final StandardExtensionElement dummyPayload = StandardExtensionElement.builder("dummy-payload",
SmackConfiguration.SMACK_URL_STRING).setText(testRunId).build();
try { try {
XMPPErrorException e = assertThrows(XMPPErrorException.class, () -> {
LeafNode leafNode = (LeafNode) node; LeafNode leafNode = (LeafNode) node;
leafNode.publish(new Item(itemId));
Item item = new PayloadItem<>(itemId, dummyPayload); fail("An exception should have been thrown.");
leafNode.publish(item); }
}); catch (XMPPErrorException e) {
assertEquals(StanzaError.Type.MODIFY, e.getStanzaError().getType()); assertEquals(StanzaError.Type.MODIFY, e.getStanzaError().getType());
assertNotNull(e.getStanzaError().getExtension("item-forbidden", "http://jabber.org/protocol/pubsub#errors")); assertNotNull(e.getStanzaError().getExtension("item-forbidden", "http://jabber.org/protocol/pubsub#errors"));
} }

View file

@ -1116,9 +1116,7 @@ public class XmppNioTcpConnection extends AbstractXmppNioConnection {
// remote hostname information, in which case peerHost needs to be specified." that A should be used. TLS // remote hostname information, in which case peerHost needs to be specified." that A should be used. TLS
// session resumption may would need or at least benefit from B. Variant A would also be required if the // session resumption may would need or at least benefit from B. Variant A would also be required if the
// String is used for certificate verification. And it appears at least likely that TLS session resumption // String is used for certificate verification. And it appears at least likely that TLS session resumption
// would not be hurt by using variant A. Therefore we currently use variant A. // would not be hurt by using variant A. Therfore we currently use variant A.
// TODO: Should we use the ACE representation of the XMPP service domain? Compare with f60e4055ec529f0b8160acedf13275592ab10a4b
// If yes, then we should probably introduce getXmppServiceDomainAceEncodedIfPossible().
engine = smackTlsContext.sslContext.createSSLEngine(config.getXMPPServiceDomain().toString(), remoteAddress.getPort()); engine = smackTlsContext.sslContext.createSSLEngine(config.getXMPPServiceDomain().toString(), remoteAddress.getPort());
engine.setUseClientMode(true); engine.setUseClientMode(true);