mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-12-14 06:51:08 +01:00
Merge branch '4.1'
Conflicts: smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java smack-core/src/main/java/org/jivesoftware/smack/PacketCollector.java smack-core/src/main/java/org/jivesoftware/smack/PacketListener.java smack-core/src/main/java/org/jivesoftware/smack/XMPPConnection.java smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebugger.java smack-core/src/main/java/org/jivesoftware/smack/packet/Packet.java smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java smack-core/src/test/java/org/jivesoftware/smack/ThreadedDummyConnection.java smack-extensions/src/main/java/org/jivesoftware/smackx/address/provider/MultipleAddressesProvider.java smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FaultTolerantNegotiator.java smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/IBBTransferNegotiator.java smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/StreamNegotiator.java smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/LeafNode.java smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Node.java smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/packet/PubSub.java smack-extensions/src/main/java/org/jivesoftware/smackx/vcardtemp/VCardManager.java smack-extensions/src/test/java/org/jivesoftware/smackx/receipts/DeliveryReceiptTest.java smack-im/src/main/java/org/jivesoftware/smack/chat/ChatManager.java smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/JingleSession.java smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/provider/JingleProvider.java smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/packet/UserID.java smack-legacy/src/main/java/org/jivesoftware/smackx/xroster/provider/RosterExchangeProvider.java smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java version.gradle
This commit is contained in:
commit
701aa7d9c4
298 changed files with 2402 additions and 1562 deletions
|
|
@ -18,26 +18,15 @@ package org.jivesoftware.smackx.filetransfer;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jivesoftware.smack.PacketCollector;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.filter.OrFilter;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
|
||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
|
@ -52,8 +41,6 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
|
|||
private final StreamNegotiator primaryNegotiator;
|
||||
private final StreamNegotiator secondaryNegotiator;
|
||||
private final XMPPConnection connection;
|
||||
private PacketFilter primaryFilter;
|
||||
private PacketFilter secondaryFilter;
|
||||
|
||||
public FaultTolerantNegotiator(XMPPConnection connection, StreamNegotiator primary,
|
||||
StreamNegotiator secondary) {
|
||||
|
|
@ -62,12 +49,10 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
|
|||
this.connection = connection;
|
||||
}
|
||||
|
||||
public PacketFilter getInitiationPacketFilter(Jid from, String streamID) {
|
||||
if (primaryFilter == null || secondaryFilter == null) {
|
||||
primaryFilter = primaryNegotiator.getInitiationPacketFilter(from, streamID);
|
||||
secondaryFilter = secondaryNegotiator.getInitiationPacketFilter(from, streamID);
|
||||
}
|
||||
return new OrFilter(primaryFilter, secondaryFilter);
|
||||
@Override
|
||||
public void newStreamInitiation(Jid from, String streamID) {
|
||||
primaryNegotiator.newStreamInitiation(from, streamID);
|
||||
secondaryNegotiator.newStreamInitiation(from, streamID);
|
||||
}
|
||||
|
||||
InputStream negotiateIncomingStream(Stanza streamInitiation) {
|
||||
|
|
@ -75,73 +60,23 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
|
|||
"stream method.");
|
||||
}
|
||||
|
||||
final Stanza initiateIncomingStream(XMPPConnection connection, StreamInitiation initiation) {
|
||||
throw new UnsupportedOperationException("Initiation handled by createIncomingStream " +
|
||||
"method");
|
||||
}
|
||||
public InputStream createIncomingStream(final StreamInitiation initiation) throws SmackException, XMPPErrorException, InterruptedException {
|
||||
// This could be either an xep47 ibb 'open' iq or an xep65 streamhost iq
|
||||
IQ initationSet = initiateIncomingStream(connection, initiation);
|
||||
|
||||
public InputStream createIncomingStream(StreamInitiation initiation) throws SmackException, InterruptedException {
|
||||
PacketCollector collector = connection.createPacketCollectorAndSend(
|
||||
getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()),
|
||||
super.createInitiationAccept(initiation, getNamespaces()));
|
||||
StreamNegotiator streamNegotiator = determineNegotiator(initationSet);
|
||||
|
||||
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(2);
|
||||
CompletionService<InputStream> service
|
||||
= new ExecutorCompletionService<InputStream>(threadPoolExecutor);
|
||||
List<Future<InputStream>> futures = new ArrayList<Future<InputStream>>();
|
||||
InputStream stream = null;
|
||||
SmackException exception = null;
|
||||
try {
|
||||
futures.add(service.submit(new NegotiatorService(collector)));
|
||||
futures.add(service.submit(new NegotiatorService(collector)));
|
||||
|
||||
int i = 0;
|
||||
while (stream == null && i < futures.size()) {
|
||||
Future<InputStream> future;
|
||||
try {
|
||||
i++;
|
||||
future = service.poll(connection.getPacketReplyTimeout(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (future == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
stream = future.get();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
/* Do Nothing */
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
exception = new SmackException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
for (Future<InputStream> future : futures) {
|
||||
future.cancel(true);
|
||||
}
|
||||
collector.cancel();
|
||||
threadPoolExecutor.shutdownNow();
|
||||
}
|
||||
if (stream == null) {
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
else {
|
||||
throw new SmackException("File transfer negotiation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
return stream;
|
||||
return streamNegotiator.negotiateIncomingStream(initationSet);
|
||||
}
|
||||
|
||||
private StreamNegotiator determineNegotiator(Stanza streamInitiation) {
|
||||
return primaryFilter.accept(streamInitiation) ? primaryNegotiator : secondaryNegotiator;
|
||||
if (streamInitiation instanceof Bytestream) {
|
||||
return primaryNegotiator;
|
||||
} else if (streamInitiation instanceof Open){
|
||||
return secondaryNegotiator;
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown stream initation type");
|
||||
}
|
||||
}
|
||||
|
||||
public OutputStream createOutgoingStream(String streamID, Jid initiator, Jid target)
|
||||
|
|
@ -168,18 +103,4 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
|
|||
return namespaces;
|
||||
}
|
||||
|
||||
private class NegotiatorService implements Callable<InputStream> {
|
||||
|
||||
private PacketCollector collector;
|
||||
|
||||
NegotiatorService(PacketCollector collector) {
|
||||
this.collector = collector;
|
||||
}
|
||||
|
||||
public InputStream call() throws XMPPErrorException, InterruptedException, NoResponseException, SmackException {
|
||||
Stanza streamInitiation = collector.nextResultOrThrow();
|
||||
StreamNegotiator negotiator = determineNegotiator(streamInitiation);
|
||||
return negotiator.negotiateIncomingStream(streamInitiation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,6 @@ public class FileTransferManager extends Manager {
|
|||
// Socks5BytestreamManager.replyRejectPacket(IQ).
|
||||
IQ rejection = IQ.createErrorResponse(initiation, new XMPPError(
|
||||
XMPPError.Condition.forbidden));
|
||||
connection().sendPacket(rejection);
|
||||
connection().sendStanza(rejection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ public class FileTransferNegotiator extends Manager {
|
|||
String errorMessage = "No stream methods contained in stanza.";
|
||||
XMPPError error = XMPPError.from(XMPPError.Condition.bad_request, errorMessage);
|
||||
IQ iqPacket = IQ.createErrorResponse(si, error);
|
||||
connection().sendPacket(iqPacket);
|
||||
connection().sendStanza(iqPacket);
|
||||
throw new FileTransferException.NoStreamMethodsOfferedException();
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ public class FileTransferNegotiator extends Manager {
|
|||
}
|
||||
catch (NoAcceptableTransferMechanisms e) {
|
||||
IQ iqPacket = IQ.createErrorResponse(si, XMPPError.from(XMPPError.Condition.bad_request, "No acceptable transfer mechanism"));
|
||||
connection().sendPacket(iqPacket);
|
||||
connection().sendStanza(iqPacket);
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
|
|||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.filter.AndFilter;
|
||||
import org.jivesoftware.smack.filter.FromMatchesFilter;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
|
||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
|
||||
|
|
@ -82,15 +77,14 @@ public class IBBTransferNegotiator extends StreamNegotiator {
|
|||
return negotiateIncomingStream(streamInitiation);
|
||||
}
|
||||
|
||||
public PacketFilter getInitiationPacketFilter(Jid from, String streamID) {
|
||||
@Override
|
||||
public void newStreamInitiation(Jid from, String streamID) {
|
||||
/*
|
||||
* this method is always called prior to #negotiateIncomingStream() so
|
||||
* the In-Band Bytestream initiation listener must ignore the next
|
||||
* In-Band Bytestream request with the given session ID
|
||||
*/
|
||||
this.manager.ignoreBytestreamRequestOnce(streamID);
|
||||
|
||||
return new AndFilter(FromMatchesFilter.create(from), new IBBOpenSidFilter(streamID));
|
||||
}
|
||||
|
||||
public String[] getNamespaces() {
|
||||
|
|
@ -108,34 +102,6 @@ public class IBBTransferNegotiator extends StreamNegotiator {
|
|||
return session.getInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* This PacketFilter accepts an incoming In-Band Bytestream open request
|
||||
* with a specified session ID.
|
||||
*/
|
||||
private static class IBBOpenSidFilter extends PacketTypeFilter {
|
||||
|
||||
private String sessionID;
|
||||
|
||||
public IBBOpenSidFilter(String sessionID) {
|
||||
super(Open.class);
|
||||
if (sessionID == null) {
|
||||
throw new IllegalArgumentException("StreamID cannot be null");
|
||||
}
|
||||
this.sessionID = sessionID;
|
||||
}
|
||||
|
||||
public boolean accept(Stanza packet) {
|
||||
if (super.accept(packet)) {
|
||||
Open bytestream = (Open) packet;
|
||||
|
||||
// packet must by of type SET and contains the given session ID
|
||||
return this.sessionID.equals(bytestream.getSessionID())
|
||||
&& IQ.Type.set.equals(bytestream.getType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive from InBandBytestreamRequest to access protected constructor.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,13 +26,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
|
|||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.filter.AndFilter;
|
||||
import org.jivesoftware.smack.filter.FromMatchesFilter;
|
||||
import org.jivesoftware.smack.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
|
||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
|
||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
|
||||
|
|
@ -86,15 +80,13 @@ public class Socks5TransferNegotiator extends StreamNegotiator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PacketFilter getInitiationPacketFilter(final Jid from, String streamID) {
|
||||
public void newStreamInitiation(final Jid from, String streamID) {
|
||||
/*
|
||||
* this method is always called prior to #negotiateIncomingStream() so the SOCKS5
|
||||
* InitiationListener must ignore the next SOCKS5 Bytestream request with the given session
|
||||
* ID
|
||||
*/
|
||||
this.manager.ignoreBytestreamRequestOnce(streamID);
|
||||
|
||||
return new AndFilter(FromMatchesFilter.create(from), new BytestreamSIDFilter(streamID));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -124,32 +116,6 @@ public class Socks5TransferNegotiator extends StreamNegotiator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This PacketFilter accepts an incoming SOCKS5 Bytestream request with a specified session ID.
|
||||
*/
|
||||
private static class BytestreamSIDFilter extends PacketTypeFilter {
|
||||
|
||||
private final String sessionID;
|
||||
|
||||
public BytestreamSIDFilter(String sessionID) {
|
||||
super(Bytestream.class);
|
||||
this.sessionID = Objects.requireNonNull(sessionID, "SessionID cannot be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(Stanza packet) {
|
||||
if (super.accept(packet)) {
|
||||
Bytestream bytestream = (Bytestream) packet;
|
||||
|
||||
// packet must by of type SET and contains the given session ID
|
||||
return this.sessionID.equals(bytestream.getSessionID())
|
||||
&& IQ.Type.set.equals(bytestream.getType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive from Socks5BytestreamRequest to access protected constructor.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.filetransfer;
|
||||
|
||||
import org.jivesoftware.smack.PacketCollector;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
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.filter.PacketFilter;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.EventManger;
|
||||
import org.jivesoftware.smack.util.EventManger.Callback;
|
||||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||
import org.jivesoftware.smackx.xdata.FormField;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
|
@ -44,6 +44,19 @@ import java.io.OutputStream;
|
|||
*/
|
||||
public abstract class StreamNegotiator {
|
||||
|
||||
/**
|
||||
* A event manager for stream initiation requests send to us.
|
||||
* <p>
|
||||
* Those are typical XEP-45 Open or XEP-65 Bytestream IQ requests. The even key is in the format
|
||||
* "initiationFrom + '\t' + streamId"
|
||||
* </p>
|
||||
*/
|
||||
// TODO This field currently being static is considered a quick hack. Ideally this should take
|
||||
// the local connection into account, for example by changing the key to
|
||||
// "localJid + '\t' + initiationFrom + '\t' + streamId" or making the field non-static (but then
|
||||
// you need to provide access to the InitiationListeners, which could get tricky)
|
||||
protected static final EventManger<String, IQ, SmackException.NotConnectedException> initationSetEvents = new EventManger<>();
|
||||
|
||||
/**
|
||||
* Creates the initiation acceptance packet to forward to the stream
|
||||
* initiator.
|
||||
|
|
@ -52,7 +65,7 @@ public abstract class StreamNegotiator {
|
|||
* @param namespaces The namespace that relates to the accepted means of transfer.
|
||||
* @return The response to be forwarded to the initiator.
|
||||
*/
|
||||
public StreamInitiation createInitiationAccept(
|
||||
protected static StreamInitiation createInitiationAccept(
|
||||
StreamInitiation streamInitiationOffer, String[] namespaces)
|
||||
{
|
||||
StreamInitiation response = new StreamInitiation();
|
||||
|
|
@ -73,29 +86,47 @@ public abstract class StreamNegotiator {
|
|||
return response;
|
||||
}
|
||||
|
||||
Stanza initiateIncomingStream(XMPPConnection connection, StreamInitiation initiation) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
StreamInitiation response = createInitiationAccept(initiation,
|
||||
protected final IQ initiateIncomingStream(final XMPPConnection connection, StreamInitiation initiation)
|
||||
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||
final StreamInitiation response = createInitiationAccept(initiation,
|
||||
getNamespaces());
|
||||
|
||||
// establish collector to await response
|
||||
PacketCollector collector = connection
|
||||
.createPacketCollectorAndSend(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()), response);
|
||||
newStreamInitiation(initiation.getFrom(), initiation.getSessionID());
|
||||
|
||||
Stanza streamMethodInitiation = collector.nextResultOrThrow();
|
||||
final String eventKey = initiation.getFrom().toString() + '\t' + initiation.getSessionID();
|
||||
IQ streamMethodInitiation;
|
||||
try {
|
||||
streamMethodInitiation = initationSetEvents.performActionAndWaitForEvent(eventKey, connection.getPacketReplyTimeout(), new Callback<NotConnectedException>() {
|
||||
@Override
|
||||
public void action() throws NotConnectedException {
|
||||
try {
|
||||
connection.sendStanza(response);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// TODO remove this try/catch once merged into 4.2's master branch
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
if (streamMethodInitiation == null) {
|
||||
throw NoResponseException.newWith(connection);
|
||||
}
|
||||
XMPPErrorException.ifHasErrorThenThrow(streamMethodInitiation);
|
||||
return streamMethodInitiation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the packet filter that will return the initiation packet for the appropriate stream
|
||||
* initiation.
|
||||
* Signal that a new stream initiation arrived. The negotiator may needs to prepare for it.
|
||||
*
|
||||
* @param from The initiator of the file transfer.
|
||||
* @param streamID The stream ID related to the transfer.
|
||||
* @return The <b><i>PacketFilter</b></i> that will return the packet relatable to the stream
|
||||
* initiation.
|
||||
*/
|
||||
public abstract PacketFilter getInitiationPacketFilter(Jid from, String streamID);
|
||||
protected abstract void newStreamInitiation(Jid from, String streamID);
|
||||
|
||||
|
||||
abstract InputStream negotiateIncomingStream(Stanza streamInitiation) throws XMPPErrorException,
|
||||
|
|
@ -149,4 +180,7 @@ public abstract class StreamNegotiator {
|
|||
*/
|
||||
public abstract String[] getNamespaces();
|
||||
|
||||
public static void signal(String eventKey, IQ eventValue) {
|
||||
initationSetEvents.signalEvent(eventKey, eventValue);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue