From 157ff138a41e8244b3bf766606a054b8a73a73c3 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 3 Jan 2017 12:08:44 +0100 Subject: [PATCH 01/15] Smack 4.2.0-rc2-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index c18ca88ed..53d4d2ffd 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.2.0-rc1' - isSnapshot = false + shortVersion = '4.2.0-rc2' + isSnapshot = true jxmppVersion = '0.5.0' smackMinAndroidSdk = 8 } From e9bbe9a475640754783fa6def2ad4e9db66e4120 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 4 Jan 2017 15:35:47 +0100 Subject: [PATCH 02/15] Fix OOB exception when setHostAddress(InetAddress) is used. Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.charAt(String.java:658) at org.jivesoftware.smack.util.dns.HostAddress.(HostAddress.java:48) at org.jivesoftware.smack.util.dns.HostAddress.(HostAddress.java:62) --- .../jivesoftware/smack/util/dns/HostAddress.java | 15 +++++++-------- .../jivesoftware/smack/util/dns/SRVRecord.java | 5 ++++- .../jivesoftware/smack/tcp/XMPPTCPConnection.java | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/HostAddress.java b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/HostAddress.java index e0eb98aed..e56b0a185 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/HostAddress.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/HostAddress.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2013-2016 Florian Schmaus + * Copyright © 2013-2017 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import java.util.Map; import java.util.Map.Entry; import org.jivesoftware.smack.SmackException.ConnectionException; -import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.StringUtils; public class HostAddress { private final String fqdn; @@ -34,18 +34,17 @@ public class HostAddress { private final List inetAddresses; /** - * Creates a new HostAddress with the given FQDN. The port will be set to the default XMPP client port: 5222 + * Creates a new HostAddress with the given FQDN. * - * @param fqdn Fully qualified domain name. + * @param fqdn the optional fully qualified domain name (FQDN). * @param port The port to connect on. - * @throws IllegalArgumentException If the fqdn is null or port is out of valid range (0 - 65535). + * @throws IllegalArgumentException If the port is out of valid range (0 - 65535). */ public HostAddress(String fqdn, int port, List inetAddresses) { - Objects.requireNonNull(fqdn, "FQDN is null"); if (port < 0 || port > 65535) throw new IllegalArgumentException( "Port must be a 16-bit unsiged integer (i.e. between 0-65535. Port was: " + port); - if (fqdn.charAt(fqdn.length() - 1) == '.') { + if (StringUtils.isNotEmpty(fqdn) && fqdn.charAt(fqdn.length() - 1) == '.') { this.fqdn = fqdn.substring(0, fqdn.length() - 1); } else { @@ -59,7 +58,7 @@ public class HostAddress { } public HostAddress(int port, InetAddress hostAddress) { - this("", port, Collections.singletonList(hostAddress)); + this(null, port, Collections.singletonList(hostAddress)); } /** diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/SRVRecord.java b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/SRVRecord.java index e84d846de..f63c94e49 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/SRVRecord.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/SRVRecord.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2016 Florian Schmaus + * Copyright 2013-2017 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ package org.jivesoftware.smack.util.dns; import java.net.InetAddress; import java.util.List; +import org.jivesoftware.smack.util.StringUtils; + /** * A DNS SRV RR. * @@ -43,6 +45,7 @@ public class SRVRecord extends HostAddress implements Comparable { */ public SRVRecord(String fqdn, int port, int priority, int weight, List inetAddresses) { super(fqdn, port, inetAddresses); + StringUtils.requireNotNullOrEmpty(fqdn, "The FQDN must not be null"); if (weight < 0 || weight > 65535) throw new IllegalArgumentException( "DNS SRV records weight must be a 16-bit unsiged integer (i.e. between 0-65535. Weight was: " diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 61fe86a3b..2080c100a 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -593,6 +593,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } failedAddresses.add(hostAddress); } else { + StringUtils.requireNotNullOrEmpty(host, "Host of HostAddress " + hostAddress + " must not be null when using a Proxy"); final String hostAndPort = host + " at port " + port; LOGGER.finer("Trying to establish TCP connection via Proxy to " + hostAndPort); try { From b343b499b55421e9b808c875bfdb82c0fba28009 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 5 Jan 2017 09:29:31 +0100 Subject: [PATCH 03/15] MiniDNS resolver: Fix exception when there is only a A or AAAA RR W/System.err: java.lang.IllegalStateException: Can not perform operation because the DNS resolution was unsuccessful W/System.err: at de.measite.minidns.hla.ResolverResult.throwIseIfErrorResponse(ResolverResult.ja va:113) W/System.err: at de.measite.minidns.hla.ResolverResult.getAnswers(ResolverResult.java:56) W/System.err: at org.jivesoftware.smack.util.dns.minidns.MiniDnsResolver.lookupHostAddress0(Mini DnsResolver.java:130) W/System.err: at org.jivesoftware.smack.util.dns.DNSResolver.lookupHostAddress(DNSResolver.java: 52) W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.populateHostAddresses(AbstractXMP PConnection.java:612) W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPC onnection.java:555) W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection. java:885) W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.ja va:374) W/System.err: at com.example.bosleo.chatapp.ChatConnection.connect(ChatConnection.java:147) W/System.err: at com.example.bosleo.chatapp.ChatConnectionService.initConnection(ChatConnectionS ervice.java:82) W/System.err: at com.example.bosleo.chatapp.ChatConnectionService.access$100(ChatConnectionServi ce.java:20) W/System.err: at com.example.bosleo.chatapp.ChatConnectionService$1.run(ChatConnectionService.ja va:105) W/System.err: at java.lang.Thread.run(Thread.java:818) W/System.err: Caused by: de.measite.minidns.hla.ResolutionUnsuccessfulException: Asking for 192.168.2.128. IN AAAA yielded an error response NX_DOMAIN W/System.err: at de.measite.minidns.hla.ResolverResult.getResolutionUnsuccessfulException(Resolv erResult.java:89) W/System.err: at de.measite.minidns.hla.ResolverResult.throwIseIfErrorResponse(ResolverResult.ja va:111) W/System.err: ... 12 more --- .../util/dns/minidns/MiniDnsResolver.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/smack-resolver-minidns/src/main/java/org/jivesoftware/smack/util/dns/minidns/MiniDnsResolver.java b/smack-resolver-minidns/src/main/java/org/jivesoftware/smack/util/dns/minidns/MiniDnsResolver.java index b62bdcb71..ff5906ff7 100644 --- a/smack-resolver-minidns/src/main/java/org/jivesoftware/smack/util/dns/minidns/MiniDnsResolver.java +++ b/smack-resolver-minidns/src/main/java/org/jivesoftware/smack/util/dns/minidns/MiniDnsResolver.java @@ -20,8 +20,10 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Set; import org.jivesoftware.smack.ConnectionConfiguration.DnssecMode; import org.jivesoftware.smack.initializer.SmackInitializer; @@ -126,10 +128,28 @@ public class MiniDnsResolver extends DNSResolver implements SmackInitializer { return null; } - List inetAddresses = new ArrayList<>(aResult.getAnswers().size() - + aaaaResult.getAnswers().size()); + // TODO: Use ResolverResult.getAnswersOrEmptySet() once we updated MiniDNS. + Set aResults; + if (aResult.wasSuccessful()) { + aResults = aResult.getAnswers(); + } + else { + aResults = Collections.emptySet(); + } - for (A a : aResult.getAnswers()) { + // TODO: Use ResolverResult.getAnswersOrEmptySet() once we updated MiniDNS. + Set aaaaResults; + if (aaaaResult.wasSuccessful()) { + aaaaResults = aaaaResult.getAnswers(); + } + else { + aaaaResults = Collections.emptySet(); + } + + List inetAddresses = new ArrayList<>(aResults.size() + + aaaaResults.size()); + + for (A a : aResults) { InetAddress inetAddress; try { inetAddress = InetAddress.getByAddress(a.getIp()); @@ -139,7 +159,7 @@ public class MiniDnsResolver extends DNSResolver implements SmackInitializer { } inetAddresses.add(inetAddress); } - for (AAAA aaaa : aaaaResult.getAnswers()) { + for (AAAA aaaa : aaaaResults) { InetAddress inetAddress; try { inetAddress = InetAddress.getByAddress(name, aaaa.getIp()); From 24bbe63da1ed67dccfd10d514c063ca59cdb4ec0 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 6 Jan 2017 14:49:12 +0100 Subject: [PATCH 04/15] Minor code improvements in DNSutil --- .../src/main/java/org/jivesoftware/smack/util/DNSUtil.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/DNSUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/DNSUtil.java index 17ed2a46b..ebe709a06 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/DNSUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/DNSUtil.java @@ -250,14 +250,16 @@ public class DNSUtil { List bucket = buckets.get(priority); int bucketSize; while ((bucketSize = bucket.size()) > 0) { - int[] totals = new int[bucket.size()]; + int[] totals = new int[bucketSize]; int running_total = 0; int count = 0; int zeroWeight = 1; for (SRVRecord r : bucket) { - if (r.getWeight() > 0) + if (r.getWeight() > 0) { zeroWeight = 0; + break; + } } for (SRVRecord r : bucket) { From 7167a55f81d6f51db04ee739799813b1a280d835 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 6 Jan 2017 14:49:58 +0100 Subject: [PATCH 05/15] AccountManager: Don't fallback to disco#info if not authenticated --- .../jivesoftware/smackx/iqregister/AccountManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java index dd291013d..40d3c4572 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java @@ -340,7 +340,13 @@ public final class AccountManager extends Manager { return true; } - return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE); + // Fallback to disco#info only if this connection is authenticated, as otherwise we won't have an full JID and + // won't be able to do IQs. + if (connection.isAuthenticated()) { + return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE); + } + + return false; } /** From cff91f5a920f31cf6ee1e1eb085a490d109c8125 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 7 Jan 2017 10:37:50 +0100 Subject: [PATCH 06/15] Use correct element and namepsace in AccountManager.isSupported() --- .../org/jivesoftware/smackx/iqregister/AccountManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java index 40d3c4572..b10df9a81 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java @@ -335,7 +335,8 @@ public final class AccountManager extends Manager { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { XMPPConnection connection = connection(); - ExtensionElement extensionElement = connection.getFeature(Registration.ELEMENT, Registration.NAMESPACE); + ExtensionElement extensionElement = connection.getFeature(Registration.Feature.ELEMENT, + Registration.Feature.NAMESPACE); if (extensionElement != null) { return true; } From bfc14227caba62de16de59fef8a09dbbdb2ec10e Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 6 Jan 2017 15:03:28 +0100 Subject: [PATCH 07/15] Propagate stream errors on connect/login to the caller Before this, if there was a stream error response by the server to our stream open, that error response would only be handled in the reader thread, and the user would get a message like: "org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). While waiting for SASL mechanisms stream feature from server" while the server may actually sent something like Too many (2) failed authentications from this IP address (1xx.66.xx.xxx). The address will be unblocked at 04:24:00 06.01.2017 UTC It was necessary to change saslFeatureReceived from SmackException to XMPPException in order to return the StreamErrorException at this sync point. But this change in return required the introduction of a tlsHandled sync point for SmackException (which just acts as a wrapper for the various exception types that could occurn when establishing TLS). The tlsHandled sync point is marked successful even if no TLS was established in case none was required and/or if not supported by the server. --- .../smack/bosh/XMPPBOSHConnection.java | 3 +++ .../smack/AbstractXMPPConnection.java | 11 ++++++++-- .../jivesoftware/smack/DummyConnection.java | 1 + .../smack/tcp/XMPPTCPConnection.java | 22 ++++++++++++++----- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 1e48c72c4..62e5d34e0 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -198,6 +198,9 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { + getHost() + ":" + getPort() + "."; throw new SmackException(errorMessage); } + + tlsHandled.reportSuccess(); + saslFeatureReceived.reportSuccess(); } public boolean isSecureConnection() { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 18bf784bf..2a714d2d1 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -188,6 +188,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ protected Writer writer; + protected final SynchronizationPoint tlsHandled = new SynchronizationPoint<>(this, "establishing TLS"); + /** * Set to success if the last features stanza from the server has been parsed. A XMPP connection * handshake can invoke multiple features stanzas, e.g. when TLS is activated a second feature @@ -198,9 +200,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { AbstractXMPPConnection.this, "last stream features received from server"); /** - * Set to success if the sasl feature has been received. + * Set to success if the SASL feature has been received. */ - protected final SynchronizationPoint saslFeatureReceived = new SynchronizationPoint( + protected final SynchronizationPoint saslFeatureReceived = new SynchronizationPoint<>( AbstractXMPPConnection.this, "SASL mechanisms stream feature from server"); /** @@ -368,11 +370,15 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { saslAuthentication.init(); saslFeatureReceived.init(); lastFeaturesReceived.init(); + tlsHandled.init(); streamId = null; // Perform the actual connection to the XMPP service connectInternal(); + // TLS handled will be successful either if TLS was established, or if it was not mandatory. + tlsHandled.checkIfSuccessOrWaitOrThrow(); + // Wait with SASL auth until the SASL mechanisms have been received saslFeatureReceived.checkIfSuccessOrWaitOrThrow(); @@ -1407,6 +1413,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // Only proceed with SASL auth if TLS is disabled or if the server doesn't announce it if (!hasFeature(StartTls.ELEMENT, StartTls.NAMESPACE) || config.getSecurityMode() == SecurityMode.disabled) { + tlsHandled.reportSuccess(); saslFeatureReceived.reportSuccess(); } } diff --git a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java index 851311b3a..1bd11e119 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java @@ -91,6 +91,7 @@ public class DummyConnection extends AbstractXMPPConnection { protected void connectInternal() { connected = true; saslFeatureReceived.reportSuccess(); + tlsHandled.reportSuccess(); streamId = "dummy-" + new Random(new Date().getTime()).nextInt(); if (reconnect) { diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 2080c100a..4d67ad567 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -46,6 +46,7 @@ import org.jivesoftware.smack.packet.StreamOpen; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.StartTls; +import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.sasl.packet.SaslStreamElements; import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Challenge; import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure; @@ -923,13 +924,19 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { StartTls startTlsFeature = getFeature(StartTls.ELEMENT, StartTls.NAMESPACE); if (startTlsFeature != null) { if (startTlsFeature.required() && config.getSecurityMode() == SecurityMode.disabled) { - notifyConnectionError(new SecurityRequiredByServerException()); + SmackException smackException = new SecurityRequiredByServerException(); + tlsHandled.reportFailure(smackException); + notifyConnectionError(smackException); return; } if (config.getSecurityMode() != ConnectionConfiguration.SecurityMode.disabled) { sendNonza(new StartTls()); + } else { + tlsHandled.reportSuccess(); } + } else { + tlsHandled.reportSuccess(); } if (getSASLAuthentication().authenticationSuccessful()) { @@ -1028,7 +1035,13 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } break; case "error": - throw new StreamErrorException(PacketParserUtils.parseStreamError(parser)); + StreamError streamError = PacketParserUtils.parseStreamError(parser); + saslFeatureReceived.reportFailure(new StreamErrorException(streamError)); + // Mark the tlsHandled sync point as success, we will use the saslFeatureReceived sync + // point to report the error, which is checked immediately after tlsHandled in + // connectInternal(). + tlsHandled.reportSuccess(); + throw new StreamErrorException(streamError); case "features": parseFeatures(parser); break; @@ -1040,9 +1053,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { openStream(); } catch (Exception e) { - // We report any failure regarding TLS in the second stage of XMPP - // connection establishment, namely the SASL authentication - saslFeatureReceived.reportFailure(new SmackException(e)); + SmackException smackException = new SmackException(e); + tlsHandled.reportFailure(smackException); throw e; } break; From 51d3c3176638eb7e9e08e6facf71d589bc2ccb04 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 8 Jan 2017 22:58:23 +0100 Subject: [PATCH 08/15] Initialize Socket in TCP connection when proxy is used Thanks to Grigory Fedorov for reporting this. --- .../main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 1 + 1 file changed, 1 insertion(+) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 4d67ad567..92a2ba631 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -594,6 +594,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } failedAddresses.add(hostAddress); } else { + socket = socketFactory.createSocket(); StringUtils.requireNotNullOrEmpty(host, "Host of HostAddress " + hostAddress + " must not be null when using a Proxy"); final String hostAndPort = host + " at port " + port; LOGGER.finer("Trying to establish TCP connection via Proxy to " + hostAndPort); From b0fef6ffcbe18af78db93aa4b0d7e9fe24e90d15 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 9 Jan 2017 19:36:21 +0100 Subject: [PATCH 09/15] Ensure that populateHostAddressees() doesn't return a list with 'null' Thanks to Grigory Fedorov for reporting this. --- .../jivesoftware/smack/AbstractXMPPConnection.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 2a714d2d1..75ad70bca 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -602,7 +602,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { protected List hostAddresses; /** - * Populates {@link #hostAddresses} with at least one host address. + * Populates {@link #hostAddresses} with the resolved addresses or with the configured host address. If no host + * address was configured and all lookups failed, for example with NX_DOMAIN, then {@link #hostAddresses} will be + * populated with the empty list. * * @return a list of host addresses where DNS (SRV) RR resolution failed. */ @@ -616,14 +618,15 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { else if (config.host != null) { hostAddresses = new ArrayList(1); HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode()); - hostAddresses.add(hostAddress); + if (hostAddress != null) { + hostAddresses.add(hostAddress); + } } else { // N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode()); } - // If we reach this, then hostAddresses *must not* be empty, i.e. there is at least one host added, either the - // config.host one or the host representing the service name by DNSUtil - assert(!hostAddresses.isEmpty()); + // Either the populated host addresses are not empty *or* there must be at least one failed address. + assert(!hostAddresses.isEmpty() || !failedAddresses.isEmpty()); return failedAddresses; } From d47463a5332fc06ee87f5aac4bf378f9629368f1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 11 Jan 2017 19:35:55 +0100 Subject: [PATCH 10/15] Deprecate Chat API, introduce new Chat API Also add (From|To)TypeFilter and update/fix the documentation in a few places. --- documentation/extensions/index.md | 1 + documentation/extensions/xhtml.md | 23 +- documentation/gettingstarted.md | 20 +- documentation/messaging.md | 76 ++---- .../smack/filter/AbstractJidTypeFilter.java | 62 +++++ .../smack/filter/FromTypeFilter.java | 38 +++ .../smack/filter/ToTypeFilter.java | 40 +++ .../smackx/muclight/MultiUserChatLight.java | 8 +- .../org/jivesoftware/smack/chat2/Chat.java | 73 ++++++ .../jivesoftware/smack/chat2/ChatManager.java | 237 ++++++++++++++++++ .../chat2/IncomingChatMessageListener.java | 26 ++ .../chat2/OutgoingChatMessageListener.java | 26 ++ .../smack/chat2/package-info.java | 21 ++ .../smackx/chatstates/ChatStateListener.java | 5 +- .../smackx/chatstates/ChatStateManager.java | 22 +- .../smackx/muc/MultiUserChat.java | 9 +- .../org/jivesoftware/smack/chat/Chat.java | 2 + .../jivesoftware/smack/chat/ChatManager.java | 2 + .../smack/chat/ChatManagerListener.java | 1 + .../smack/chat/ChatMessageListener.java | 1 + .../smack/chat/ChatConnectionTest.java | 18 +- .../java/org/jivesoftware/smack/ChatTest.java | 14 +- 22 files changed, 612 insertions(+), 113 deletions(-) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/filter/AbstractJidTypeFilter.java create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/filter/FromTypeFilter.java create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/filter/ToTypeFilter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smack/chat2/Chat.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smack/chat2/ChatManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smack/chat2/IncomingChatMessageListener.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smack/chat2/OutgoingChatMessageListener.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smack/chat2/package-info.java diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md index 1cf51a067..481229840 100644 --- a/documentation/extensions/index.md +++ b/documentation/extensions/index.md @@ -69,6 +69,7 @@ Smack Extensions and currently supported XEPs of smack-extensions | XMPP Over BOSH | [XEP-0206](http://xmpp.org/extensions/xep-0206.html) | Use Bidirectional-streams Over Synchronous HTTP (BOSH) to transport XMPP stanzas. | | Attention | [XEP-0224](http://xmpp.org/extensions/xep-0224.html) | Getting attention of another user. | | Bits of Binary | [XEP-0231](http://xmpp.org/extensions/xep-0231.html) | Including or referring to small bits of binary data in an XML stanza. | +| Best Practices for Resource Locking | [XEP-0296](https://xmpp.org/extensions/xep-0296.html) | Specifies best practices to be followed by Jabber/XMPP clients about when to lock into, and unlock away from, resources. | | Last Message Correction | [XEP-0308](http://xmpp.org/extensions/xep-0308.html) | Provides a method for indicating that a message is a correction of the last sent message. | | [Group Chat Invitations](invitation.md) | n/a | Send invitations to other users to join a group chat room. | | [Jive Properties](properties.md) | n/a | TODO | diff --git a/documentation/extensions/xhtml.md b/documentation/extensions/xhtml.md index 62580bd97..a947e6ada 100644 --- a/documentation/extensions/xhtml.md +++ b/documentation/extensions/xhtml.md @@ -97,8 +97,8 @@ done. The last step is to send the message as you do with any other message. An XHTML message is like any regular message, therefore to send the message you can follow the usual steps you do in order to send a message. For example, -to send a message as part of a chat just use the message **#send(Message)** of -_**Chat**_ or you can use the message **#send(Stanza)** of +to send a message as part of a chat just use the message **#sendMessage(Message)** of +_**Chat**_ or you can use the message **#sendStanza(Stanza)** of _**XMPPConnection**_. **Example** @@ -142,19 +142,20 @@ XHTML bodies of any received message. ``` // Create a listener for the chat and display any XHTML content -PacketListener packetListener = new PacketListener() { -public void processStanza(Stanza stanza) { - Message message = (Message) stanza; +IncomingChatMessageListener listener = new IncomingChatMessageListener() { +public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { // Obtain the XHTML bodies of the message List bodies = XHTMLManager.getBodies(message); - if (bodies != null) { - // Display the bodies on the console - for (CharSequence body : bodies) { - System.out.println(body); - } + if (bodies == null) { + return; + + // Display the bodies on the console + for (CharSequence body : bodies) { + System.out.println(body); } +} }; -chat.addMessageListener(packetListener); +chatManager.addListener(listener); ``` Discover support for XHTML Messages diff --git a/documentation/gettingstarted.md b/documentation/gettingstarted.md index 98879bdaf..c006950e7 100644 --- a/documentation/gettingstarted.md +++ b/documentation/gettingstarted.md @@ -70,7 +70,7 @@ created, such as the ability to disable or require encryption. See Once you've created a connection, you should login with the `XMPPConnection.login()` method. Once you've logged in, you can being -chatting with other users by creating new `Chat` or `GroupChat` +chatting with other users by creating new `Chat` or `MultiUserChat` objects. Working with the Roster @@ -98,18 +98,18 @@ your presence to let people know you're unavailable and "out fishing": // Create a new presence. Pass in false to indicate we're unavailable._ Presence presence = new Presence(Presence.Type.unavailable); presence.setStatus("Gone fishing"); -// Send the packet (assume we have an XMPPConnection instance called "con"). +// Send the stanza (assume we have an XMPPConnection instance called "con"). con.sendStanza(presence); ``` -Smack provides two ways to read incoming packets: `PacketListener`, and -`PacketCollector`. Both use `StanzaFilter` instances to determine which -packets should be processed. A packet listener is used for event style -programming, while a packet collector has a result queue of packets that you -can do polling and blocking operations on. So, a packet listener is useful -when you want to take some action whenever a packet happens to come in, while -a packet collector is useful when you want to wait for a specific packet to -arrive. Packet collectors and listeners can be created using an Connection +Smack provides two ways to read incoming packets: `StanzaListener`, and +`StanzaCollector`. Both use `StanzaFilter` instances to determine which +stanzas should be processed. A stanza listener is used for event style +programming, while a stanza collector has a result queue of packets that you +can do polling and blocking operations on. So, a stanza listener is useful +when you want to take some action whenever a stanza happens to come in, while +a stanza collector is useful when you want to wait for a specific packet to +arrive. Stanza collectors and listeners can be created using an Connection instance. Copyright (C) Jive Software 2002-2008 diff --git a/documentation/messaging.md b/documentation/messaging.md index 666bbecef..72302ef61 100644 --- a/documentation/messaging.md +++ b/documentation/messaging.md @@ -6,7 +6,7 @@ Messaging using Chats Sending messages back and forth is at the core of instant messaging. Although individual messages can be sent and received as packets, it's generally easier to treat the string of messages as a chat using the -`org.jivesoftware.smack.Chat` class. +`org.jivesoftware.smack.chat2.Chat` class. Chat ---- @@ -17,80 +17,44 @@ and then send them a text message: ``` // Assume we've created an XMPPConnection name "connection"._ -ChatManager chatmanager = ChatManager.getInstanceFor(connection); -Chat newChat = chatmanager.createChat("jsmith@jivesoftware.com", new MessageListener() { - public void processMessage(Chat chat, Message message) { - System.out.println("Received message: " + message); - } +ChatManager chatManager = ChatManager.getInstanceFor(connection); +chatManager.addListener(new IncomingChatMessageListener() { + @Override + void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { + System.out.println("New message from " + from ": " + message.getBody()); + } }); - -try { - newChat.sendMessage("Howdy!"); -} -catch (XMPPException e) { - System.out.println("Error Delivering block"); +EntityBareJid jid = JidCreate.entityBareFrom("jsmith@jivesoftware.com"); +Chat chat = chatManager.chatWith(jid); +chat.sendMessage("Howdy!"); } ``` The `Chat.sendMessage(String)` method is a convenience method that creates a Message object, sets the body using the String parameter, then sends the message. In the case that you wish to set additional values on a Message -before sending it, use the `Chat.createMessage()` and -`Chat.sendMessage(Message)` methods, as in the following code snippet: +before sending it, use +`Chat.sendMessage(Message)` method, as in the following code snippet: ``` Message newMessage = new Message(); newMessage.setBody("Howdy!"); // Additional modifications to the message Stanza. JivePropertiesManager.addProperty(newMessage, "favoriteColor", "red"); -newChat.sendMessage(newMessage); +chat.sendMessage(newMessage); ``` -You'll also notice in the example above that we specified a MessageListener -when creating a chat. The listener is notified any time a new message arrives -from the other user in the chat. The following code snippet uses the listener +You'll also notice in the example above that we specified an IncomingChatMessageListener. +The listener is notified any time a new chat message arrives. +The following code snippet uses the listener as a parrot-bot -- it echoes back everything the other user types. ``` -// Assume a MessageListener we've setup with a chat._ - -public void processMessage(Chat chat, Message message) { - // Send back the same text the other user sent us._ - chat.sendMessage(message.getBody()); +// Assume a IncomingChatMessageListener we've setup with a ChatManager +public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) { + // Send back the same text the other user sent us. + chat.sendMessage(message.getBody()); } ``` -Incoming Chat -------------- - -When chats are prompted by another user, the setup is slightly different since -you are receiving a chat message first. Instead of explicitly creating a chat -to send messages, you need to register to handle newly created Chat instances -when the ChatManager creates them. The ChatManager will already find a -matching chat (by thread id) and if none exists, then it will create a new one -that does match. To get this new chat, you have to register to be notified -when it happens. You can register a message listener to receive all future -messages as part of this handler. - -``` -// Assume we've created an XMPPConnection name "connection"._ -ChatManager chatManager = ChatManager.getInstanceFor(connection); -chatManager.addChatListener( - new ChatManagerListener() { - @Override - public void chatCreated(Chat chat, boolean createdLocally) - { - if (!createdLocally) - chat.addMessageListener(new MyNewMessageListener());; - } - }); -``` - -In addition to thread based chat messages, there are some clients that do not -send a thread id as part of the chat. To handle this scenario, Smack will -attempt match the incoming messages to the best fit existing chat, based on -the JID. It will attempt to find a chat with the same full JID, failing that, -it will try the base JID. If no existing chat to the user can found, then a -new one is created. - Copyright (C) Jive Software 2002-2008 diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/AbstractJidTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/AbstractJidTypeFilter.java new file mode 100644 index 000000000..e091d6786 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/AbstractJidTypeFilter.java @@ -0,0 +1,62 @@ +/** + * + * Copyright 2017 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.smack.filter; + +import org.jivesoftware.smack.packet.Stanza; +import org.jxmpp.jid.Jid; + +public abstract class AbstractJidTypeFilter implements StanzaFilter { + + protected enum JidType { + entityFull, + entityBare, + domainFull, + domainBare, + ; + } + + private final JidType jidType; + + protected AbstractJidTypeFilter(JidType jidType) { + this.jidType = jidType; + } + + protected abstract Jid getJidToInspect(Stanza stanza); + + @Override + public final boolean accept(Stanza stanza) { + final Jid jid = stanza.getFrom(); + + if (jid == null) { + return false; + } + + switch (jidType) { + case entityFull: + return jid.isEntityFullJid(); + case entityBare: + return jid.isEntityBareJid(); + case domainFull: + return jid.isDomainFullJid(); + case domainBare: + return jid.isDomainBareJid(); + default: + throw new AssertionError(); + } + } + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/FromTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/FromTypeFilter.java new file mode 100644 index 000000000..1948d5f84 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/FromTypeFilter.java @@ -0,0 +1,38 @@ +/** + * + * Copyright 2017 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.smack.filter; + +import org.jivesoftware.smack.packet.Stanza; +import org.jxmpp.jid.Jid; + +public final class FromTypeFilter extends AbstractJidTypeFilter { + + public static final FromTypeFilter ENTITY_FULL_JID = new FromTypeFilter(JidType.entityFull); + public static final FromTypeFilter ENTITY_BARE_JID = new FromTypeFilter(JidType.entityBare); + public static final FromTypeFilter DOMAIN_FULL_JID = new FromTypeFilter(JidType.domainFull); + public static final FromTypeFilter DOMAIN_BARE_JID = new FromTypeFilter(JidType.domainBare); + + private FromTypeFilter(JidType jidType) { + super(jidType); + } + + @Override + protected Jid getJidToInspect(Stanza stanza) { + return stanza.getFrom(); + } + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/ToTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/ToTypeFilter.java new file mode 100644 index 000000000..8d8059627 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/ToTypeFilter.java @@ -0,0 +1,40 @@ +/** + * + * Copyright 2017 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.smack.filter; + +import org.jivesoftware.smack.packet.Stanza; +import org.jxmpp.jid.Jid; + +public final class ToTypeFilter extends AbstractJidTypeFilter { + + public static final ToTypeFilter ENTITY_FULL_JID = new ToTypeFilter(JidType.entityFull); + public static final ToTypeFilter ENTITY_BARE_JID = new ToTypeFilter(JidType.entityBare); + public static final ToTypeFilter DOMAIN_FULL_JID = new ToTypeFilter(JidType.domainFull); + public static final ToTypeFilter DOMAIN_BARE_JID = new ToTypeFilter(JidType.domainBare); + + public static final StanzaFilter ENTITY_FULL_OR_BARE_JID = new OrFilter(ENTITY_FULL_JID, ENTITY_BARE_JID); + + private ToTypeFilter(JidType jidType) { + super(jidType); + } + + @Override + protected Jid getJidToInspect(Stanza stanza) { + return stanza.getTo(); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/muclight/MultiUserChatLight.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/muclight/MultiUserChatLight.java index a2ee01441..e14f9df11 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/muclight/MultiUserChatLight.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/muclight/MultiUserChatLight.java @@ -28,8 +28,6 @@ import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException.XMPPErrorException; -import org.jivesoftware.smack.chat.Chat; -import org.jivesoftware.smack.chat.ChatManager; import org.jivesoftware.smack.chat.ChatMessageListener; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.FromMatchesFilter; @@ -146,8 +144,10 @@ public class MultiUserChatLight { * for the newly created chat. * @return new Chat for sending private messages to a given room occupant. */ - public Chat createPrivateChat(EntityJid occupant, ChatMessageListener listener) { - return ChatManager.getInstanceFor(connection).createChat(occupant, listener); + @Deprecated + // Do not re-use Chat API, which was designed for XMPP-IM 1:1 chats and not MUClight private chats. + public org.jivesoftware.smack.chat.Chat createPrivateChat(EntityJid occupant, ChatMessageListener listener) { + return org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection).createChat(occupant, listener); } /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/Chat.java b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/Chat.java new file mode 100644 index 000000000..f8b9edbd6 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/Chat.java @@ -0,0 +1,73 @@ +/** + * + * Copyright 2017 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.smack.chat2; + +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Presence; +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; +import org.jxmpp.jid.Jid; + +public final class Chat extends Manager { + + private final EntityBareJid jid; + + volatile EntityFullJid lockedResource; + + Presence lastPresenceOfLockedResource; + + Chat(final XMPPConnection connection, EntityBareJid jid) { + super(connection); + this.jid = jid; + } + + public void send(CharSequence message) throws NotConnectedException, InterruptedException { + Message stanza = new Message(); + stanza.setBody(message); + send(stanza); + } + + public void send(Message message) throws NotConnectedException, InterruptedException { + switch (message.getType()) { + case normal: + case chat: + break; + default: + throw new IllegalArgumentException("Message must be of type 'normal' or 'chat'"); + } + + Jid to = lockedResource; + if (to == null) { + to = jid; + } + message.setTo(to); + + connection().sendStanza(message); + } + + public EntityBareJid getXmppAddressOfChatPartner() { + return jid; + } + + void unlockResource() { + lockedResource = null; + lastPresenceOfLockedResource = null; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/ChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/ChatManager.java new file mode 100644 index 000000000..b19dd290f --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/ChatManager.java @@ -0,0 +1,237 @@ +/** + * + * Copyright 2017 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.smack.chat2; + +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.StanzaListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromTypeFilter; +import org.jivesoftware.smack.filter.MessageTypeFilter; +import org.jivesoftware.smack.filter.MessageWithBodiesFilter; +import org.jivesoftware.smack.filter.OrFilter; +import org.jivesoftware.smack.filter.StanzaExtensionFilter; +import org.jivesoftware.smack.filter.StanzaFilter; +import org.jivesoftware.smack.filter.ToTypeFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.roster.AbstractRosterListener; +import org.jivesoftware.smack.roster.Roster; +import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension; +import org.jxmpp.jid.EntityBareJid; +import org.jxmpp.jid.EntityFullJid; +import org.jxmpp.jid.Jid; + +/** + * A chat manager for 1:1 XMPP instant messaging chats. + *

+ * This manager and the according {@link Chat} API implement "Resource Locking" (XEP-0296). Support for Carbon Copies + * (XEP-0280) will be added once the XEP has progressed from experimental. + *

+ * + * @see
XEP-0296: Best Practices for Resource Locking + */ +public final class ChatManager extends Manager { + + private static final Map INSTANCES = new WeakHashMap<>(); + + public static synchronized ChatManager getInstanceFor(XMPPConnection connection) { + ChatManager chatManager = INSTANCES.get(connection); + if (chatManager == null) { + chatManager = new ChatManager(connection); + INSTANCES.put(connection, chatManager); + } + return chatManager; + } + + // @FORMATTER:OFF + private static final StanzaFilter MESSAGE_FILTER = new AndFilter( + MessageTypeFilter.NORMAL_OR_CHAT, + new OrFilter(MessageWithBodiesFilter.INSTANCE), new StanzaExtensionFilter(XHTMLExtension.ELEMENT, XHTMLExtension.NAMESPACE) + ); + + private static final StanzaFilter OUTGOING_MESSAGE_FILTER = new AndFilter( + MESSAGE_FILTER, + ToTypeFilter.ENTITY_FULL_OR_BARE_JID + ); + + private static final StanzaFilter INCOMING_MESSAGE_FILTER = new AndFilter( + MESSAGE_FILTER, + FromTypeFilter.ENTITY_FULL_JID + ); + // @FORMATTER:ON + + private final Map chats = new ConcurrentHashMap<>(); + + private final Set incomingListeners = new CopyOnWriteArraySet<>(); + + private final Set outgoingListeners = new CopyOnWriteArraySet<>(); + + private boolean xhtmlIm; + + private ChatManager(final XMPPConnection connection) { + super(connection); + connection.addSyncStanzaListener(new StanzaListener() { + @Override + public void processStanza(Stanza stanza) { + Message message = (Message) stanza; + if (!shouldAcceptMessage(message)) { + return; + } + + final Jid from = message.getFrom(); + final EntityFullJid fullFrom = from.asEntityFullJidOrThrow(); + final EntityBareJid bareFrom = fullFrom.asEntityBareJid(); + final Chat chat = chatWith(bareFrom); + chat.lockedResource = fullFrom; + + for (IncomingChatMessageListener listener : incomingListeners) { + listener.newIncomingMessage(bareFrom, message, chat); + } + } + }, INCOMING_MESSAGE_FILTER); + + connection.addPacketInterceptor(new StanzaListener() { + @Override + public void processStanza(Stanza stanza) throws NotConnectedException, InterruptedException { + Message message = (Message) stanza; + if (!shouldAcceptMessage(message)) { + return; + } + + final EntityBareJid to = message.getTo().asEntityBareJidOrThrow(); + final Chat chat = chatWith(to); + + for (OutgoingChatMessageListener listener : outgoingListeners) { + listener.newOutgoingMessage(to, message, chat); + } + } + }, OUTGOING_MESSAGE_FILTER); + + Roster roster = Roster.getInstanceFor(connection); + roster.addRosterListener(new AbstractRosterListener() { + @Override + public void presenceChanged(Presence presence) { + final Jid from = presence.getFrom(); + final EntityBareJid bareFrom = from.asEntityBareJidIfPossible(); + if (bareFrom == null) { + return; + } + + final Chat chat = chats.get(bareFrom); + if (chat == null) { + return; + } + + if (chat.lockedResource == null) { + // According to XEP-0296, no action is required for resource locking upon receiving a presence if no + // resource is currently locked. + return; + } + + final EntityFullJid fullFrom = from.asEntityFullJidIfPossible(); + if (!chat.lockedResource.equals(fullFrom)) { + return; + } + + if (chat.lastPresenceOfLockedResource == null) { + // We have no last known presence from the locked resource. + chat.lastPresenceOfLockedResource = presence; + return; + } + + if (chat.lastPresenceOfLockedResource.getMode() != presence.getMode() + || chat.lastPresenceOfLockedResource.getType() != presence.getType()) { + chat.unlockResource(); + } + } + }); + } + + private boolean shouldAcceptMessage(Message message) { + if (!message.getBodies().isEmpty()) { + return true; + } + + // Message has no XMPP-IM bodies, abort here if xhtmlIm is not enabled. + if (!xhtmlIm) { + return false; + } + + XHTMLExtension xhtmlExtension = XHTMLExtension.from(message); + if (xhtmlExtension == null) { + // Message has no XHTML-IM extension, abort. + return false; + } + return true; + } + + public boolean addListener(IncomingChatMessageListener listener) { + return incomingListeners.add(listener); + } + + public boolean removeListener(IncomingChatMessageListener listener) { + return incomingListeners.remove(listener); + } + + public boolean addListener(OutgoingChatMessageListener listener) { + return outgoingListeners.add(listener); + } + + public boolean removeOutoingLIstener(OutgoingChatMessageListener listener) { + return outgoingListeners.remove(listener); + } + + /** + * Start a new or retrieve the existing chat with jid. + * + * @param jid the XMPP address of the other entity to chat with. + * @return the Chat API for the given XMPP address. + */ + public Chat chatWith(EntityBareJid jid) { + Chat chat = chats.get(jid); + if (chat == null) { + synchronized (chats) { + // Double-checked locking. + chat = chats.get(jid); + if (chat != null) { + return chat; + } + chat = new Chat(connection(), jid); + chats.put(jid, chat); + } + } + return chat; + } + + /** + * Also notify about messages containing XHTML-IM. + * + * @param xhtmlIm + */ + public void setXhmtlImEnabled(boolean xhtmlIm) { + this.xhtmlIm = xhtmlIm; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/IncomingChatMessageListener.java b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/IncomingChatMessageListener.java new file mode 100644 index 000000000..a59e7b057 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/IncomingChatMessageListener.java @@ -0,0 +1,26 @@ +/** + * + * Copyright 2017 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.smack.chat2; + +import org.jivesoftware.smack.packet.Message; +import org.jxmpp.jid.EntityBareJid; + +public interface IncomingChatMessageListener { + + void newIncomingMessage(EntityBareJid from, Message message, Chat chat); + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/OutgoingChatMessageListener.java b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/OutgoingChatMessageListener.java new file mode 100644 index 000000000..74660cb56 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/OutgoingChatMessageListener.java @@ -0,0 +1,26 @@ +/** + * + * Copyright 2017 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.smack.chat2; + +import org.jivesoftware.smack.packet.Message; +import org.jxmpp.jid.EntityBareJid; + +public interface OutgoingChatMessageListener { + + void newOutgoingMessage(EntityBareJid to, Message message, Chat chat); + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/package-info.java new file mode 100644 index 000000000..e189afa10 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smack/chat2/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright 2017 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 new improved API for 1:1 chats. + */ +package org.jivesoftware.smack.chat2; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java index d0c671b95..c670f55ac 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateListener.java @@ -17,7 +17,6 @@ package org.jivesoftware.smackx.chatstates; -import org.jivesoftware.smack.chat.Chat; import org.jivesoftware.smack.chat.ChatMessageListener; import org.jivesoftware.smack.packet.Message; @@ -35,5 +34,7 @@ public interface ChatStateListener extends ChatMessageListener { * @param state the new state of the participant. * @param message the message carrying the chat state. */ - void stateChanged(Chat chat, ChatState state, Message message); + // TODO Migrate to new chat2 API on Smack 4.3. + @SuppressWarnings("deprecation") + void stateChanged(org.jivesoftware.smack.chat.Chat chat, ChatState state, Message message); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java index ec15c1910..212ad0918 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java @@ -24,8 +24,6 @@ import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.Manager; -import org.jivesoftware.smack.chat.Chat; -import org.jivesoftware.smack.chat.ChatManager; import org.jivesoftware.smack.chat.ChatManagerListener; import org.jivesoftware.smack.chat.ChatMessageListener; import org.jivesoftware.smack.filter.NotFilter; @@ -49,6 +47,8 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; * @see org.jivesoftware.smackx.chatstates.ChatState * @see org.jivesoftware.smackx.chatstates.packet.ChatStateExtension */ +// TODO Migrate to new chat2 API on Smack 4.3. +@SuppressWarnings("deprecation") public final class ChatStateManager extends Manager { public static final String NAMESPACE = "http://jabber.org/protocol/chatstates"; @@ -79,13 +79,13 @@ public final class ChatStateManager extends Manager { /** * Maps chat to last chat state. */ - private final Map chatStates = new WeakHashMap(); + private final Map chatStates = new WeakHashMap<>(); - private final ChatManager chatManager; + private final org.jivesoftware.smack.chat.ChatManager chatManager; private ChatStateManager(XMPPConnection connection) { super(connection); - chatManager = ChatManager.getInstanceFor(connection); + chatManager = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection); chatManager.addOutgoingMessageInterceptor(outgoingInterceptor, filter); chatManager.addChatListener(incomingInterceptor); @@ -104,7 +104,7 @@ public final class ChatStateManager extends Manager { * @throws NotConnectedException * @throws InterruptedException */ - public void setCurrentState(ChatState newState, Chat chat) throws NotConnectedException, InterruptedException { + public void setCurrentState(ChatState newState, org.jivesoftware.smack.chat.Chat chat) throws NotConnectedException, InterruptedException { if(chat == null || newState == null) { throw new IllegalArgumentException("Arguments cannot be null."); } @@ -133,7 +133,7 @@ public final class ChatStateManager extends Manager { return connection().hashCode(); } - private synchronized boolean updateChatState(Chat chat, ChatState newState) { + private synchronized boolean updateChatState(org.jivesoftware.smack.chat.Chat chat, ChatState newState) { ChatState lastChatState = chatStates.get(chat); if (lastChatState != newState) { chatStates.put(chat, newState); @@ -142,7 +142,7 @@ public final class ChatStateManager extends Manager { return false; } - private static void fireNewChatState(Chat chat, ChatState state, Message message) { + private static void fireNewChatState(org.jivesoftware.smack.chat.Chat chat, ChatState state, Message message) { for (ChatMessageListener listener : chat.getListeners()) { if (listener instanceof ChatStateListener) { ((ChatStateListener) listener).stateChanged(chat, state, message); @@ -154,7 +154,7 @@ public final class ChatStateManager extends Manager { @Override public void processMessage(Message message) { - Chat chat = chatManager.getThreadChat(message.getThread()); + org.jivesoftware.smack.chat.Chat chat = chatManager.getThreadChat(message.getThread()); if (chat == null) { return; } @@ -166,11 +166,11 @@ public final class ChatStateManager extends Manager { private class IncomingMessageInterceptor implements ChatManagerListener, ChatMessageListener { - public void chatCreated(final Chat chat, boolean createdLocally) { + public void chatCreated(final org.jivesoftware.smack.chat.Chat chat, boolean createdLocally) { chat.addMessageListener(this); } - public void processMessage(Chat chat, Message message) { + public void processMessage(org.jivesoftware.smack.chat.Chat chat, Message message) { ExtensionElement extension = message.getExtension(NAMESPACE); if (extension == null) { return; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index d4d0d1e84..b47cc311d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -37,8 +37,6 @@ import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException.XMPPErrorException; -import org.jivesoftware.smack.chat.Chat; -import org.jivesoftware.smack.chat.ChatManager; import org.jivesoftware.smack.chat.ChatMessageListener; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.FromMatchesFilter; @@ -1847,8 +1845,11 @@ public class MultiUserChat { * created chat. * @return new Chat for sending private messages to a given room occupant. */ - public Chat createPrivateChat(EntityFullJid occupant, ChatMessageListener listener) { - return ChatManager.getInstanceFor(connection).createChat(occupant, listener); + // TODO This should be made new not using chat.Chat. Private MUC chats are different from XMPP-IM 1:1 chats in to many ways. + // API sketch: PrivateMucChat createPrivateChat(Resourcepart nick) + @SuppressWarnings("deprecation") + public org.jivesoftware.smack.chat.Chat createPrivateChat(EntityFullJid occupant, ChatMessageListener listener) { + return org.jivesoftware.smack.chat.ChatManager.getInstanceFor(connection).createChat(occupant, listener); } /** diff --git a/smack-im/src/main/java/org/jivesoftware/smack/chat/Chat.java b/smack-im/src/main/java/org/jivesoftware/smack/chat/Chat.java index 0a463b261..5a9b6c97e 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/chat/Chat.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/chat/Chat.java @@ -36,7 +36,9 @@ import java.util.concurrent.CopyOnWriteArraySet; * sender. * * @author Matt Tucker + * @deprecated use org.jivesoftware.smack.chat2.Chat from smack-extensions instead. */ +@Deprecated public class Chat { private ChatManager chatManager; diff --git a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManager.java b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManager.java index 683a59e63..5c59136e9 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManager.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManager.java @@ -52,7 +52,9 @@ import org.jxmpp.jid.EntityJid; * made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}. * * @author Alexander Wenckus + * @deprecated use org.jivesoftware.smack.chat2.ChatManager from smack-extensions instead. */ +@Deprecated public final class ChatManager extends Manager{ private static final Logger LOGGER = Logger.getLogger(ChatManager.class.getName()); diff --git a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManagerListener.java b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManagerListener.java index eaa706810..73b12cdc9 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManagerListener.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManagerListener.java @@ -30,5 +30,6 @@ public interface ChatManagerListener { * @param chat the chat that was created. * @param createdLocally true if the chat was created by the local user and false if it wasn't. */ + @SuppressWarnings("deprecation") void chatCreated(Chat chat, boolean createdLocally); } diff --git a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatMessageListener.java b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatMessageListener.java index 4ca62bbb0..a0396540f 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatMessageListener.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/chat/ChatMessageListener.java @@ -20,5 +20,6 @@ package org.jivesoftware.smack.chat; import org.jivesoftware.smack.packet.Message; public interface ChatMessageListener { + @SuppressWarnings("deprecation") void processMessage(Chat chat, Message message); } diff --git a/smack-im/src/test/java/org/jivesoftware/smack/chat/ChatConnectionTest.java b/smack-im/src/test/java/org/jivesoftware/smack/chat/ChatConnectionTest.java index 1fe9004b3..1c4d8a950 100644 --- a/smack-im/src/test/java/org/jivesoftware/smack/chat/ChatConnectionTest.java +++ b/smack-im/src/test/java/org/jivesoftware/smack/chat/ChatConnectionTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.jivesoftware.smack.DummyConnection; -import org.jivesoftware.smack.chat.ChatManager.MatchMode; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message.Type; import org.jivesoftware.smack.packet.Stanza; @@ -35,6 +34,7 @@ import org.junit.Test; import org.jxmpp.jid.Jid; import org.jxmpp.jid.JidTestUtil; +@SuppressWarnings("deprecation") public class ChatConnectionTest { private DummyConnection dc; @@ -46,7 +46,7 @@ public class ChatConnectionTest { public void setUp() throws Exception { // Defaults ChatManager.setDefaultIsNormalIncluded(true); - ChatManager.setDefaultMatchMode(MatchMode.BARE_JID); + ChatManager.setDefaultMatchMode(ChatManager.MatchMode.BARE_JID); dc = DummyConnection.newConnectedDummyConnection(); cm = ChatManager.getInstanceFor(dc); @@ -77,14 +77,14 @@ public class ChatConnectionTest { @Test public void validateDefaultSetMatchModeNone() { - ChatManager.setDefaultMatchMode(MatchMode.NONE); - assertEquals(MatchMode.NONE, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode()); + ChatManager.setDefaultMatchMode(ChatManager.MatchMode.NONE); + assertEquals(ChatManager.MatchMode.NONE, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode()); } @Test public void validateDefaultSetMatchModeEntityBareJid() { - ChatManager.setDefaultMatchMode(MatchMode.BARE_JID); - assertEquals(MatchMode.BARE_JID, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode()); + ChatManager.setDefaultMatchMode(ChatManager.MatchMode.BARE_JID); + assertEquals(ChatManager.MatchMode.BARE_JID, ChatManager.getInstanceFor(new DummyConnection()).getMatchMode()); } @Test @@ -138,7 +138,7 @@ public class ChatConnectionTest { // No thread behaviour @Test public void chatMatchedOnJIDWhenNoThreadBareMode() { - // MatchMode.BARE_JID is the default, so setting required. + // ChatManager.MatchMode.BARE_JID is the default, so setting required. TestMessageListener msgListener = new TestMessageListener(); TestChatManagerListener listener = new TestChatManagerListener(msgListener); cm.addChatListener(listener); @@ -162,7 +162,7 @@ public class ChatConnectionTest { public void chatMatchedOnJIDWhenNoThreadJidMode() { TestMessageListener msgListener = new TestMessageListener(); TestChatManagerListener listener = new TestChatManagerListener(msgListener); - cm.setMatchMode(MatchMode.SUPPLIED_JID); + cm.setMatchMode(ChatManager.MatchMode.SUPPLIED_JID); cm.addChatListener(listener); Stanza incomingChat = createChatPacket(null, true); processServerMessage(incomingChat); @@ -188,7 +188,7 @@ public class ChatConnectionTest { public void chatMatchedOnJIDWhenNoThreadNoneMode() { TestMessageListener msgListener = new TestMessageListener(); TestChatManagerListener listener = new TestChatManagerListener(msgListener); - cm.setMatchMode(MatchMode.NONE); + cm.setMatchMode(ChatManager.MatchMode.NONE); cm.addChatListener(listener); Stanza incomingChat = createChatPacket(null, true); processServerMessage(incomingChat); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java index 1a79e0a7b..6d068d88a 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java @@ -31,8 +31,6 @@ import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; import org.jivesoftware.smack.SmackException.NotConnectedException; -import org.jivesoftware.smack.chat.Chat; -import org.jivesoftware.smack.chat.ChatManager; import org.jivesoftware.smack.chat.ChatManagerListener; import org.jivesoftware.smack.filter.ThreadFilter; import org.jivesoftware.smack.packet.Message; @@ -46,12 +44,14 @@ import org.jxmpp.stringprep.XmppStringprepException; */ public class ChatTest extends AbstractSmackIntegrationTest { - private final ChatManager chatManagerOne; + @SuppressWarnings("deprecation") + private final org.jivesoftware.smack.chat.ChatManager chatManagerOne; private boolean invoked; + @SuppressWarnings("deprecation") public ChatTest(SmackIntegrationTestEnvironment environment) { super(environment); - chatManagerOne = ChatManager.getInstanceFor(conOne); + chatManagerOne = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(conOne); } @BeforeClass @@ -64,9 +64,10 @@ public class ChatTest extends AbstractSmackIntegrationTest { JivePropertiesManager.setJavaObjectEnabled(false); } + @SuppressWarnings("deprecation") @SmackIntegrationTest public void testProperties() throws XmppStringprepException, NotConnectedException, Exception { - Chat newChat = chatManagerOne.createChat(conTwo.getUser()); + org.jivesoftware.smack.chat.Chat newChat = chatManagerOne.createChat(conTwo.getUser()); StanzaCollector collector = conTwo.createStanzaCollector(new ThreadFilter(newChat.getThreadID())); Message msg = new Message(); @@ -112,12 +113,13 @@ public class ChatTest extends AbstractSmackIntegrationTest { getProperty(msg2, "birthdate")); } + @SuppressWarnings("deprecation") @SmackIntegrationTest public void chatManagerTest() { ChatManagerListener listener = new ChatManagerListener() { @Override - public void chatCreated(Chat chat, boolean createdLocally) { + public void chatCreated(org.jivesoftware.smack.chat.Chat chat, boolean createdLocally) { invoked = true; } From 9d8caf0563554559f6b5bf50b3bd43c030307e34 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 12 Jan 2017 12:48:07 +0100 Subject: [PATCH 11/15] Fix "XEP-0323: IoT - Sensor Data" namespace --- .../org/jivesoftware/smackx/iot/data/element/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/Constants.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/Constants.java index 5efe5a058..68ed34f20 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/Constants.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/data/element/Constants.java @@ -18,6 +18,6 @@ package org.jivesoftware.smackx.iot.data.element; public class Constants { - public static final String IOT_SENSORDATA_NAMESPACE = "urn:xmpp:iot:data"; + public static final String IOT_SENSORDATA_NAMESPACE = "urn:xmpp:iot:sensordata"; } From f31cc6e043410d9b81d969622354261751033d1e Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 12 Jan 2017 13:39:11 +0100 Subject: [PATCH 12/15] Fix IllegalArgumentException on DNS lookup if XMPP domain is wrong Fixes the following exception thrown if the user had entered a non-existend XMPP domain: java.lang.IllegalArgumentException: Must provide at least one InetAddress at org.jivesoftware.smack.util.dns.HostAddress.(HostAddress.java:55) at org.jivesoftware.smack.util.dns.DNSResolver.lookupHostAddress(DNSResolver.java: 56) at org.jivesoftware.smack.util.DNSUtil.resolveDomain(DNSUtil.java:209) at org.jivesoftware.smack.util.DNSUtil.resolveXMPPServiceDomain(DNSUtil.java:136) at org.jivesoftware.smack.AbstractXMPPConnection.populateHostAddresses(AbstractXMP PConnection.java:626) at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPC onnection.java:556) at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection. java:888) at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.ja va:377) Thanks to Grigory Fedorov for reporting. --- .../java/org/jivesoftware/smack/util/dns/DNSResolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/DNSResolver.java b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/DNSResolver.java index dde188959..79de3e08a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/dns/DNSResolver.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/dns/DNSResolver.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2016 Florian Schmaus + * Copyright 2013-2017 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ public abstract class DNSResolver { public final HostAddress lookupHostAddress(String name, int port, List failedAddresses, DnssecMode dnssecMode) { checkIfDnssecRequestedAndSupported(dnssecMode); List inetAddresses = lookupHostAddress0(name, failedAddresses, dnssecMode); - if (inetAddresses == null) { + if (inetAddresses == null || inetAddresses.isEmpty()) { return null; } return new HostAddress(name, port, inetAddresses); From b5415fe841ab452bf967515958aba618583792d1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 12 Jan 2017 13:40:55 +0100 Subject: [PATCH 13/15] Don't wait the reply timeout in OfflineMessageManager.getMessages(List) for the last message. We now count the number of messages we want to retrieve, and don't wait for another message if we have already received all. Thanks to King Jeong Hun for reporting this. --- .../jivesoftware/smackx/offline/OfflineMessageManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/offline/OfflineMessageManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/offline/OfflineMessageManager.java index 69a3ec987..7afe302ec 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/offline/OfflineMessageManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/offline/OfflineMessageManager.java @@ -158,12 +158,14 @@ public class OfflineMessageManager { return nodes.contains(info.getNode()); } }); + int pendingNodes = nodes.size(); StanzaCollector messageCollector = connection.createStanzaCollector(messageFilter); try { connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); // Collect the received offline messages Message message = messageCollector.nextResult(); - while (message != null) { + while (message != null && pendingNodes > 0) { + pendingNodes--; messages.add(message); message = messageCollector.nextResult(); } From 7c46f58c806eb179608c3bb662b8cfbcc7a6cc63 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 12 Jan 2017 20:57:19 +0100 Subject: [PATCH 14/15] =?UTF-8?q?Rename=20"PacketReplyTimeout"=20=E2=86=92?= =?UTF-8?q?=20"ReplyTimeout"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../smack/bosh/XMPPBOSHConnection.java | 2 +- .../smack/AbstractXMPPConnection.java | 28 +++++++++++++------ .../smack/SASLAuthentication.java | 2 +- .../smack/SmackConfiguration.java | 26 ++++++++++++++++- .../jivesoftware/smack/SmackException.java | 4 +-- .../jivesoftware/smack/StanzaCollector.java | 4 +-- .../smack/SynchronizationPoint.java | 2 +- .../jivesoftware/smack/XMPPConnection.java | 20 +++++++++++++ .../smack/SmackConfigurationTest.java | 4 +-- .../smackx/filetransfer/StreamNegotiator.java | 2 +- .../smackx/muc/MultiUserChat.java | 2 +- .../jivesoftware/smackx/ping/PingManager.java | 4 +-- .../jivesoftware/smackx/ping/PingTest.java | 2 +- .../smackx/pubsub/ConfigureFormTest.java | 2 +- .../org/jivesoftware/smack/roster/Roster.java | 2 +- .../jivesoftware/smack/roster/RosterTest.java | 2 +- .../roster/SubscriptionPreApprovalTest.java | 2 +- .../SmackIntegrationTestFramework.java | 2 +- .../smack/roster/RosterIntegrationTest.java | 2 +- .../igniterealtime/smack/smackrepl/IoT.java | 4 +-- .../smack/smackrepl/TlsTest.java | 2 +- 21 files changed, 88 insertions(+), 32 deletions(-) diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 62e5d34e0..f88cc7c3e 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -182,7 +182,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { // Wait for the response from the server synchronized (this) { if (!connected) { - final long deadline = System.currentTimeMillis() + getPacketReplyTimeout(); + final long deadline = System.currentTimeMillis() + getReplyTimeout(); while (!notified) { final long now = System.currentTimeMillis(); if (now >= deadline) break; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 75ad70bca..b75e937a5 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -169,9 +169,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { protected String streamId; /** - * + * The timeout to wait for a reply in milliseconds. */ - private long packetReplyTimeout = SmackConfiguration.getDefaultPacketReplyTimeout(); + private long replyTimeout = SmackConfiguration.getDefaultReplyTimeout(); /** * The SmackDebugger allows to log and debug XML traffic. @@ -969,14 +969,26 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } } + @SuppressWarnings("deprecation") @Override public long getPacketReplyTimeout() { - return packetReplyTimeout; + return getReplyTimeout(); + } + + @SuppressWarnings("deprecation") + @Override + public void setPacketReplyTimeout(long timeout) { + setReplyTimeout(timeout); } @Override - public void setPacketReplyTimeout(long timeout) { - packetReplyTimeout = timeout; + public long getReplyTimeout() { + return replyTimeout; + } + + @Override + public void setReplyTimeout(long timeout) { + replyTimeout = timeout; } private static boolean replyToUnknownIqDefault = true; @@ -1466,7 +1478,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { StanzaListener callback, ExceptionCallback exceptionCallback) throws NotConnectedException, InterruptedException { sendStanzaWithResponseCallback(stanza, replyFilter, callback, exceptionCallback, - getPacketReplyTimeout()); + getReplyTimeout()); } @Override @@ -1527,7 +1539,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { @Override public void sendIqWithResponseCallback(IQ iqRequest, StanzaListener callback, ExceptionCallback exceptionCallback) throws NotConnectedException, InterruptedException { - sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getPacketReplyTimeout()); + sendIqWithResponseCallback(iqRequest, callback, exceptionCallback, getReplyTimeout()); } @Override @@ -1556,7 +1568,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { public void run() { removeSyncStanzaListener(packetListener); } - }, getPacketReplyTimeout(), TimeUnit.MILLISECONDS); + }, getReplyTimeout(), TimeUnit.MILLISECONDS); } @Override diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java b/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java index 024a7ef9e..5cc8f5dcd 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SASLAuthentication.java @@ -200,7 +200,7 @@ public final class SASLAuthentication { else { currentMechanism.authenticate(username, host, xmppServiceDomain, password, authzid, sslSession); } - final long deadline = System.currentTimeMillis() + connection.getPacketReplyTimeout(); + final long deadline = System.currentTimeMillis() + connection.getReplyTimeout(); while (!authenticationSuccessful && saslException == null) { final long now = System.currentTimeMillis(); if (now >= deadline) break; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java index f68ff03ef..2e6770c7a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -101,8 +101,32 @@ public final class SmackConfiguration { * the server. The default value is 5000 ms. * * @return the milliseconds to wait for a response from the server + * @deprecated use {@link #getDefaultReplyTimeout()} instead. */ + @Deprecated public static int getDefaultPacketReplyTimeout() { + return getDefaultReplyTimeout(); + } + + /** + * Sets the number of milliseconds to wait for a response from + * the server. + * + * @param timeout the milliseconds to wait for a response from the server + * @deprecated use {@link #setDefaultReplyTimeout(int)} instead. + */ + @Deprecated + public static void setDefaultPacketReplyTimeout(int timeout) { + setDefaultReplyTimeout(timeout); + } + + /** + * Returns the number of milliseconds to wait for a response from + * the server. The default value is 5000 ms. + * + * @return the milliseconds to wait for a response from the server + */ + public static int getDefaultReplyTimeout() { // The timeout value must be greater than 0 otherwise we will answer the default value if (defaultPacketReplyTimeout <= 0) { defaultPacketReplyTimeout = 5000; @@ -116,7 +140,7 @@ public final class SmackConfiguration { * * @param timeout the milliseconds to wait for a response from the server */ - public static void setDefaultPacketReplyTimeout(int timeout) { + public static void setDefaultReplyTimeout(int timeout) { if (timeout <= 0) { throw new IllegalArgumentException(); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java index 23e76d96e..b6d190fa6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java @@ -58,7 +58,7 @@ public class SmackException extends Exception { /** * Exception thrown always when there was no response to an request within the stanza(/packet) reply timeout of the used * connection instance. You can modify (e.g. increase) the stanza(/packet) reply timeout with - * {@link XMPPConnection#setPacketReplyTimeout(long)}. + * {@link XMPPConnection#setReplyTimeout(long)}. */ public static final class NoResponseException extends SmackException { /** @@ -111,7 +111,7 @@ public class SmackException extends Exception { } private static StringBuilder getWaitingFor(XMPPConnection connection) { - final long replyTimeout = connection.getPacketReplyTimeout(); + final long replyTimeout = connection.getReplyTimeout(); final StringBuilder sb = new StringBuilder(256); sb.append("No response received within reply timeout. Timeout was " + replyTimeout + "ms (~" diff --git a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java index 7b47bc947..888884efd 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java @@ -161,7 +161,7 @@ public class StanzaCollector { * @throws InterruptedException */ public

P nextResult() throws InterruptedException { - return nextResult(connection.getPacketReplyTimeout()); + return nextResult(connection.getReplyTimeout()); } private volatile long waitStart; @@ -205,7 +205,7 @@ public class StanzaCollector { */ public

P nextResultOrThrow() throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { - return nextResultOrThrow(connection.getPacketReplyTimeout()); + return nextResultOrThrow(connection.getReplyTimeout()); } /** diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java index ec991509e..2fa69d72f 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -234,7 +234,7 @@ public class SynchronizationPoint { * @throws InterruptedException */ private void waitForConditionOrTimeout() throws InterruptedException { - long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout()); + long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getReplyTimeout()); while (state == State.RequestSent || state == State.Initial) { if (remainingWait <= 0) { state = State.NoResponse; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java index c7d64752f..87965276d 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java @@ -407,7 +407,9 @@ public interface XMPPConnection { * XMPPConnection instance. * * @return the stanza(/packet) reply timeout in milliseconds + * @deprecated use {@link #getReplyTimeout()} instead. */ + @Deprecated public long getPacketReplyTimeout(); /** @@ -415,9 +417,27 @@ public interface XMPPConnection { * {@link NoResponseException} if no reply to a request was received within the timeout period. * * @param timeout the stanza(/packet) reply timeout in milliseconds + * @deprecated use {@link #setReplyTimeout(long)} instead. */ + @Deprecated public void setPacketReplyTimeout(long timeout); + /** + * Returns the current value of the reply timeout in milliseconds for request for this + * XMPPConnection instance. + * + * @return the reply timeout in milliseconds + */ + public long getReplyTimeout(); + + /** + * Set the stanza(/packet) reply timeout in milliseconds. In most cases, Smack will throw a + * {@link NoResponseException} if no reply to a request was received within the timeout period. + * + * @param timeout for a reply in milliseconds + */ + public void setReplyTimeout(long timeout); + /** * Get the connection counter of this XMPPConnection instance. Those can be used as ID to * identify the connection, but beware that the ID may not be unique if you create more then diff --git a/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java b/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java index 5915db7f5..a863d44dd 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java @@ -28,7 +28,7 @@ public class SmackConfigurationTest { @Test public void testSmackConfiguration() { try { - SmackConfiguration.getDefaultPacketReplyTimeout(); + SmackConfiguration.getDefaultReplyTimeout(); } catch (Throwable t) { fail("SmackConfiguration threw Throwable"); } @@ -40,7 +40,7 @@ public class SmackConfigurationTest { @Ignore @Test public void smackConfigurationShouldNotCauseInitializationTest() { - SmackConfiguration.getDefaultPacketReplyTimeout(); + SmackConfiguration.getDefaultReplyTimeout(); // Only a call to SmackConfiguration.getVersion() should cause Smack to become initialized. assertFalse(SmackConfiguration.isSmackInitialized()); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java index dcc2c0ed6..0590d7aa8 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java @@ -96,7 +96,7 @@ public abstract class StreamNegotiator { final String eventKey = initiation.getFrom().toString() + '\t' + initiation.getSessionID(); IQ streamMethodInitiation; try { - streamMethodInitiation = initationSetEvents.performActionAndWaitForEvent(eventKey, connection.getPacketReplyTimeout(), new Callback() { + streamMethodInitiation = initationSetEvents.performActionAndWaitForEvent(eventKey, connection.getReplyTimeout(), new Callback() { @Override public void action() throws NotConnectedException { try { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index b47cc311d..ea823accc 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -355,7 +355,7 @@ public class MultiUserChat { * @since 4.2 */ public MucEnterConfiguration.Builder getEnterConfigurationBuilder(Resourcepart nickname) { - return new MucEnterConfiguration.Builder(nickname, connection.getPacketReplyTimeout()); + return new MucEnterConfiguration.Builder(nickname, connection.getReplyTimeout()); } /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java index 0535c0e0a..ce63a78ea 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/ping/PingManager.java @@ -186,7 +186,7 @@ public final class PingManager extends Manager { * @throws InterruptedException */ public boolean ping(Jid jid) throws NotConnectedException, NoResponseException, InterruptedException { - return ping(jid, connection().getPacketReplyTimeout()); + return ping(jid, connection().getReplyTimeout()); } /** @@ -231,7 +231,7 @@ public final class PingManager extends Manager { * @throws InterruptedException */ public boolean pingMyServer(boolean notifyListeners) throws NotConnectedException, InterruptedException { - return pingMyServer(notifyListeners, connection().getPacketReplyTimeout()); + return pingMyServer(notifyListeners, connection().getReplyTimeout()); } /** diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/ping/PingTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/ping/PingTest.java index 2218aa0fa..9b4b9a178 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/ping/PingTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/ping/PingTest.java @@ -248,7 +248,7 @@ public class PingTest extends InitExtensions { */ private static DummyConnection getAuthenticatedDummyConnectionWithoutIqReplies() throws SmackException, IOException, XMPPException, InterruptedException { DummyConnection con = new DummyConnection(); - con.setPacketReplyTimeout(500); + con.setReplyTimeout(500); con.connect(); con.login(); return con; diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java index 038af40d1..a3686b1a8 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java @@ -88,7 +88,7 @@ public class ConfigureFormTest Node node = mgr.getNode("princely_musings"); - SmackConfiguration.setDefaultPacketReplyTimeout(100); + SmackConfiguration.setDefaultReplyTimeout(100); con.setTimeout(); node.getNodeConfiguration(); diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index 6082f9400..71d01fa42 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -473,7 +473,7 @@ public final class Roster extends Manager { } protected boolean waitUntilLoaded() throws InterruptedException { - long waitTime = connection().getPacketReplyTimeout(); + long waitTime = connection().getReplyTimeout(); long start = System.currentTimeMillis(); while (!isLoaded()) { if (waitTime <= 0) { diff --git a/smack-im/src/test/java/org/jivesoftware/smack/roster/RosterTest.java b/smack-im/src/test/java/org/jivesoftware/smack/roster/RosterTest.java index eea54d25a..10ffd1c3d 100644 --- a/smack-im/src/test/java/org/jivesoftware/smack/roster/RosterTest.java +++ b/smack-im/src/test/java/org/jivesoftware/smack/roster/RosterTest.java @@ -75,7 +75,7 @@ public class RosterTest extends InitSmackIm { rosterListener = new TestRosterListener(); roster = Roster.getInstanceFor(connection); roster.addRosterListener(rosterListener); - connection.setPacketReplyTimeout(1000 * 60 * 5); + connection.setReplyTimeout(1000 * 60 * 5); } @After diff --git a/smack-im/src/test/java/org/jivesoftware/smack/roster/SubscriptionPreApprovalTest.java b/smack-im/src/test/java/org/jivesoftware/smack/roster/SubscriptionPreApprovalTest.java index a864273da..634a7def8 100644 --- a/smack-im/src/test/java/org/jivesoftware/smack/roster/SubscriptionPreApprovalTest.java +++ b/smack-im/src/test/java/org/jivesoftware/smack/roster/SubscriptionPreApprovalTest.java @@ -61,7 +61,7 @@ public class SubscriptionPreApprovalTest extends InitSmackIm { rosterListener = new TestRosterListener(); roster = Roster.getInstanceFor(connection); roster.addRosterListener(rosterListener); - connection.setPacketReplyTimeout(1000 * 60 * 5); + connection.setReplyTimeout(1000 * 60 * 5); } @After diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java index 5989a92b4..35edeac47 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java @@ -133,7 +133,7 @@ public class SmackIntegrationTestFramework { SmackConfiguration.DEBUG = true; } if (config.replyTimeout > 0) { - SmackConfiguration.setDefaultPacketReplyTimeout(config.replyTimeout); + SmackConfiguration.setDefaultReplyTimeout(config.replyTimeout); } if (config.securityMode != SecurityMode.required) { AccountManager.sensitiveOperationOverInsecureConnectionDefault(true); diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smack/roster/RosterIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smack/roster/RosterIntegrationTest.java index 537d00c7e..3b9c148aa 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smack/roster/RosterIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smack/roster/RosterIntegrationTest.java @@ -104,7 +104,7 @@ public class RosterIntegrationTest extends AbstractSmackIntegrationTest { try { rosterOne.createEntry(conTwo.getUser().asBareJid(), conTwosRosterName, null); - assertTrue(addedAndSubscribed.waitForResult(2 * connection.getPacketReplyTimeout())); + assertTrue(addedAndSubscribed.waitForResult(2 * connection.getReplyTimeout())); } finally { rosterTwo.removeSubscribeListener(subscribeListener); diff --git a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java index 489d9b424..e1c3d4da1 100644 --- a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java +++ b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java @@ -75,8 +75,8 @@ public class IoT { final XMPPTCPConnection dataThingConnection = new XMPPTCPConnection(dataThingConnectionConfiguration); final XMPPTCPConnection readingThingConnection = new XMPPTCPConnection(readingThingConnectionConfiguration); - dataThingConnection.setPacketReplyTimeout(TIMEOUT); - readingThingConnection.setPacketReplyTimeout(TIMEOUT); + dataThingConnection.setReplyTimeout(TIMEOUT); + readingThingConnection.setReplyTimeout(TIMEOUT); dataThingConnection.setUseStreamManagement(false); readingThingConnection.setUseStreamManagement(false); diff --git a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java index 16ee15a12..2145cf41b 100644 --- a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java +++ b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java @@ -89,7 +89,7 @@ public class TlsTest { XMPPTCPConnection connection = new XMPPTCPConnection(builder.build()); - connection.setPacketReplyTimeout(20000); + connection.setReplyTimeout(20000); try { connection.connect().login(); From ce194819db065be646c54e032b68f40a09922ec7 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 15 Jan 2017 10:02:22 +0100 Subject: [PATCH 15/15] Smack 4.2.0-rc2 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 53d4d2ffd..a35799368 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { shortVersion = '4.2.0-rc2' - isSnapshot = true + isSnapshot = false jxmppVersion = '0.5.0' smackMinAndroidSdk = 8 }