mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 06:12:05 +01:00
Merge branch '4.1'
Conflicts: smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java version.gradle
This commit is contained in:
commit
01f08e87c2
7 changed files with 82 additions and 56 deletions
|
@ -19,6 +19,7 @@ package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.id.StanzaIdUtil;
|
||||||
import org.jivesoftware.smack.util.Objects;
|
import org.jivesoftware.smack.util.Objects;
|
||||||
import org.jivesoftware.smack.util.TypedCloneable;
|
import org.jivesoftware.smack.util.TypedCloneable;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
@ -259,6 +260,18 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
return new Presence(this);
|
return new Presence(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone this presence and set a newly generated stanza ID as the clone's ID.
|
||||||
|
*
|
||||||
|
* @return a "clone" of this presence with a different stanza ID.
|
||||||
|
* @since 4.1.2
|
||||||
|
*/
|
||||||
|
public Presence cloneWithNewId() {
|
||||||
|
Presence clone = clone();
|
||||||
|
clone.setStanzaId(StanzaIdUtil.newStanzaId());
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum to represent the presence type. Note that presence type is often confused
|
* An enum to represent the presence type. Note that presence type is often confused
|
||||||
* with presence mode. Generally, if a user is signed in to a server, they have a presence
|
* with presence mode. Generally, if a user is signed in to a server, they have a presence
|
||||||
|
|
|
@ -359,6 +359,23 @@ public abstract class Stanza implements TopLevelStreamElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given extension and override eventually existing extensions with the same name and
|
||||||
|
* namespace.
|
||||||
|
*
|
||||||
|
* @param extension the extension element to add.
|
||||||
|
* @return one of the removed extensions or <code>null</code> if there are none.
|
||||||
|
* @since 4.1.2
|
||||||
|
*/
|
||||||
|
public ExtensionElement overrideExtension(ExtensionElement extension) {
|
||||||
|
if (extension == null) return null;
|
||||||
|
synchronized (packetExtensions) {
|
||||||
|
ExtensionElement removedExtension = removeExtension(extension);
|
||||||
|
addExtension(extension);
|
||||||
|
return removedExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a collection of stanza(/packet) extensions to the packet. Does nothing if extensions is null.
|
* Adds a collection of stanza(/packet) extensions to the packet. Does nothing if extensions is null.
|
||||||
*
|
*
|
||||||
|
|
|
@ -201,7 +201,10 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
|
||||||
private final void authenticate() throws SmackException, NotConnectedException, InterruptedException {
|
private final void authenticate() throws SmackException, NotConnectedException, InterruptedException {
|
||||||
byte[] authenticationBytes = getAuthenticationText();
|
byte[] authenticationBytes = getAuthenticationText();
|
||||||
String authenticationText;
|
String authenticationText;
|
||||||
if (authenticationBytes != null) {
|
// Some SASL mechanisms do return an empty array (e.g. EXTERNAL from javax), so check that
|
||||||
|
// the array is not-empty. Mechanisms are allowed to return either 'null' or an empty array
|
||||||
|
// if there is no authentication text.
|
||||||
|
if (authenticationBytes != null && authenticationBytes.length > 0) {
|
||||||
authenticationText = Base64.encodeToString(authenticationBytes);
|
authenticationText = Base64.encodeToString(authenticationBytes);
|
||||||
} else {
|
} else {
|
||||||
// RFC6120 6.4.2 "If the initiating entity needs to send a zero-length initial response,
|
// RFC6120 6.4.2 "If the initiating entity needs to send a zero-length initial response,
|
||||||
|
@ -215,7 +218,8 @@ public abstract class SASLMechanism implements Comparable<SASLMechanism> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the initial response of the SASL mechanism. The returned byte array will be
|
* Should return the initial response of the SASL mechanism. The returned byte array will be
|
||||||
* send base64 encoded to the server. SASL mechanism are free to return <code>null</code> here.
|
* send base64 encoded to the server. SASL mechanism are free to return <code>null</code> or an
|
||||||
|
* empty array here.
|
||||||
*
|
*
|
||||||
* @return the initial response or null
|
* @return the initial response or null
|
||||||
* @throws SmackException
|
* @throws SmackException
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.jivesoftware.smack.AbstractConnectionClosedListener;
|
import org.jivesoftware.smack.Manager;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
|
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
|
||||||
|
@ -89,7 +89,7 @@ import org.jxmpp.jid.Jid;
|
||||||
*
|
*
|
||||||
* @author Henning Staib
|
* @author Henning Staib
|
||||||
*/
|
*/
|
||||||
public final class Socks5BytestreamManager implements BytestreamManager {
|
public final class Socks5BytestreamManager extends Manager implements BytestreamManager {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new Socks5BytestreamManager and register a shutdown listener on every established
|
* create a new Socks5BytestreamManager and register a shutdown listener on every established
|
||||||
|
@ -101,22 +101,6 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
public void connectionCreated(final XMPPConnection connection) {
|
public void connectionCreated(final XMPPConnection connection) {
|
||||||
// create the manager for this connection
|
// create the manager for this connection
|
||||||
Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
// register shutdown listener
|
|
||||||
connection.addConnectionListener(new AbstractConnectionClosedListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionTerminated() {
|
|
||||||
Socks5BytestreamManager.getBytestreamManager(connection).disableService();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reconnectionSuccessful() {
|
|
||||||
// re-create the manager for this connection
|
|
||||||
Socks5BytestreamManager.getBytestreamManager(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -131,9 +115,6 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
/* stores one Socks5BytestreamManager for each XMPP connection */
|
/* stores one Socks5BytestreamManager for each XMPP connection */
|
||||||
private final static Map<XMPPConnection, Socks5BytestreamManager> managers = new HashMap<XMPPConnection, Socks5BytestreamManager>();
|
private final static Map<XMPPConnection, Socks5BytestreamManager> managers = new HashMap<XMPPConnection, Socks5BytestreamManager>();
|
||||||
|
|
||||||
/* XMPP connection */
|
|
||||||
private final XMPPConnection connection;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assigns a user to a listener that is informed if a bytestream request for this user is
|
* assigns a user to a listener that is informed if a bytestream request for this user is
|
||||||
* received
|
* received
|
||||||
|
@ -188,7 +169,6 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
manager = new Socks5BytestreamManager(connection);
|
manager = new Socks5BytestreamManager(connection);
|
||||||
managers.put(connection, manager);
|
managers.put(connection, manager);
|
||||||
manager.activate();
|
|
||||||
}
|
}
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
@ -199,8 +179,9 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* @param connection the XMPP connection
|
* @param connection the XMPP connection
|
||||||
*/
|
*/
|
||||||
private Socks5BytestreamManager(XMPPConnection connection) {
|
private Socks5BytestreamManager(XMPPConnection connection) {
|
||||||
this.connection = connection;
|
super(connection);
|
||||||
this.initiationListener = new InitiationListener(this);
|
this.initiationListener = new InitiationListener(this);
|
||||||
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -285,7 +266,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
|
* Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
|
||||||
*/
|
*/
|
||||||
public synchronized void disableService() {
|
public synchronized void disableService() {
|
||||||
|
XMPPConnection connection = connection();
|
||||||
// remove initiation packet listener
|
// remove initiation packet listener
|
||||||
connection.unregisterIQRequestHandler(initiationListener);
|
connection.unregisterIQRequestHandler(initiationListener);
|
||||||
|
|
||||||
|
@ -302,7 +283,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
this.ignoredBytestreamRequests.clear();
|
this.ignoredBytestreamRequests.clear();
|
||||||
|
|
||||||
// remove manager from static managers map
|
// remove manager from static managers map
|
||||||
managers.remove(this.connection);
|
managers.remove(connection);
|
||||||
|
|
||||||
// shutdown local SOCKS5 proxy if there are no more managers for other connections
|
// shutdown local SOCKS5 proxy if there are no more managers for other connections
|
||||||
if (managers.size() == 0) {
|
if (managers.size() == 0) {
|
||||||
|
@ -310,7 +291,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove feature from service discovery
|
// remove feature from service discovery
|
||||||
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
|
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
|
||||||
// check if service discovery is not already disposed by connection shutdown
|
// check if service discovery is not already disposed by connection shutdown
|
||||||
if (serviceDiscoveryManager != null) {
|
if (serviceDiscoveryManager != null) {
|
||||||
|
@ -426,7 +407,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
*/
|
*/
|
||||||
public Socks5BytestreamSession establishSession(Jid targetJID, String sessionID)
|
public Socks5BytestreamSession establishSession(Jid targetJID, String sessionID)
|
||||||
throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException{
|
throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException{
|
||||||
|
XMPPConnection connection = connection();
|
||||||
XMPPErrorException discoveryException = null;
|
XMPPErrorException discoveryException = null;
|
||||||
// check if target supports SOCKS5 Bytestream
|
// check if target supports SOCKS5 Bytestream
|
||||||
if (!supportsSocks5(targetJID)) {
|
if (!supportsSocks5(targetJID)) {
|
||||||
|
@ -455,7 +436,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute digest
|
// compute digest
|
||||||
String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID);
|
String digest = Socks5Utils.createDigest(sessionID, connection.getUser(), targetJID);
|
||||||
|
|
||||||
// prioritize last working SOCKS5 proxy if exists
|
// prioritize last working SOCKS5 proxy if exists
|
||||||
if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
|
if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
|
||||||
|
@ -496,7 +477,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
|
|
||||||
// build SOCKS5 client
|
// build SOCKS5 client
|
||||||
Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
|
Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
|
||||||
this.connection, sessionID, targetJID);
|
connection, sessionID, targetJID);
|
||||||
|
|
||||||
// establish connection to proxy
|
// establish connection to proxy
|
||||||
Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
|
Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
|
||||||
|
@ -506,7 +487,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
|
|
||||||
// negotiation successful, return the output stream
|
// negotiation successful, return the output stream
|
||||||
return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(
|
return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(
|
||||||
this.connection.getUser()));
|
connection.getUser()));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (TimeoutException e) {
|
catch (TimeoutException e) {
|
||||||
|
@ -533,7 +514,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
private boolean supportsSocks5(Jid targetJID) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
private boolean supportsSocks5(Jid targetJID) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
return ServiceDiscoveryManager.getInstanceFor(connection).supportsFeature(targetJID, Bytestream.NAMESPACE);
|
return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(targetJID, Bytestream.NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,12 +528,13 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
private List<Jid> determineProxies() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
private List<Jid> determineProxies() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
|
XMPPConnection connection = connection();
|
||||||
|
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
|
||||||
List<Jid> proxies = new ArrayList<>();
|
List<Jid> proxies = new ArrayList<>();
|
||||||
|
|
||||||
// get all items from XMPP server
|
// get all items from XMPP server
|
||||||
DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(this.connection.getXMPPServiceDomain());
|
DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(connection.getXMPPServiceDomain());
|
||||||
|
|
||||||
// query all items if they are SOCKS5 proxies
|
// query all items if they are SOCKS5 proxies
|
||||||
for (Item item : discoverItems.getItems()) {
|
for (Item item : discoverItems.getItems()) {
|
||||||
|
@ -595,6 +577,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* @return a list of stream hosts containing the IP address an the port
|
* @return a list of stream hosts containing the IP address an the port
|
||||||
*/
|
*/
|
||||||
private List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
private List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
||||||
|
XMPPConnection connection = connection();
|
||||||
List<StreamHost> streamHosts = new ArrayList<StreamHost>();
|
List<StreamHost> streamHosts = new ArrayList<StreamHost>();
|
||||||
|
|
||||||
// add local proxy on first position if exists
|
// add local proxy on first position if exists
|
||||||
|
@ -641,7 +624,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* is not running
|
* is not running
|
||||||
*/
|
*/
|
||||||
private List<StreamHost> getLocalStreamHost() {
|
private List<StreamHost> getLocalStreamHost() {
|
||||||
|
XMPPConnection connection = connection();
|
||||||
// get local proxy singleton
|
// get local proxy singleton
|
||||||
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
||||||
|
|
||||||
|
@ -710,7 +693,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
protected void replyRejectPacket(IQ packet) throws NotConnectedException, InterruptedException {
|
protected void replyRejectPacket(IQ packet) throws NotConnectedException, InterruptedException {
|
||||||
XMPPError xmppError = new XMPPError(XMPPError.Condition.not_acceptable);
|
XMPPError xmppError = new XMPPError(XMPPError.Condition.not_acceptable);
|
||||||
IQ errorIQ = IQ.createErrorResponse(packet, xmppError);
|
IQ errorIQ = IQ.createErrorResponse(packet, xmppError);
|
||||||
this.connection.sendStanza(errorIQ);
|
connection().sendStanza(errorIQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -719,7 +702,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
*/
|
*/
|
||||||
private void activate() {
|
private void activate() {
|
||||||
// register bytestream initiation packet listener
|
// register bytestream initiation packet listener
|
||||||
connection.registerIQRequestHandler(initiationListener);
|
connection().registerIQRequestHandler(initiationListener);
|
||||||
|
|
||||||
// enable SOCKS5 feature
|
// enable SOCKS5 feature
|
||||||
enableService();
|
enableService();
|
||||||
|
@ -729,7 +712,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* Adds the SOCKS5 Bytestream feature to the service discovery.
|
* Adds the SOCKS5 Bytestream feature to the service discovery.
|
||||||
*/
|
*/
|
||||||
private void enableService() {
|
private void enableService() {
|
||||||
ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection);
|
ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(connection());
|
||||||
manager.addFeature(Bytestream.NAMESPACE);
|
manager.addFeature(Bytestream.NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +734,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
|
||||||
* @return the XMPP connection
|
* @return the XMPP connection
|
||||||
*/
|
*/
|
||||||
protected XMPPConnection getConnection() {
|
protected XMPPConnection getConnection() {
|
||||||
return this.connection;
|
return connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.jivesoftware.smackx.bytestreams.socks5;
|
package org.jivesoftware.smackx.bytestreams.socks5;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ import org.jxmpp.jid.Jid;
|
||||||
class Socks5ClientForInitiator extends Socks5Client {
|
class Socks5ClientForInitiator extends Socks5Client {
|
||||||
|
|
||||||
/* the XMPP connection used to communicate with the SOCKS5 proxy */
|
/* the XMPP connection used to communicate with the SOCKS5 proxy */
|
||||||
private XMPPConnection connection;
|
private WeakReference<XMPPConnection> connection;
|
||||||
|
|
||||||
/* the session ID used to activate SOCKS5 stream */
|
/* the session ID used to activate SOCKS5 stream */
|
||||||
private String sessionID;
|
private String sessionID;
|
||||||
|
@ -63,7 +64,7 @@ class Socks5ClientForInitiator extends Socks5Client {
|
||||||
public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection,
|
public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection,
|
||||||
String sessionID, Jid target) {
|
String sessionID, Jid target) {
|
||||||
super(streamHost, digest);
|
super(streamHost, digest);
|
||||||
this.connection = connection;
|
this.connection = new WeakReference<>(connection);
|
||||||
this.sessionID = sessionID;
|
this.sessionID = sessionID;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,7 @@ class Socks5ClientForInitiator extends Socks5Client {
|
||||||
Socket socket = null;
|
Socket socket = null;
|
||||||
|
|
||||||
// check if stream host is the local SOCKS5 proxy
|
// check if stream host is the local SOCKS5 proxy
|
||||||
if (this.streamHost.getJID().equals(this.connection.getUser())) {
|
if (this.streamHost.getJID().equals(this.connection.get().getUser())) {
|
||||||
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
||||||
socket = socks5Server.getSocket(this.digest);
|
socket = socks5Server.getSocket(this.digest);
|
||||||
if (socket == null) {
|
if (socket == null) {
|
||||||
|
@ -112,7 +113,7 @@ class Socks5ClientForInitiator extends Socks5Client {
|
||||||
private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
Bytestream activate = createStreamHostActivation();
|
Bytestream activate = createStreamHostActivation();
|
||||||
// if activation fails #nextResultOrThrow() throws an exception
|
// if activation fails #nextResultOrThrow() throws an exception
|
||||||
connection.createPacketCollectorAndSend(activate).nextResultOrThrow();
|
connection.get().createPacketCollectorAndSend(activate).nextResultOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.jivesoftware.smack.packet.Stanza;
|
||||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
import org.jivesoftware.smack.packet.Presence;
|
import org.jivesoftware.smack.packet.Presence;
|
||||||
import org.jivesoftware.smack.filter.NotFilter;
|
import org.jivesoftware.smack.filter.NotFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PresenceTypeFilter;
|
||||||
import org.jivesoftware.smack.filter.StanzaFilter;
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
import org.jivesoftware.smack.filter.AndFilter;
|
import org.jivesoftware.smack.filter.AndFilter;
|
||||||
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
||||||
|
@ -96,7 +97,6 @@ public final class EntityCapsManager extends Manager {
|
||||||
ELEMENT, NAMESPACE));
|
ELEMENT, NAMESPACE));
|
||||||
private static final StanzaFilter PRESENCES_WITHOUT_CAPS = new AndFilter(new StanzaTypeFilter(Presence.class), new NotFilter(new StanzaExtensionFilter(
|
private static final StanzaFilter PRESENCES_WITHOUT_CAPS = new AndFilter(new StanzaTypeFilter(Presence.class), new NotFilter(new StanzaExtensionFilter(
|
||||||
ELEMENT, NAMESPACE)));
|
ELEMENT, NAMESPACE)));
|
||||||
private static final StanzaFilter PRESENCES = StanzaTypeFilter.PRESENCE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of "node + '#' + hash" to DiscoverInfo data
|
* Map of "node + '#' + hash" to DiscoverInfo data
|
||||||
|
@ -264,7 +264,7 @@ public final class EntityCapsManager extends Manager {
|
||||||
|
|
||||||
private boolean entityCapsEnabled;
|
private boolean entityCapsEnabled;
|
||||||
private CapsVersionAndHash currentCapsVersion;
|
private CapsVersionAndHash currentCapsVersion;
|
||||||
private boolean presenceSend = false;
|
private volatile Presence presenceSend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The entity node String used by this EntityCapsManager instance.
|
* The entity node String used by this EntityCapsManager instance.
|
||||||
|
@ -293,7 +293,7 @@ public final class EntityCapsManager extends Manager {
|
||||||
|
|
||||||
// Reset presenceSend when the connection was not resumed
|
// Reset presenceSend when the connection was not resumed
|
||||||
if (!resumed) {
|
if (!resumed) {
|
||||||
presenceSend = false;
|
presenceSend = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void processCapsStreamFeatureIfAvailable(XMPPConnection connection) {
|
private void processCapsStreamFeatureIfAvailable(XMPPConnection connection) {
|
||||||
|
@ -341,23 +341,26 @@ public final class EntityCapsManager extends Manager {
|
||||||
connection.addPacketSendingListener(new StanzaListener() {
|
connection.addPacketSendingListener(new StanzaListener() {
|
||||||
@Override
|
@Override
|
||||||
public void processPacket(Stanza packet) {
|
public void processPacket(Stanza packet) {
|
||||||
presenceSend = true;
|
presenceSend = (Presence) packet;
|
||||||
}
|
}
|
||||||
}, PRESENCES);
|
}, PresenceTypeFilter.AVAILABLE);
|
||||||
|
|
||||||
// Intercept presence packages and add caps data when intended.
|
// Intercept presence packages and add caps data when intended.
|
||||||
// XEP-0115 specifies that a client SHOULD include entity capabilities
|
// XEP-0115 specifies that a client SHOULD include entity capabilities
|
||||||
// with every presence notification it sends.
|
// with every presence notification it sends.
|
||||||
StanzaListener packetInterceptor = new StanzaListener() {
|
StanzaListener packetInterceptor = new StanzaListener() {
|
||||||
public void processPacket(Stanza packet) {
|
public void processPacket(Stanza packet) {
|
||||||
if (!entityCapsEnabled)
|
if (!entityCapsEnabled) {
|
||||||
|
// Be sure to not send stanzas with the caps extension if it's not enabled
|
||||||
|
packet.removeExtension(CapsExtension.ELEMENT, CapsExtension.NAMESPACE);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
CapsVersionAndHash capsVersionAndHash = getCapsVersionAndHash();
|
CapsVersionAndHash capsVersionAndHash = getCapsVersionAndHash();
|
||||||
CapsExtension caps = new CapsExtension(entityNode, capsVersionAndHash.version, capsVersionAndHash.hash);
|
CapsExtension caps = new CapsExtension(entityNode, capsVersionAndHash.version, capsVersionAndHash.hash);
|
||||||
packet.addExtension(caps);
|
packet.overrideExtension(caps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
connection.addPacketInterceptor(packetInterceptor, PRESENCES);
|
connection.addPacketInterceptor(packetInterceptor, PresenceTypeFilter.AVAILABLE);
|
||||||
// It's important to do this as last action. Since it changes the
|
// It's important to do this as last action. Since it changes the
|
||||||
// behavior of the SDM in some ways
|
// behavior of the SDM in some ways
|
||||||
sdm.setEntityCapsManager(this);
|
sdm.setEntityCapsManager(this);
|
||||||
|
@ -506,15 +509,14 @@ public final class EntityCapsManager extends Manager {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send an empty presence, and let the packet interceptor
|
// Re-send the last sent presence, and let the stanza interceptor
|
||||||
// add a <c/> node to it.
|
// add a <c/> node to it.
|
||||||
// See http://xmpp.org/extensions/xep-0115.html#advertise
|
// See http://xmpp.org/extensions/xep-0115.html#advertise
|
||||||
// We only send a presence packet if there was already one send
|
// We only send a presence packet if there was already one send
|
||||||
// to respect ConnectionConfiguration.isSendPresence()
|
// to respect ConnectionConfiguration.isSendPresence()
|
||||||
if (connection != null && connection.isAuthenticated() && presenceSend) {
|
if (connection != null && connection.isAuthenticated() && presenceSend != null) {
|
||||||
Presence presence = new Presence(Presence.Type.available);
|
|
||||||
try {
|
try {
|
||||||
connection.sendStanza(presence);
|
connection.sendStanza(presenceSend.cloneWithNewId());
|
||||||
}
|
}
|
||||||
catch (InterruptedException | NotConnectedException e) {
|
catch (InterruptedException | NotConnectedException e) {
|
||||||
LOGGER.log(Level.WARNING, "Could could not update presence with caps info", e);
|
LOGGER.log(Level.WARNING, "Could could not update presence with caps info", e);
|
||||||
|
|
|
@ -1075,6 +1075,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
}
|
}
|
||||||
smResumedSyncPoint.reportSuccess();
|
smResumedSyncPoint.reportSuccess();
|
||||||
smEnabledSyncPoint.reportSuccess();
|
smEnabledSyncPoint.reportSuccess();
|
||||||
|
// If there where stanzas resent, then request a SM ack for them.
|
||||||
|
// Writer's sendStreamElement() won't do it automatically based on
|
||||||
|
// predicates.
|
||||||
|
if (!stanzasToResend.isEmpty()) {
|
||||||
|
requestSmAcknowledgementInternal();
|
||||||
|
}
|
||||||
LOGGER.fine("Stream Management (XEP-198): Stream resumed");
|
LOGGER.fine("Stream Management (XEP-198): Stream resumed");
|
||||||
break;
|
break;
|
||||||
case AckAnswer.ELEMENT:
|
case AckAnswer.ELEMENT:
|
||||||
|
|
Loading…
Reference in a new issue