mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Rewrote Jingle code
This commit is contained in:
parent
a6b27f62d2
commit
df69c8a81c
25 changed files with 571 additions and 780 deletions
|
@ -18,7 +18,6 @@ package org.jivesoftware.smackx.jingle_filetransfer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
@ -29,24 +28,24 @@ import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.hashes.HashManager;
|
import org.jivesoftware.smackx.jingle.JingleBytestreamManager;
|
||||||
import org.jivesoftware.smackx.hashes.element.HashElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.AbstractJingleContentTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleContentProviderManager;
|
import org.jivesoftware.smackx.jingle.JingleContentProviderManager;
|
||||||
import org.jivesoftware.smackx.jingle.JingleHandler;
|
import org.jivesoftware.smackx.jingle.JingleHandler;
|
||||||
import org.jivesoftware.smackx.jingle.JingleManager;
|
import org.jivesoftware.smackx.jingle.JingleManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
import org.jivesoftware.smackx.jingle.element.JingleAction;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement;
|
import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingJingleFileTransferCallback;
|
import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingJingleFileTransferCallback;
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement;
|
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement;
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferContentDescription;
|
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferContentDescription;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.handler.IncomingFileTransferResponded;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.handler.OutgoingFileTransferInitiator;
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.listener.IncomingJingleFileTransferListener;
|
import org.jivesoftware.smackx.jingle_filetransfer.listener.IncomingJingleFileTransferListener;
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.provider.JingleFileTransferContentDescriptionProvider;
|
import org.jivesoftware.smackx.jingle_filetransfer.provider.JingleFileTransferContentDescriptionProvider;
|
||||||
import org.jivesoftware.smackx.jingle_ibb.JingleInBandBytestreamTransportManager;
|
import org.jivesoftware.smackx.jingle_ibb2.JingleIBBTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle_s5b.JingleSocks5BytestreamTransportManager;
|
|
||||||
import org.jxmpp.jid.FullJid;
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +77,9 @@ public final class JingleFileTransferManager extends Manager implements JingleHa
|
||||||
NAMESPACE_V5, this);
|
NAMESPACE_V5, this);
|
||||||
JingleContentProviderManager.addJingleContentDescriptionProvider(
|
JingleContentProviderManager.addJingleContentDescriptionProvider(
|
||||||
NAMESPACE_V5, new JingleFileTransferContentDescriptionProvider());
|
NAMESPACE_V5, new JingleFileTransferContentDescriptionProvider());
|
||||||
JingleInBandBytestreamTransportManager.getInstanceFor(connection);
|
JingleIBBTransportManager.getInstanceFor(connection);
|
||||||
|
//JingleInBandBytestreamTransportManager.getInstanceFor(connection);
|
||||||
|
//JingleSocks5BytestreamTransportManager.getInstanceFor(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,37 +111,34 @@ public final class JingleFileTransferManager extends Manager implements JingleHa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addFileTransferRejectedListener() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QnD method.
|
* QnD method.
|
||||||
* @param file
|
* @param file
|
||||||
*/
|
*/
|
||||||
public void sendFile(File file, final FullJid recipient) throws IOException, SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException {
|
public void sendFile(File file, final FullJid recipient) throws IOException, SmackException, InterruptedException, XMPPException {
|
||||||
AbstractJingleContentTransportManager<?> preferredTransportManager = JingleSocks5BytestreamTransportManager.getInstanceFor(connection());
|
JingleBytestreamManager<?> tm = JingleTransportManager.getInstanceFor(connection())
|
||||||
|
.getAvailableJingleBytestreamManagers().iterator().next();
|
||||||
|
|
||||||
JingleFileTransferSession session = new JingleFileTransferSession(connection(), recipient, connection().getUser(), recipient);
|
|
||||||
JingleFileTransferChildElement.Builder b = JingleFileTransferChildElement.getBuilder();
|
JingleFileTransferChildElement.Builder b = JingleFileTransferChildElement.getBuilder();
|
||||||
b.setFile(file);
|
b.setFile(file);
|
||||||
byte[] buf = new byte[(int) file.length()];
|
|
||||||
HashElement hashElement = FileAndHashReader.readAndCalculateHash(file, buf, HashManager.ALGORITHM.SHA_256);
|
|
||||||
b.setHash(hashElement);
|
|
||||||
b.setDescription("File");
|
b.setDescription("File");
|
||||||
b.setMediaType("text/plain");
|
b.setMediaType("application/octet-stream");
|
||||||
|
|
||||||
session.setBytes(buf);
|
JingleFileTransferContentDescription description = new JingleFileTransferContentDescription(
|
||||||
JingleManager.getInstanceFor(connection()).registerJingleSession(session);
|
Collections.singletonList((JingleContentDescriptionChildElement) b.build()));
|
||||||
|
Jingle initiate = tm.createSessionInitiate(recipient, description);
|
||||||
|
|
||||||
ArrayList<JingleContentDescriptionChildElement> payloads = new ArrayList<>();
|
JingleManager.FullJidAndSessionId fullJidAndSessionId =
|
||||||
payloads.add(b.build());
|
new JingleManager.FullJidAndSessionId(recipient, initiate.getSid());
|
||||||
|
|
||||||
JingleContent.Builder bb = JingleContent.getBuilder();
|
jingleManager.registerJingleSessionHandler(recipient, initiate.getSid(),
|
||||||
bb.setDescription(new JingleFileTransferContentDescription(payloads))
|
new OutgoingFileTransferInitiator(this, fullJidAndSessionId, file));
|
||||||
.setCreator(JingleContent.Creator.initiator)
|
|
||||||
.setName(StringUtils.randomString(24))
|
|
||||||
.addTransport(preferredTransportManager.createJingleContentTransport(recipient));
|
|
||||||
|
|
||||||
Jingle jingle = (Jingle) session.initiate(Collections.singletonList(bb.build()));
|
connection().sendStanza(initiate);
|
||||||
jingle.setTo(recipient);
|
|
||||||
connection().sendStanza(jingle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FullJid ourJid() {
|
public FullJid ourJid() {
|
||||||
|
@ -148,9 +146,49 @@ public final class JingleFileTransferManager extends Manager implements JingleHa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IQ handleJingleRequest(Jingle jingle) {
|
public IQ handleJingleSessionInitiate(final Jingle jingle) {
|
||||||
JingleFileTransferSession session = new JingleFileTransferSession(connection(), jingle);
|
if (jingle.getAction() != JingleAction.session_initiate) {
|
||||||
JingleManager.getInstanceFor(connection()).registerJingleSession(session);
|
//TODO tie-break?
|
||||||
return session.handleRequest(jingle);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
JingleTransportManager tm = JingleTransportManager.getInstanceFor(connection());
|
||||||
|
String transportNamespace = jingle.getContents().get(0).getJingleTransports().get(0).getNamespace();
|
||||||
|
|
||||||
|
JingleBytestreamManager<?> transportManager = null;
|
||||||
|
for (JingleBytestreamManager<?> b : tm.getAvailableJingleBytestreamManagers()) {
|
||||||
|
if (b.getNamespace().equals(transportNamespace)) {
|
||||||
|
transportManager = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transportManager == null) {
|
||||||
|
//TODO unsupported-transport?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final JingleBytestreamManager<?> finalTransportManager = transportManager;
|
||||||
|
|
||||||
|
notifyIncomingFileTransferListeners(jingle, new IncomingJingleFileTransferCallback() {
|
||||||
|
@Override
|
||||||
|
public void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, UnsupportedJingleTransportException, SmackException.NoResponseException {
|
||||||
|
connection().sendStanza(finalTransportManager.createSessionAccept(jingle));
|
||||||
|
IncomingFileTransferResponded responded = new IncomingFileTransferResponded(JingleFileTransferManager.this, jingle, target);
|
||||||
|
jingleManager.registerJingleSessionHandler(jingle.getFrom().asFullJidIfPossible(), jingle.getSid(),
|
||||||
|
responded);
|
||||||
|
finalTransportManager.setIncomingRespondedSessionListener(jingle, responded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return IQ.createResultIQ(jingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMPPConnection getConnection() {
|
||||||
|
return connection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_filetransfer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleInputStream;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportInputStreamCallback;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingJingleFileTransferCallback;
|
|
||||||
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement;
|
|
||||||
import org.jivesoftware.smackx.jingle_ibb.JingleInBandBytestreamTransportManager;
|
|
||||||
import org.jxmpp.jid.FullJid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent a jingle file transfer session.
|
|
||||||
*/
|
|
||||||
public class JingleFileTransferSession extends JingleSession {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(JingleFileTransferSession.class.getName());
|
|
||||||
|
|
||||||
private byte[] buffer;
|
|
||||||
|
|
||||||
public JingleFileTransferSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder, String sid) {
|
|
||||||
super(connection, remote, initiator, responder, sid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleFileTransferSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder) {
|
|
||||||
super(connection, remote, initiator, responder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleFileTransferSession(XMPPConnection connection, Jingle initiate) {
|
|
||||||
super(connection, initiate);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBytes(byte[] bytes) {
|
|
||||||
this.buffer = bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSessionInitiate(final Jingle jingle) {
|
|
||||||
JingleFileTransferManager jfm = JingleFileTransferManager.getInstanceFor(connection);
|
|
||||||
jfm.notifyIncomingFileTransferListeners(jingle, new IncomingJingleFileTransferCallback() {
|
|
||||||
@Override
|
|
||||||
public void acceptFileTransfer(final File target) throws SmackException.NotConnectedException, InterruptedException {
|
|
||||||
connection.sendStanza(accept(jingle));
|
|
||||||
JingleInBandBytestreamTransportManager.getInstanceFor(connection).acceptInputStream(jingle, new JingleTransportInputStreamCallback() {
|
|
||||||
@Override
|
|
||||||
public void onInputStream(JingleInputStream inputStream) {
|
|
||||||
receive(inputStream, target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException {
|
|
||||||
connection.sendStanza(terminateFormally());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAccept(Jingle jingle) {
|
|
||||||
this.contents = jingle.getContents();
|
|
||||||
JingleInBandBytestreamTransportManager jibb = JingleInBandBytestreamTransportManager.getInstanceFor(connection);
|
|
||||||
OutputStream outputStream = jibb.createOutputStream(jingle);
|
|
||||||
|
|
||||||
if (outputStream == null) {
|
|
||||||
LOGGER.log(Level.SEVERE, "OutputStream is null!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
send(outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(OutputStream outputStream) {
|
|
||||||
try {
|
|
||||||
outputStream.write(buffer);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Caught exception while writing to output stream: " + e, e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
outputStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Could not close output stream: " + e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void receive(JingleInputStream in, File file) {
|
|
||||||
JingleFileTransferChildElement payload = (JingleFileTransferChildElement) contents.get(0).getDescription().getJingleContentDescriptionChildren().get(0);
|
|
||||||
InputStream inputStream = in.getInputStream();
|
|
||||||
byte[] fileBuffer = new byte[payload.getSize()];
|
|
||||||
byte[] packetBuffer = new byte[in.getBlockSize()];
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileOutputStream outputStream = new FileOutputStream(file);
|
|
||||||
int read = 0, count = 0;
|
|
||||||
while (read > -1 && read < fileBuffer.length) {
|
|
||||||
int r = inputStream.read(packetBuffer);
|
|
||||||
read += r;
|
|
||||||
System.arraycopy(packetBuffer, 0, fileBuffer, packetBuffer.length * count, r);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputStream.close();
|
|
||||||
outputStream.write(fileBuffer);
|
|
||||||
outputStream.close();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Caught exception while receiving and writing file: " + e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTerminate(Jingle jingle) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,13 +19,15 @@ package org.jivesoftware.smackx.jingle_filetransfer.callback;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that allows the user to accept or cancel file transfers.
|
* Callback that allows the user to accept or cancel file transfers.
|
||||||
*/
|
*/
|
||||||
public interface IncomingJingleFileTransferCallback {
|
public interface IncomingJingleFileTransferCallback {
|
||||||
|
|
||||||
void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException;
|
void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, UnsupportedJingleTransportException, SmackException.NoResponseException;
|
||||||
|
|
||||||
void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException;
|
void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_filetransfer.handler;
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by vanitas on 02.06.17.
|
|
||||||
*/
|
|
||||||
public interface FileOfferHandler {
|
|
||||||
void handleFileOffer(Jingle jingle);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_filetransfer.handler;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by vanitas on 02.06.17.
|
|
||||||
*/
|
|
||||||
public interface FileRequestHandler {
|
|
||||||
|
|
||||||
IQ handleFileRequest(Jingle jingle);
|
|
||||||
}
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
package org.jivesoftware.smackx.jingle_filetransfer.handler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleSessionHandler;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by vanitas on 09.06.17.
|
||||||
|
*/
|
||||||
|
public class IncomingFileTransferResponded implements JingleSessionHandler, BytestreamListener {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IncomingFileTransferResponded.class.getName());
|
||||||
|
|
||||||
|
private final WeakReference<JingleFileTransferManager> manager;
|
||||||
|
private final File target;
|
||||||
|
private final int size;
|
||||||
|
private final FullJid initiator;
|
||||||
|
private final String sessionId;
|
||||||
|
|
||||||
|
public IncomingFileTransferResponded(JingleFileTransferManager manager, Jingle initiate, File target) {
|
||||||
|
this.manager = new WeakReference<>(manager);
|
||||||
|
this.target = target;
|
||||||
|
this.size = ((JingleFileTransferChildElement) initiate.getContents().get(0).getDescription()
|
||||||
|
.getJingleContentDescriptionChildren().get(0)).getSize();
|
||||||
|
this.initiator = initiate.getInitiator();
|
||||||
|
this.sessionId = initiate.getSid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incomingBytestreamRequest(BytestreamRequest request) {
|
||||||
|
if (!request.getFrom().asFullJidIfPossible().equals(initiator) || !sessionId.equals(request.getSessionID())) {
|
||||||
|
LOGGER.log(Level.INFO, "Not our session.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BytestreamSession session;
|
||||||
|
try {
|
||||||
|
session = request.accept();
|
||||||
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Exception while accepting session: " + e, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[] fileBuf = new byte[size];
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
InputStream inputStream = null;
|
||||||
|
FileOutputStream fileOutputStream = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!target.exists()) {
|
||||||
|
target.createNewFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOutputStream = new FileOutputStream(target);
|
||||||
|
inputStream = session.getInputStream();
|
||||||
|
|
||||||
|
int read = 0;
|
||||||
|
while (read < fileBuf.length) {
|
||||||
|
int r = inputStream.read(buf);
|
||||||
|
if (r != -1) {
|
||||||
|
System.arraycopy(buf, 0, fileBuf, read, r);
|
||||||
|
read += r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOutputStream.write(fileBuf);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Caught IOException while receiving files: " + e, e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inputStream != null) {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
if (fileOutputStream != null) {
|
||||||
|
fileOutputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Caught Exception while closing streams: " + e, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IQ handleJingleSessionRequest(Jingle jingle, String sessionId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package org.jivesoftware.smackx.jingle_filetransfer.handler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
|
import org.jivesoftware.smackx.hashes.HashManager;
|
||||||
|
import org.jivesoftware.smackx.hashes.element.HashElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleBytestreamManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleSessionHandler;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.FileAndHashReader;
|
||||||
|
import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by vanitas on 09.06.17.
|
||||||
|
*/
|
||||||
|
public class OutgoingFileTransferInitiator implements JingleSessionHandler {
|
||||||
|
|
||||||
|
private final WeakReference<JingleFileTransferManager> manager;
|
||||||
|
private final JingleManager.FullJidAndSessionId fullJidAndSessionId;
|
||||||
|
private final File file;
|
||||||
|
|
||||||
|
public OutgoingFileTransferInitiator(JingleFileTransferManager manager, JingleManager.FullJidAndSessionId fullJidAndSessionId, File file) {
|
||||||
|
this.fullJidAndSessionId = fullJidAndSessionId;
|
||||||
|
this.file = file;
|
||||||
|
this.manager = new WeakReference<>(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IQ handleJingleSessionRequest(Jingle jingle, String sessionId) {
|
||||||
|
JingleBytestreamManager<?> bm;
|
||||||
|
try {
|
||||||
|
bm = JingleTransportManager.getInstanceFor(manager.get().getConnection())
|
||||||
|
.getJingleContentTransportManager(jingle);
|
||||||
|
} catch (UnsupportedJingleTransportException e) {
|
||||||
|
// TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (jingle.getAction()) {
|
||||||
|
case session_accept:
|
||||||
|
BytestreamSession session;
|
||||||
|
|
||||||
|
try {
|
||||||
|
session = bm.outgoingInitiatedSession(jingle);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//TODO
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashElement fileHash;
|
||||||
|
byte[] buf = new byte[(int) file.length()];
|
||||||
|
|
||||||
|
try {
|
||||||
|
fileHash = FileAndHashReader.readAndCalculateHash(file, buf, HashManager.ALGORITHM.SHA_256);
|
||||||
|
session.getOutputStream().write(buf);
|
||||||
|
session.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
//TODO:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case session_terminate:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return IQ.createResultIQ(jingle);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,131 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_ibb;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.AbstractJingleContentTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleInputStream;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportInputStreamCallback;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
|
||||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
|
||||||
import org.jivesoftware.smackx.jingle_ibb.element.JingleInBandBytestreamTransport;
|
|
||||||
import org.jivesoftware.smackx.jingle_ibb.provider.JingleInBandByteStreamTransportProvider;
|
|
||||||
import org.jxmpp.jid.Jid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manager for Jingle In-Band-Bytestreams.
|
|
||||||
*/
|
|
||||||
public final class JingleInBandBytestreamTransportManager extends AbstractJingleContentTransportManager<JingleInBandBytestreamTransport> {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(JingleInBandBytestreamTransportManager.class.getName());
|
|
||||||
public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:ibb:1";
|
|
||||||
|
|
||||||
private static final WeakHashMap<XMPPConnection, JingleInBandBytestreamTransportManager> INSTANCES = new WeakHashMap<>();
|
|
||||||
|
|
||||||
private JingleInBandBytestreamTransportManager(XMPPConnection connection) {
|
|
||||||
super(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected JingleContentTransportProvider<JingleInBandBytestreamTransport> createJingleContentTransportProvider() {
|
|
||||||
return new JingleInBandByteStreamTransportProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JingleInBandBytestreamTransportManager getInstanceFor(XMPPConnection connection) {
|
|
||||||
JingleInBandBytestreamTransportManager manager = INSTANCES.get(connection);
|
|
||||||
if (manager == null) {
|
|
||||||
manager = new JingleInBandBytestreamTransportManager(connection);
|
|
||||||
INSTANCES.put(connection, manager);
|
|
||||||
}
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getNamespace() {
|
|
||||||
return NAMESPACE_V1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void acceptInputStream(final Jingle jingle, final JingleTransportInputStreamCallback callback) {
|
|
||||||
final int blockSize = ((JingleInBandBytestreamTransport)
|
|
||||||
jingle.getContents().get(0).getJingleTransports().get(0)).getBlockSize();
|
|
||||||
InBandBytestreamListener bytestreamListener = new InBandBytestreamListener() {
|
|
||||||
@Override
|
|
||||||
public void incomingBytestreamRequest(InBandBytestreamRequest request) {
|
|
||||||
if (request.getSessionID().equals(jingle.getSid())) {
|
|
||||||
try {
|
|
||||||
InBandBytestreamSession ibs = request.accept();
|
|
||||||
InputStream inputStream = ibs.getInputStream();
|
|
||||||
callback.onInputStream(new JingleInputStream(inputStream, blockSize));
|
|
||||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Could not accept IBB session: " + e, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
InBandBytestreamManager.getByteStreamManager(connection())
|
|
||||||
.addIncomingBytestreamListener(bytestreamListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OutputStream createOutputStream(Jingle jingle) {
|
|
||||||
JingleInBandBytestreamTransport transport = null;
|
|
||||||
JingleContent content = jingle.getContents().get(0);
|
|
||||||
for (JingleContentTransport t : content.getJingleTransports()) {
|
|
||||||
if (t.getNamespace().equals(NAMESPACE_V1)) {
|
|
||||||
transport = (JingleInBandBytestreamTransport) t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transport == null) {
|
|
||||||
//TODO: Transport-failed
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
InBandBytestreamManager ibm = InBandBytestreamManager.getByteStreamManager(connection());
|
|
||||||
ibm.setMaximumBlockSize(transport.getBlockSize());
|
|
||||||
InBandBytestreamSession ibs;
|
|
||||||
try {
|
|
||||||
ibs = ibm.establishSession(jingle.getFrom(), jingle.getSid());
|
|
||||||
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Fail in handle request: " + e, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ibs.getOutputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JingleInBandBytestreamTransport createJingleContentTransport(Jid otherUser) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
|
||||||
return new JingleInBandBytestreamTransport();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* 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 API for <a href="https://xmpp.org/extensions/xep-0261.html">XEP-0261: Jingle In-Band Bytestreams</a>.
|
|
||||||
* Element classes.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_ibb.element;
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package org.jivesoftware.smackx.jingle_ibb2;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleBytestreamManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleAction;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
|
||||||
|
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||||
|
import org.jivesoftware.smackx.jingle_ibb2.element.JingleIBBTransport;
|
||||||
|
import org.jivesoftware.smackx.jingle_ibb2.provider.JingleIBBTransportProvider;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BytestreamManager for Jingle InBandBytestream Transports.
|
||||||
|
*/
|
||||||
|
public final class JingleIBBTransportManager extends JingleBytestreamManager<JingleIBBTransport> {
|
||||||
|
|
||||||
|
private static final WeakHashMap<XMPPConnection, JingleIBBTransportManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
public static JingleIBBTransportManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
JingleIBBTransportManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new JingleIBBTransportManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JingleIBBTransportManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application) throws XMPPException, IOException, InterruptedException, SmackException {
|
||||||
|
return createSessionInitiate(targetJID, application, JingleTransportManager.generateRandomId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application, String sessionID) throws XMPPException, IOException, InterruptedException, SmackException {
|
||||||
|
Jingle.Builder jb = Jingle.getBuilder();
|
||||||
|
JingleContent.Builder cb = JingleContent.getBuilder();
|
||||||
|
cb.setDescription(application)
|
||||||
|
.setName(JingleTransportManager.generateRandomId())
|
||||||
|
.setCreator(JingleContent.Creator.initiator)
|
||||||
|
.setSenders(JingleContent.Senders.initiator)
|
||||||
|
.addTransport(new JingleIBBTransport());
|
||||||
|
jb.addJingleContent(cb.build());
|
||||||
|
jb.setInitiator(connection().getUser())
|
||||||
|
.setResponder(targetJID)
|
||||||
|
.setSessionId(sessionID)
|
||||||
|
.setAction(JingleAction.session_initiate);
|
||||||
|
Jingle jingle = jb.build();
|
||||||
|
jingle.setTo(targetJID);
|
||||||
|
jingle.setFrom(connection().getUser());
|
||||||
|
jingle.setType(IQ.Type.set);
|
||||||
|
return jingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Jingle createSessionAccept(Jingle request) {
|
||||||
|
Jingle.Builder jb = Jingle.getBuilder();
|
||||||
|
jb.setAction(JingleAction.session_accept)
|
||||||
|
.setSessionId(request.getSid())
|
||||||
|
.setResponder(connection().getUser());
|
||||||
|
|
||||||
|
JingleContent requestContent = request.getContents().get(0);
|
||||||
|
JingleContent.Builder cb = JingleContent.getBuilder();
|
||||||
|
cb.setDescription(requestContent.getDescription())
|
||||||
|
.setSenders(requestContent.getSenders())
|
||||||
|
.setCreator(requestContent.getCreator())
|
||||||
|
.setName(requestContent.getName());
|
||||||
|
cb.addTransport(requestContent.getJingleTransports().get(0));
|
||||||
|
|
||||||
|
jb.addJingleContent(cb.build());
|
||||||
|
Jingle jingle = jb.build();
|
||||||
|
jingle.setType(IQ.Type.set);
|
||||||
|
jingle.setTo(request.getFrom());
|
||||||
|
jingle.setFrom(connection().getUser());
|
||||||
|
return jingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytestreamSession outgoingInitiatedSession(Jingle jingle) throws Exception {
|
||||||
|
InBandBytestreamManager ibb = InBandBytestreamManager.getByteStreamManager(connection());
|
||||||
|
return ibb.establishSession(jingle.getResponder(), jingle.getSid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIncomingRespondedSessionListener(Jingle jingle, BytestreamListener listener) {
|
||||||
|
InBandBytestreamManager.getByteStreamManager(connection()).addIncomingBytestreamListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
//###############################################
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JingleContentTransportProvider<JingleIBBTransport> createJingleContentTransportProvider() {
|
||||||
|
return new JingleIBBTransportProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return JingleIBBTransport.NAMESPACE_V1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,47 +1,31 @@
|
||||||
/**
|
package org.jivesoftware.smackx.jingle_ibb2.element;
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle_ibb.element;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
import org.jivesoftware.smackx.jingle_ibb.JingleInBandBytestreamTransportManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jingle In-Band-ByteStream transport.
|
* Transport Element for JingleInBandBytestream transports.
|
||||||
*/
|
*/
|
||||||
public class JingleInBandBytestreamTransport extends JingleContentTransport {
|
public class JingleIBBTransport extends JingleContentTransport {
|
||||||
|
public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:ibb:1";
|
||||||
public static final String ATTR_BLOCK_SIZE = "block-size";
|
public static final String ATTR_BLOCK_SIZE = "block-size";
|
||||||
public static final String ATTR_SID = "sid";
|
public static final String ATTR_SID = "sid";
|
||||||
|
|
||||||
public static final short DEFAULT_BLOCK_SIZE = 4096;
|
public static final short DEFAULT_BLOCK_SIZE = 4096;
|
||||||
|
|
||||||
private final short blockSize;
|
private final short blockSize;
|
||||||
private final String sid;
|
private final String sid;
|
||||||
|
|
||||||
public JingleInBandBytestreamTransport() {
|
public JingleIBBTransport() {
|
||||||
this(DEFAULT_BLOCK_SIZE);
|
this(DEFAULT_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleInBandBytestreamTransport(short blockSize) {
|
public JingleIBBTransport(short blockSize) {
|
||||||
this(blockSize, JingleTransportManager.generateRandomId());
|
this(blockSize, JingleTransportManager.generateRandomId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleInBandBytestreamTransport(short blockSize, String sid) {
|
public JingleIBBTransport(short blockSize, String sid) {
|
||||||
super(null);
|
super(null);
|
||||||
if (blockSize > 0) {
|
if (blockSize > 0) {
|
||||||
this.blockSize = blockSize;
|
this.blockSize = blockSize;
|
||||||
|
@ -67,16 +51,16 @@ public class JingleInBandBytestreamTransport extends JingleContentTransport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNamespace() {
|
public String getNamespace() {
|
||||||
return JingleInBandBytestreamTransportManager.NAMESPACE_V1;
|
return NAMESPACE_V1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !(other instanceof JingleInBandBytestreamTransport)) {
|
if (other == null || !(other instanceof JingleIBBTransport)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.hashCode() == other.hashCode();
|
return this == other || this.hashCode() == other.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -18,4 +18,4 @@
|
||||||
/**
|
/**
|
||||||
* Smack's API for <a href="https://xmpp.org/extensions/xep-0261.html">XEP-0261: Jingle In-Band Bytestreams</a>.
|
* Smack's API for <a href="https://xmpp.org/extensions/xep-0261.html">XEP-0261: Jingle In-Band Bytestreams</a>.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle_ibb;
|
package org.jivesoftware.smackx.jingle_ibb2;
|
|
@ -14,26 +14,26 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle_ibb.provider;
|
package org.jivesoftware.smackx.jingle_ibb2.provider;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||||
import org.jivesoftware.smackx.jingle_ibb.element.JingleInBandBytestreamTransport;
|
import org.jivesoftware.smackx.jingle_ibb2.element.JingleIBBTransport;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse JingleByteStreamTransport elements.
|
* Parse JingleByteStreamTransport elements.
|
||||||
*/
|
*/
|
||||||
public class JingleInBandByteStreamTransportProvider extends JingleContentTransportProvider<JingleInBandBytestreamTransport> {
|
public class JingleIBBTransportProvider extends JingleContentTransportProvider<JingleIBBTransport> {
|
||||||
@Override
|
@Override
|
||||||
public JingleInBandBytestreamTransport parse(XmlPullParser parser, int initialDepth) throws Exception {
|
public JingleIBBTransport parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
String blockSizeString = parser.getAttributeValue(null, JingleInBandBytestreamTransport.ATTR_BLOCK_SIZE);
|
String blockSizeString = parser.getAttributeValue(null, JingleIBBTransport.ATTR_BLOCK_SIZE);
|
||||||
String sid = parser.getAttributeValue(null, JingleInBandBytestreamTransport.ATTR_SID);
|
String sid = parser.getAttributeValue(null, JingleIBBTransport.ATTR_SID);
|
||||||
|
|
||||||
short blockSize = -1;
|
short blockSize = -1;
|
||||||
if (blockSizeString != null) {
|
if (blockSizeString != null) {
|
||||||
blockSize = Short.valueOf(blockSizeString);
|
blockSize = Short.valueOf(blockSizeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JingleInBandBytestreamTransport(blockSize, sid);
|
return new JingleIBBTransport(blockSize, sid);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,4 +19,4 @@
|
||||||
* Smack's API for <a href="https://xmpp.org/extensions/xep-0261.html">XEP-0261: Jingle In-Band Bytestreams</a>.
|
* Smack's API for <a href="https://xmpp.org/extensions/xep-0261.html">XEP-0261: Jingle In-Band Bytestreams</a>.
|
||||||
* Provider classes.
|
* Provider classes.
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle_ibb.provider;
|
package org.jivesoftware.smackx.jingle_ibb2.provider;
|
|
@ -16,30 +16,37 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle_s5b;
|
package org.jivesoftware.smackx.jingle_s5b;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
|
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
import org.jivesoftware.smackx.hashes.HashManager;
|
import org.jivesoftware.smackx.hashes.HashManager;
|
||||||
import org.jivesoftware.smackx.jingle.AbstractJingleContentTransportManager;
|
import org.jivesoftware.smackx.jingle.JingleBytestreamManager;
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportInputStreamCallback;
|
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||||
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport;
|
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport;
|
||||||
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate;
|
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle_s5b.provider.JingleSocks5BytestreamTransportProvider;
|
import org.jivesoftware.smackx.jingle_s5b.provider.JingleSocks5BytestreamTransportProvider;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager for JingleSocks5BytestreamTransports.
|
* Manager for JingleSocks5BytestreamTransports.
|
||||||
*/
|
*/
|
||||||
public final class JingleSocks5BytestreamTransportManager extends AbstractJingleContentTransportManager<JingleSocks5BytestreamTransport> {
|
public final class JingleSocks5BytestreamTransportManager extends JingleBytestreamManager<JingleSocks5BytestreamTransport> {
|
||||||
|
|
||||||
private static final WeakHashMap<XMPPConnection, JingleSocks5BytestreamTransportManager> INSTANCES = new WeakHashMap<>();
|
private static final WeakHashMap<XMPPConnection, JingleSocks5BytestreamTransportManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
@ -59,7 +66,7 @@ public final class JingleSocks5BytestreamTransportManager extends AbstractJingle
|
||||||
public List<Bytestream.StreamHost> getAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
public List<Bytestream.StreamHost> getAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
||||||
Socks5BytestreamManager s5m = Socks5BytestreamManager.getBytestreamManager(connection());
|
Socks5BytestreamManager s5m = Socks5BytestreamManager.getBytestreamManager(connection());
|
||||||
List<Jid> proxies = s5m.determineProxies();
|
List<Jid> proxies = s5m.determineProxies();
|
||||||
return s5m.determineStreamHostInfos(proxies);
|
return determineStreamHostInfos(proxies);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Bytestream.StreamHost> getLocalStreamHosts() {
|
public List<Bytestream.StreamHost> getLocalStreamHosts() {
|
||||||
|
@ -67,6 +74,33 @@ public final class JingleSocks5BytestreamTransportManager extends AbstractJingle
|
||||||
.getLocalStreamHost();
|
.getLocalStreamHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Bytestream.StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
||||||
|
XMPPConnection connection = connection();
|
||||||
|
List<Bytestream.StreamHost> streamHosts = new ArrayList<>();
|
||||||
|
|
||||||
|
Iterator<Jid> iterator = proxies.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Jid proxy = iterator.next();
|
||||||
|
Bytestream request = new Bytestream();
|
||||||
|
request.setType(IQ.Type.get);
|
||||||
|
request.setTo(proxy);
|
||||||
|
try {
|
||||||
|
Bytestream response = connection.createStanzaCollectorAndSend(request).nextResultOrThrow();
|
||||||
|
streamHosts.addAll(response.getStreamHosts());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return streamHosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectToStreamHost() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JingleContentTransportProvider<JingleSocks5BytestreamTransport> createJingleContentTransportProvider() {
|
protected JingleContentTransportProvider<JingleSocks5BytestreamTransport> createJingleContentTransportProvider() {
|
||||||
return new JingleSocks5BytestreamTransportProvider();
|
return new JingleSocks5BytestreamTransportProvider();
|
||||||
|
@ -78,19 +112,29 @@ public final class JingleSocks5BytestreamTransportManager extends AbstractJingle
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptInputStream(Jingle jingle, JingleTransportInputStreamCallback callback) {
|
public Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application, String sessionId) throws XMPPException, IOException, InterruptedException, SmackException {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OutputStream createOutputStream(Jingle jingle) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JingleSocks5BytestreamTransport createJingleContentTransport(Jid otherUser) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
public Jingle createSessionAccept(Jingle request) {
|
||||||
JingleSocks5BytestreamTransport.Builder builder = JingleSocks5BytestreamTransport.getBuilder();
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BytestreamSession outgoingInitiatedSession(Jingle jingle) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIncomingRespondedSessionListener(Jingle jingle, BytestreamListener listener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public JingleSocks5BytestreamTransport createJingleContentTransport(Jid remote, JingleContentTransport received_) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
|
||||||
|
JingleSocks5BytestreamTransport received = (JingleSocks5BytestreamTransport) received_;
|
||||||
|
|
||||||
|
JingleSocks5BytestreamTransport.Builder builder = JingleSocks5BytestreamTransport.getBuilder();
|
||||||
List<Bytestream.StreamHost> localStreams = getLocalStreamHosts();
|
List<Bytestream.StreamHost> localStreams = getLocalStreamHosts();
|
||||||
List<Bytestream.StreamHost> availableStreams = getAvailableStreamHosts();
|
List<Bytestream.StreamHost> availableStreams = getAvailableStreamHosts();
|
||||||
|
|
||||||
|
@ -104,14 +148,23 @@ public final class JingleSocks5BytestreamTransportManager extends AbstractJingle
|
||||||
builder.addTransportCandidate(candidate);
|
builder.addTransportCandidate(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setMode(Bytestream.Mode.tcp);
|
String sid = (received == null ? JingleTransportManager.generateRandomId() : received.getStreamId());
|
||||||
String sid = JingleTransportManager.generateRandomId();
|
|
||||||
builder.setStreamId(sid);
|
builder.setStreamId(sid);
|
||||||
|
builder.setMode(received == null ? Bytestream.Mode.tcp : received.getMode());
|
||||||
|
|
||||||
String digestString =
|
String digestString =
|
||||||
sid +
|
sid +
|
||||||
connection().getUser().asFullJidIfPossible().toString() +
|
connection().getUser().asFullJidIfPossible().toString() +
|
||||||
otherUser.asFullJidIfPossible().toString();
|
remote.asFullJidIfPossible().toString();
|
||||||
builder.setDestinationAddress(HashManager.sha_1HexString(digestString));
|
builder.setDestinationAddress(HashManager.sha_1HexString(digestString));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Session {
|
||||||
|
private ArrayList<Bytestream.StreamHost> ourStreamHosts;
|
||||||
|
private ArrayList<Bytestream.StreamHost> theirStreamHosts;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@ import static org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5Bytestream
|
||||||
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||||
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport;
|
import org.jivesoftware.smackx.jingle_s5b.elements.JingleSocks5BytestreamTransport;
|
||||||
|
@ -42,21 +39,17 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
*/
|
*/
|
||||||
public class JingleSocks5BytestreamTransportProvider extends JingleContentTransportProvider<JingleSocks5BytestreamTransport> {
|
public class JingleSocks5BytestreamTransportProvider extends JingleContentTransportProvider<JingleSocks5BytestreamTransport> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(JingleSocks5BytestreamTransportProvider.class.getName());
|
|
||||||
@Override
|
@Override
|
||||||
public JingleSocks5BytestreamTransport parse(XmlPullParser parser, int initialDepth) throws Exception {
|
public JingleSocks5BytestreamTransport parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
JingleSocks5BytestreamTransport.Builder builder = JingleSocks5BytestreamTransport.getBuilder();
|
JingleSocks5BytestreamTransport.Builder builder = JingleSocks5BytestreamTransport.getBuilder();
|
||||||
|
|
||||||
String streamId = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_SID);
|
String streamId = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_SID);
|
||||||
LOGGER.log(Level.INFO, "streamId: " + streamId);
|
|
||||||
builder.setStreamId(streamId);
|
builder.setStreamId(streamId);
|
||||||
|
|
||||||
String dstAddr = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_DSTADDR);
|
String dstAddr = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_DSTADDR);
|
||||||
LOGGER.log(Level.INFO, "dstAddr: " + dstAddr);
|
|
||||||
builder.setDestinationAddress(dstAddr);
|
builder.setDestinationAddress(dstAddr);
|
||||||
|
|
||||||
String mode = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_MODE);
|
String mode = parser.getAttributeValue(null, JingleSocks5BytestreamTransport.ATTR_MODE);
|
||||||
LOGGER.log(Level.INFO, "Mode: " + mode);
|
|
||||||
if (mode != null) {
|
if (mode != null) {
|
||||||
builder.setMode(mode.equals(udp.toString()) ? udp : tcp);
|
builder.setMode(mode.equals(udp.toString()) ? udp : tcp);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +62,6 @@ public class JingleSocks5BytestreamTransportProvider extends JingleContentTransp
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
||||||
case JingleSocks5BytestreamTransportCandidate.ELEMENT:
|
case JingleSocks5BytestreamTransportCandidate.ELEMENT:
|
||||||
LOGGER.log(Level.SEVERE, "Payload");
|
|
||||||
cb = JingleSocks5BytestreamTransportCandidate.getBuilder();
|
cb = JingleSocks5BytestreamTransportCandidate.getBuilder();
|
||||||
cb.setCandidateId(parser.getAttributeValue(null, ATTR_CID));
|
cb.setCandidateId(parser.getAttributeValue(null, ATTR_CID));
|
||||||
cb.setHost(parser.getAttributeValue(null, ATTR_HOST));
|
cb.setHost(parser.getAttributeValue(null, ATTR_HOST));
|
||||||
|
@ -89,26 +81,22 @@ public class JingleSocks5BytestreamTransportProvider extends JingleContentTransp
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleSocks5BytestreamTransportInfo.CandidateActivated.ELEMENT:
|
case JingleSocks5BytestreamTransportInfo.CandidateActivated.ELEMENT:
|
||||||
LOGGER.log(Level.INFO, "Candidate-Activated found");
|
|
||||||
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateActivated(
|
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateActivated(
|
||||||
parser.getAttributeValue(null,
|
parser.getAttributeValue(null,
|
||||||
JingleSocks5BytestreamTransportInfo.CandidateActivated.ATTR_CID)));
|
JingleSocks5BytestreamTransportInfo.CandidateActivated.ATTR_CID)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleSocks5BytestreamTransportInfo.CandidateUsed.ELEMENT:
|
case JingleSocks5BytestreamTransportInfo.CandidateUsed.ELEMENT:
|
||||||
LOGGER.log(Level.INFO, "Candidate-Used found");
|
|
||||||
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateUsed(
|
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateUsed(
|
||||||
parser.getAttributeValue(null,
|
parser.getAttributeValue(null,
|
||||||
JingleSocks5BytestreamTransportInfo.CandidateUsed.ATTR_CID)));
|
JingleSocks5BytestreamTransportInfo.CandidateUsed.ATTR_CID)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleSocks5BytestreamTransportInfo.CandidateError.ELEMENT:
|
case JingleSocks5BytestreamTransportInfo.CandidateError.ELEMENT:
|
||||||
LOGGER.log(Level.INFO, "Candidate-Error found");
|
|
||||||
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateError());
|
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.CandidateError());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleSocks5BytestreamTransportInfo.ProxyError.ELEMENT:
|
case JingleSocks5BytestreamTransportInfo.ProxyError.ELEMENT:
|
||||||
LOGGER.log(Level.INFO, "Proxy-Error found");
|
|
||||||
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.ProxyError());
|
builder.addTransportInfo(JingleSocks5BytestreamTransportInfo.ProxyError());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,14 @@ import static junit.framework.TestCase.assertTrue;
|
||||||
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
import org.jivesoftware.smack.test.util.TestUtils;
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
import org.jivesoftware.smackx.jingle.JingleTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle_ibb.element.JingleInBandBytestreamTransport;
|
import org.jivesoftware.smackx.jingle_ibb2.element.JingleIBBTransport;
|
||||||
import org.jivesoftware.smackx.jingle_ibb.provider.JingleInBandByteStreamTransportProvider;
|
import org.jivesoftware.smackx.jingle_ibb2.provider.JingleIBBTransportProvider;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test JingleInBandByteStreamTransport provider and element.
|
* Test JingleIBBTransport provider and element.
|
||||||
*/
|
*/
|
||||||
public class JingleInBandByteStreamTransportTest extends SmackTestSuite {
|
public class JingleIBBTransportTest extends SmackTestSuite {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parserTest() throws Exception {
|
public void parserTest() throws Exception {
|
||||||
|
@ -40,32 +40,32 @@ public class JingleInBandByteStreamTransportTest extends SmackTestSuite {
|
||||||
|
|
||||||
String xml = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='8192' sid='" + sid + "'/>";
|
String xml = "<transport xmlns='urn:xmpp:jingle:transports:ibb:1' block-size='8192' sid='" + sid + "'/>";
|
||||||
|
|
||||||
JingleInBandBytestreamTransport transport = new JingleInBandBytestreamTransport(size, sid);
|
JingleIBBTransport transport = new JingleIBBTransport(size, sid);
|
||||||
assertEquals(xml, transport.toXML().toString());
|
assertEquals(xml, transport.toXML().toString());
|
||||||
assertEquals(size, transport.getBlockSize());
|
assertEquals(size, transport.getBlockSize());
|
||||||
assertEquals(sid, transport.getSessionId());
|
assertEquals(sid, transport.getSessionId());
|
||||||
|
|
||||||
JingleInBandBytestreamTransport parsed = new JingleInBandByteStreamTransportProvider()
|
JingleIBBTransport parsed = new JingleIBBTransportProvider()
|
||||||
.parse(TestUtils.getParser(xml));
|
.parse(TestUtils.getParser(xml));
|
||||||
assertEquals(transport, parsed);
|
assertEquals(transport, parsed);
|
||||||
assertTrue(transport.equals(parsed));
|
assertTrue(transport.equals(parsed));
|
||||||
assertEquals(xml, parsed.toXML().toString());
|
assertEquals(xml, parsed.toXML().toString());
|
||||||
|
|
||||||
JingleInBandBytestreamTransport transport1 = new JingleInBandBytestreamTransport((short) 1024);
|
JingleIBBTransport transport1 = new JingleIBBTransport((short) 1024);
|
||||||
assertEquals((short) 1024, transport1.getBlockSize());
|
assertEquals((short) 1024, transport1.getBlockSize());
|
||||||
assertNotSame(transport, transport1);
|
assertNotSame(transport, transport1);
|
||||||
assertNotSame(transport.getSessionId(), transport1.getSessionId());
|
assertNotSame(transport.getSessionId(), transport1.getSessionId());
|
||||||
|
|
||||||
assertFalse(transport.equals(null));
|
assertFalse(transport.equals(null));
|
||||||
|
|
||||||
JingleInBandBytestreamTransport transport2 = new JingleInBandBytestreamTransport();
|
JingleIBBTransport transport2 = new JingleIBBTransport();
|
||||||
assertEquals(JingleInBandBytestreamTransport.DEFAULT_BLOCK_SIZE, transport2.getBlockSize());
|
assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport2.getBlockSize());
|
||||||
assertFalse(transport1.equals(transport2));
|
assertFalse(transport1.equals(transport2));
|
||||||
|
|
||||||
JingleInBandBytestreamTransport transport3 = new JingleInBandBytestreamTransport((short) -1024);
|
JingleIBBTransport transport3 = new JingleIBBTransport((short) -1024);
|
||||||
assertEquals(JingleInBandBytestreamTransport.DEFAULT_BLOCK_SIZE, transport3.getBlockSize());
|
assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport3.getBlockSize());
|
||||||
|
|
||||||
assertEquals(transport3.getNamespace(), JingleInBandBytestreamTransportManager.NAMESPACE_V1);
|
assertEquals(transport3.getNamespace(), JingleIBBTransport.NAMESPACE_V1);
|
||||||
assertEquals(transport3.getElementName(), "transport");
|
assertEquals(transport3.getElementName(), "transport");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -585,7 +585,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
* @param proxies a list of SOCKS5 proxy JIDs
|
* @param proxies a list of SOCKS5 proxy JIDs
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
public List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
private List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
||||||
XMPPConnection connection = connection();
|
XMPPConnection connection = connection();
|
||||||
List<StreamHost> streamHosts = new ArrayList<StreamHost>();
|
List<StreamHost> streamHosts = new ArrayList<StreamHost>();
|
||||||
|
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.Manager;
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
|
||||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
|
||||||
import org.jxmpp.jid.Jid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface with methods that JingleContentTransportManagers must implement.
|
|
||||||
*/
|
|
||||||
public abstract class AbstractJingleContentTransportManager<D extends JingleContentTransport> extends Manager {
|
|
||||||
|
|
||||||
public AbstractJingleContentTransportManager(XMPPConnection connection) {
|
|
||||||
super(connection);
|
|
||||||
JingleTransportManager.getInstanceFor(connection).registerJingleContentTransportManager(this);
|
|
||||||
JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), createJingleContentTransportProvider());
|
|
||||||
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract JingleContentTransportProvider<D> createJingleContentTransportProvider();
|
|
||||||
|
|
||||||
public abstract String getNamespace();
|
|
||||||
|
|
||||||
public abstract void acceptInputStream(Jingle jingle, JingleTransportInputStreamCallback callback);
|
|
||||||
|
|
||||||
public abstract OutputStream createOutputStream(Jingle jingle);
|
|
||||||
|
|
||||||
public abstract D createJingleContentTransport(Jid remote) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException;
|
|
||||||
}
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package org.jivesoftware.smackx.jingle;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
|
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by vanitas on 09.06.17.
|
||||||
|
*/
|
||||||
|
public abstract class JingleBytestreamManager<D extends JingleContentTransport>
|
||||||
|
extends Manager {
|
||||||
|
|
||||||
|
public JingleBytestreamManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
JingleTransportManager.getInstanceFor(connection).registerJingleContentTransportManager(this);
|
||||||
|
JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), createJingleContentTransportProvider());
|
||||||
|
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract JingleContentTransportProvider<D> createJingleContentTransportProvider();
|
||||||
|
|
||||||
|
public abstract String getNamespace();
|
||||||
|
|
||||||
|
public Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application) throws XMPPException, IOException, InterruptedException, SmackException {
|
||||||
|
return createSessionInitiate(targetJID, application, JingleTransportManager.generateRandomId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application, String sessionId) throws XMPPException, IOException, InterruptedException, SmackException;
|
||||||
|
|
||||||
|
public abstract Jingle createSessionAccept(Jingle request);
|
||||||
|
|
||||||
|
public abstract BytestreamSession outgoingInitiatedSession(Jingle jingle) throws Exception;
|
||||||
|
|
||||||
|
public abstract void setIncomingRespondedSessionListener(Jingle jingle, BytestreamListener listener);
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,6 @@ import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
|
||||||
public interface JingleHandler {
|
public interface JingleHandler {
|
||||||
|
|
||||||
IQ handleJingleRequest(Jingle jingle);
|
IQ handleJingleSessionInitiate(Jingle jingle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle;
|
package org.jivesoftware.smackx.jingle;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
@ -54,7 +53,7 @@ public final class JingleManager extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, JingleHandler> descriptionHandlers = new ConcurrentHashMap<>();
|
private final Map<String, JingleHandler> descriptionHandlers = new ConcurrentHashMap<>();
|
||||||
private final Map<FullJidAndSessionId, JingleSession> jingleSessions = new ConcurrentHashMap<>();
|
private final Map<FullJidAndSessionId, JingleSessionHandler> jingleSessionHandlers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private JingleManager(final XMPPConnection connection) {
|
private JingleManager(final XMPPConnection connection) {
|
||||||
super(connection);
|
super(connection);
|
||||||
|
@ -71,16 +70,16 @@ public final class JingleManager extends Manager {
|
||||||
assert (from != null);
|
assert (from != null);
|
||||||
FullJid fullFrom = from.asFullJidOrThrow();
|
FullJid fullFrom = from.asFullJidOrThrow();
|
||||||
FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, jingle.getSid());
|
FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, jingle.getSid());
|
||||||
JingleSession jingleSession = jingleSessions.get(fullJidAndSessionId);
|
JingleSessionHandler jingleSessionHandler = jingleSessionHandlers.get(fullJidAndSessionId);
|
||||||
|
|
||||||
if (jingleSession == null) {
|
if (jingleSessionHandler == null) {
|
||||||
// Handle unknown session (XEP-0166 §10)
|
// Handle unknown session (XEP-0166 §10)
|
||||||
XMPPError.Builder errorBuilder = XMPPError.getBuilder();
|
XMPPError.Builder errorBuilder = XMPPError.getBuilder();
|
||||||
errorBuilder.setCondition(XMPPError.Condition.item_not_found)
|
errorBuilder.setCondition(XMPPError.Condition.item_not_found)
|
||||||
.addExtension(JingleError.UNKNOWN_SESSION);
|
.addExtension(JingleError.UNKNOWN_SESSION);
|
||||||
return IQ.createErrorResponse(jingle, errorBuilder);
|
return IQ.createErrorResponse(jingle, errorBuilder);
|
||||||
}
|
}
|
||||||
return jingleSession.handleRequest(jingle);
|
return jingleSessionHandler.handleJingleSessionRequest(jingle, jingle.getSid());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jingle.getContents().size() > 1) {
|
if (jingle.getContents().size() > 1) {
|
||||||
|
@ -104,33 +103,41 @@ public final class JingleManager extends Manager {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return jingleDescriptionHandler.handleJingleRequest(jingle);
|
return jingleDescriptionHandler.handleJingleSessionInitiate(jingle);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerJingleSession(JingleSession session) {
|
public void registerJingleSessionHandler(FullJid jid, String sessionId, JingleSessionHandler sessionHandler) {
|
||||||
FullJidAndSessionId jidAndSid = new FullJidAndSessionId(session.getRemote(), session.getSid());
|
jingleSessionHandlers.put(new FullJidAndSessionId(jid, sessionId), sessionHandler);
|
||||||
jingleSessions.put(jidAndSid, session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterJingleSession(JingleSession session) {
|
public void unregisterJingleSession(FullJid jid, String sessionId) {
|
||||||
jingleSessions.values().removeAll(Collections.singleton(session));
|
jingleSessionHandlers.remove(new FullJidAndSessionId(jid, sessionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) {
|
public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) {
|
||||||
return descriptionHandlers.put(namespace, handler);
|
return descriptionHandlers.put(namespace, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class FullJidAndSessionId {
|
public static final class FullJidAndSessionId {
|
||||||
final FullJid fullJid;
|
final FullJid fullJid;
|
||||||
final String sessionId;
|
final String sessionId;
|
||||||
|
|
||||||
private FullJidAndSessionId(FullJid fullJid, String sessionId) {
|
public FullJidAndSessionId(FullJid fullJid, String sessionId) {
|
||||||
this.fullJid = fullJid;
|
this.fullJid = fullJid;
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FullJid getFullJid() {
|
||||||
|
return fullJid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hashCode = 31 * fullJid.hashCode();
|
int hashCode = 31 * fullJid.hashCode();
|
||||||
|
|
|
@ -1,247 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright 2017 Paul Schaub
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.jivesoftware.smackx.jingle;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleAction;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleError;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleReason;
|
|
||||||
import org.jxmpp.jid.FullJid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JingleSession.
|
|
||||||
*/
|
|
||||||
public abstract class JingleSession {
|
|
||||||
|
|
||||||
public enum State {
|
|
||||||
fresh,
|
|
||||||
pending,
|
|
||||||
accepted,
|
|
||||||
terminated,
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final XMPPConnection connection;
|
|
||||||
protected final FullJid initiator;
|
|
||||||
protected final FullJid responder;
|
|
||||||
protected final FullJid ourJid;
|
|
||||||
protected final FullJid remote;
|
|
||||||
protected final String sid;
|
|
||||||
protected State sessionState;
|
|
||||||
protected List<JingleContent> contents;
|
|
||||||
|
|
||||||
public JingleSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder, String sid) {
|
|
||||||
this.connection = connection;
|
|
||||||
this.ourJid = connection.getUser();
|
|
||||||
this.remote = remote;
|
|
||||||
this.initiator = initiator;
|
|
||||||
this.responder = responder;
|
|
||||||
this.sid = sid;
|
|
||||||
this.sessionState = State.fresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder) {
|
|
||||||
this(connection, remote, initiator, responder, StringUtils.randomString(24));
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleSession(XMPPConnection connection, Jingle initiate) {
|
|
||||||
if (initiate.getAction() != JingleAction.session_initiate) {
|
|
||||||
throw new AssertionError("Session cannot be created without session-initiate");
|
|
||||||
}
|
|
||||||
this.connection = connection;
|
|
||||||
this.ourJid = connection.getUser();
|
|
||||||
this.remote = initiate.getFrom().asFullJidIfPossible();
|
|
||||||
this.initiator = initiate.getInitiator();
|
|
||||||
this.responder = initiate.getResponder();
|
|
||||||
this.sid = initiate.getSid();
|
|
||||||
this.sessionState = State.fresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FullJid getInitiator() {
|
|
||||||
return initiator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FullJid getResponder() {
|
|
||||||
return responder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FullJid getRemote() {
|
|
||||||
return remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FullJid getOurJid() {
|
|
||||||
return ourJid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSid() {
|
|
||||||
return sid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public State getSessionState() {
|
|
||||||
return sessionState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleRequest(Jingle jingle) {
|
|
||||||
switch (jingle.getAction()) {
|
|
||||||
case session_initiate:
|
|
||||||
// Did we already get another session-initiate?
|
|
||||||
if (sessionState != State.fresh) {
|
|
||||||
return outOfOrder(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Keep local copy of contents
|
|
||||||
contents = jingle.getContents();
|
|
||||||
|
|
||||||
onSessionInitiate(jingle);
|
|
||||||
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
|
|
||||||
case session_accept:
|
|
||||||
if (sessionState != State.pending) {
|
|
||||||
return outOfOrder(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
onAccept(jingle);
|
|
||||||
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
|
|
||||||
case session_terminate:
|
|
||||||
|
|
||||||
onTerminate(jingle);
|
|
||||||
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
|
|
||||||
case content_add:
|
|
||||||
//TODO: Inform listeners
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
|
|
||||||
default: return IQ.createResultIQ(jingle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void onSessionInitiate(Jingle jingle);
|
|
||||||
|
|
||||||
public abstract void onAccept(Jingle jingle);
|
|
||||||
|
|
||||||
public abstract void onTerminate(Jingle jingle);
|
|
||||||
|
|
||||||
public IQ initiate(List<JingleContent> contents) {
|
|
||||||
Jingle.Builder b = Jingle.getBuilder();
|
|
||||||
b.setInitiator(initiator)
|
|
||||||
.setAction(JingleAction.session_initiate)
|
|
||||||
.setSessionId(sid);
|
|
||||||
for (JingleContent c : contents) {
|
|
||||||
b.addJingleContent(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
Jingle j = b.build();
|
|
||||||
j.setTo(remote);
|
|
||||||
j.setFrom(ourJid);
|
|
||||||
this.sessionState = State.pending;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ accept(Jingle jingle) {
|
|
||||||
Jingle.Builder b = Jingle.getBuilder();
|
|
||||||
b.setResponder(ourJid)
|
|
||||||
.setAction(JingleAction.session_accept)
|
|
||||||
.setSessionId(sid);
|
|
||||||
for (JingleContent c : jingle.getContents()) {
|
|
||||||
b.addJingleContent(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
Jingle j = b.build();
|
|
||||||
j.setTo(remote);
|
|
||||||
j.setFrom(ourJid);
|
|
||||||
this.sessionState = State.accepted;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminate(JingleReason.Reason reason) {
|
|
||||||
Jingle.Builder b = Jingle.getBuilder();
|
|
||||||
b.setAction(JingleAction.session_terminate)
|
|
||||||
.setSessionId(sid)
|
|
||||||
.setReason(reason);
|
|
||||||
Jingle j = b.build();
|
|
||||||
j.setTo(remote);
|
|
||||||
j.setFrom(ourJid);
|
|
||||||
this.sessionState = State.terminated;
|
|
||||||
return b.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateFormally() {
|
|
||||||
return terminate(JingleReason.Reason.decline);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Fix
|
|
||||||
public IQ terminateAlternativeSession(String alternative) {
|
|
||||||
Jingle.Builder b = Jingle.getBuilder();
|
|
||||||
b.setAction(JingleAction.session_terminate)
|
|
||||||
.setSessionId(sid)
|
|
||||||
.setReason(JingleReason.Reason.alternative_session); //Set alt. sessionId
|
|
||||||
Jingle j = b.build();
|
|
||||||
j.setTo(remote);
|
|
||||||
j.setFrom(ourJid);
|
|
||||||
this.sessionState = State.terminated;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateSuccessfully() {
|
|
||||||
return terminate(JingleReason.Reason.success);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateBusy() {
|
|
||||||
return terminate(JingleReason.Reason.busy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateUnsupportedTransports() {
|
|
||||||
return terminate(JingleReason.Reason.unsupported_transports);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateFailedTransport() {
|
|
||||||
return terminate(JingleReason.Reason.failed_transport);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateUnsupportedApplications() {
|
|
||||||
return terminate(JingleReason.Reason.unsupported_applications);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateFailedApplication() {
|
|
||||||
return terminate(JingleReason.Reason.failed_application);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ terminateIncompatibleParameters() {
|
|
||||||
return terminate(JingleReason.Reason.incompatible_parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ unknownInitiator(Jingle jingle) {
|
|
||||||
return IQ.createErrorResponse(jingle, XMPPError.Condition.service_unavailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ outOfOrder(Jingle jingle) {
|
|
||||||
XMPPError.Builder b = XMPPError.getBuilder();
|
|
||||||
b.setCondition(XMPPError.Condition.unexpected_request);
|
|
||||||
b.addExtension(JingleError.OUT_OF_ORDER);
|
|
||||||
return IQ.createErrorResponse(jingle, b);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,12 +16,15 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle;
|
package org.jivesoftware.smackx.jingle;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +34,7 @@ public final class JingleTransportManager extends Manager {
|
||||||
|
|
||||||
public static final WeakHashMap<XMPPConnection, JingleTransportManager> INSTANCES = new WeakHashMap<>();
|
public static final WeakHashMap<XMPPConnection, JingleTransportManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
private final HashMap<String, AbstractJingleContentTransportManager<?>> contentTransportManagers = new HashMap<>();
|
private final HashMap<String, JingleBytestreamManager<?>> contentTransportManagers = new HashMap<>();
|
||||||
|
|
||||||
private JingleTransportManager(XMPPConnection connection) {
|
private JingleTransportManager(XMPPConnection connection) {
|
||||||
super(connection);
|
super(connection);
|
||||||
|
@ -46,22 +49,30 @@ public final class JingleTransportManager extends Manager {
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractJingleContentTransportManager<?> getJingleContentTransportManager(String namespace) throws UnsupportedJingleTransportException {
|
public JingleBytestreamManager<?> getJingleContentTransportManager(String namespace) throws UnsupportedJingleTransportException {
|
||||||
AbstractJingleContentTransportManager<?> manager = contentTransportManagers.get(namespace);
|
JingleBytestreamManager<?> manager = contentTransportManagers.get(namespace);
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
throw new UnsupportedJingleTransportException("Cannot find registered JingleContentTransportManager for " + namespace);
|
throw new UnsupportedJingleTransportException("Cannot find registered JingleContentTransportManager for " + namespace);
|
||||||
}
|
}
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerJingleContentTransportManager(AbstractJingleContentTransportManager<?> manager) {
|
public JingleBytestreamManager<?> getJingleContentTransportManager(Jingle jingle) throws UnsupportedJingleTransportException {
|
||||||
|
return getJingleContentTransportManager(jingle.getContents().get(0).getJingleTransports().get(0).getNamespace());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerJingleContentTransportManager(JingleBytestreamManager<?> manager) {
|
||||||
contentTransportManagers.put(manager.getNamespace(), manager);
|
contentTransportManagers.put(manager.getNamespace(), manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterJingleContentTransportManager(AbstractJingleContentTransportManager<?> manager) {
|
public void unregisterJingleContentTransportManager(JingleBytestreamManager<?> manager) {
|
||||||
contentTransportManagers.remove(manager.getNamespace());
|
contentTransportManagers.remove(manager.getNamespace());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<JingleBytestreamManager<?>> getAvailableJingleBytestreamManagers() {
|
||||||
|
return Collections.unmodifiableCollection(contentTransportManagers.values());
|
||||||
|
}
|
||||||
|
|
||||||
public static String generateRandomId() {
|
public static String generateRandomId() {
|
||||||
return StringUtils.randomString(24);
|
return StringUtils.randomString(24);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.jivesoftware.smackx.jingle;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by vanitas on 09.06.17.
|
||||||
|
*/
|
||||||
|
public class PendingJingleSession {
|
||||||
|
|
||||||
|
public PendingJingleSession(Jingle initiation, File file) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue