diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/AbstractJingleSession.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/AbstractJingleSession.java new file mode 100644 index 000000000..7d5b34e14 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/AbstractJingleSession.java @@ -0,0 +1,138 @@ +/** + * + * 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 org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.jingle.JingleSessionHandler; +import org.jivesoftware.smackx.jingle.element.Jingle; + +/** + * AbstractJingleSession that implements basic handler methods that basically do nothing. + */ +public abstract class AbstractJingleSession implements JingleSessionHandler { + + protected final XMPPConnection connection; + protected AbstractJingleSession state; + + public AbstractJingleSession(XMPPConnection connection) { + this.connection = connection; + } + + @Override + public IQ handleJingleSessionRequest(Jingle jingle) { + switch (jingle.getAction()) { + case content_accept: + return handleContentAccept(jingle); + case content_add: + return handleContentAdd(jingle); + case content_modify: + return handleContentModify(jingle); + case content_reject: + return handleContentReject(jingle); + case content_remove: + return handleContentRemove(jingle); + case description_info: + return handleDescriptionInfo(jingle); + case session_info: + return handleSessionInfo(jingle); + case security_info: + return handleSecurityInfo(jingle); + case session_accept: + return handleSessionAccept(jingle); + case transport_accept: + return handleTransportAccept(jingle); + case transport_info: + return handleTransportInfo(jingle); + case session_initiate: + return handleSessionInitiate(jingle); + case transport_reject: + return handleTransportReject(jingle); + case session_terminate: + return handleSessionTerminate(jingle); + case transport_replace: + return handleTransportReplace(jingle); + default: + return IQ.createResultIQ(jingle); + } + } + + protected IQ handleSessionInitiate(Jingle sessionInitiate) { + return IQ.createResultIQ(sessionInitiate); + } + + protected IQ handleSessionTerminate(Jingle sessionTerminate) { + return IQ.createResultIQ(sessionTerminate); + } + + protected IQ handleSessionInfo(Jingle sessionInfo) { + return IQ.createResultIQ(sessionInfo); + } + + protected IQ handleSessionAccept(Jingle sessionAccept) { + return IQ.createResultIQ(sessionAccept); + } + + protected IQ handleContentAdd(Jingle contentAdd) { + return IQ.createResultIQ(contentAdd); + } + + protected IQ handleContentAccept(Jingle contentAccept) { + return IQ.createResultIQ(contentAccept); + } + + protected IQ handleContentModify(Jingle contentModify) { + return IQ.createResultIQ(contentModify); + } + + protected IQ handleContentReject(Jingle contentReject) { + return IQ.createResultIQ(contentReject); + } + + protected IQ handleContentRemove(Jingle contentRemove) { + return IQ.createResultIQ(contentRemove); + } + + protected IQ handleDescriptionInfo(Jingle descriptionInfo) { + return IQ.createResultIQ(descriptionInfo); + } + + protected IQ handleSecurityInfo(Jingle securityInfo) { + return IQ.createResultIQ(securityInfo); + } + + protected IQ handleTransportAccept(Jingle transportAccept) { + return IQ.createResultIQ(transportAccept); + } + + protected IQ handleTransportInfo(Jingle transportInfo) { + return IQ.createResultIQ(transportInfo); + } + + protected IQ handleTransportReplace(Jingle transportReplace) { + return IQ.createResultIQ(transportReplace); + } + + protected IQ handleTransportReject(Jingle transportReject) { + return IQ.createResultIQ(transportReject); + } + + @Override + public XMPPConnection getConnection() { + return connection; + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java index 0e67e62c1..3e85c55db 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Paul Schaub + * 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. @@ -17,87 +17,41 @@ package org.jivesoftware.smackx.jingle_filetransfer; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.HashMap; import java.util.WeakHashMap; -import java.util.logging.Logger; import org.jivesoftware.smack.Manager; -import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.util.StringUtils; -import org.jivesoftware.smackx.bytestreams.BytestreamSession; -import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; -import org.jivesoftware.smackx.hashes.HashManager; -import org.jivesoftware.smackx.hashes.element.HashElement; -import org.jivesoftware.smackx.jingle.AbstractJingleTransportManager; -import org.jivesoftware.smackx.jingle.JingleContentProviderManager; import org.jivesoftware.smackx.jingle.JingleHandler; import org.jivesoftware.smackx.jingle.JingleManager; -import org.jivesoftware.smackx.jingle.JingleTransportEstablishedCallback; -import org.jivesoftware.smackx.jingle.JingleTransportHandler; -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.element.JingleContentDescriptionChildElement; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.element.JingleReason; -import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; import org.jivesoftware.smackx.jingle_filetransfer.callback.JingleFileTransferCallback; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; -import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferContentDescription; -import org.jivesoftware.smackx.jingle_filetransfer.handler.InitiatorOutgoingFileTransferInitiated; -import org.jivesoftware.smackx.jingle_filetransfer.handler.ResponderIncomingFileTransferAccepted; import org.jivesoftware.smackx.jingle_filetransfer.listener.IncomingJingleFileTransferListener; -import org.jivesoftware.smackx.jingle_filetransfer.provider.JingleFileTransferContentDescriptionProvider; -import org.jivesoftware.smackx.jingle_s5b.JingleS5BTransportManager; +import org.jivesoftware.smackx.jingle_ibb.JingleIBBTransportManager; import org.jxmpp.jid.FullJid; /** - * Manager for Jingle File Transfers. - * - * @author Paul Schaub + * Manager for JingleFileTransfer. */ public final class JingleFileTransferManager extends Manager implements JingleHandler { - - private static final Logger LOGGER = Logger.getLogger(JingleFileTransferManager.class.getName()); - public static final String NAMESPACE_V5 = "urn:xmpp:jingle:apps:file-transfer:5"; - private final JingleManager jingleManager; private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - private final HashSet incomingJingleFileTransferListeners = new HashSet<>(); - /** - * Private constructor. This registers a JingleContentDescriptionFileTransferProvider with the - * JingleContentProviderManager. - * @param connection connection - */ + private final ArrayList incomingJFTListeners = new ArrayList<>(); + + private HashMap jingleSessions = new HashMap<>(); + private JingleFileTransferManager(XMPPConnection connection) { super(connection); - ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); - sdm.addFeature(NAMESPACE_V5); - jingleManager = JingleManager.getInstanceFor(connection); - jingleManager.registerDescriptionHandler( - NAMESPACE_V5, this); - JingleContentProviderManager.addJingleContentDescriptionProvider( - NAMESPACE_V5, new JingleFileTransferContentDescriptionProvider()); - //JingleIBBTransportManager.getInstanceFor(connection); - JingleS5BTransportManager.getInstanceFor(connection); + JingleManager.getInstanceFor(connection).registerDescriptionHandler(NAMESPACE_V5, this); + JingleIBBTransportManager.getInstanceFor(connection); + //JingleS5BTransportManager.getInstanceFor(connection); } - /** - * Return a new instance of the FileTransferManager for the given connection. - * - * @param connection XMPPConnection we wish to get a FileTransferManager for. - * @return manager instance. - */ public static JingleFileTransferManager getInstanceFor(XMPPConnection connection) { JingleFileTransferManager manager = INSTANCES.get(connection); if (manager == null) { @@ -107,211 +61,37 @@ public final class JingleFileTransferManager extends Manager implements JingleHa return manager; } - public void addIncomingFileTransferListener(IncomingJingleFileTransferListener listener) { - incomingJingleFileTransferListeners.add(listener); + public void addIncomingJingleFileTransferListener(IncomingJingleFileTransferListener listener) { + incomingJFTListeners.add(listener); } - public void removeIncomingFileTransferListener(IncomingJingleFileTransferListener listener) { - incomingJingleFileTransferListeners.remove(listener); - } - - void notifyIncomingFileTransferListeners(Jingle jingle, JingleFileTransferCallback callback) { - for (IncomingJingleFileTransferListener l : incomingJingleFileTransferListeners) { - l.onIncomingJingleFileTransfer(jingle, callback); + void notifyIncomingJingleFileTransferListeners(JingleFileTransferChild file, JingleFileTransferCallback callback) { + for (IncomingJingleFileTransferListener l : incomingJFTListeners) { + l.onIncomingJingleFileTransfer(file, callback); } } - /** - * QnD method. - * @param file - */ - public void sendFile(final File file, final FullJid recipient) throws Exception { - AbstractJingleTransportManager tm = JingleTransportManager.getInstanceFor(connection()) - .getAvailableJingleBytestreamManagers().iterator().next(); - - JingleFileTransferChild.Builder b = JingleFileTransferChild.getBuilder(); - b.setFile(file); - b.setDescription("File"); - b.setMediaType("application/octet-stream"); - - JingleFileTransferContentDescription description = new JingleFileTransferContentDescription( - Collections.singletonList((JingleContentDescriptionChildElement) b.build())); - - JingleContentTransport transport = tm.createJingleContentTransport(recipient); - Jingle initiate = sessionInitiate(recipient, description, transport); - - JingleManager.FullJidAndSessionId fullJidAndSessionId = - new JingleManager.FullJidAndSessionId(recipient, initiate.getSessionId()); - - InitiatorOutgoingFileTransferInitiated sessionHandler = - new InitiatorOutgoingFileTransferInitiated(this, fullJidAndSessionId, file); - - jingleManager.registerJingleSessionHandler(recipient, initiate.getSessionId(), sessionHandler); - - JingleTransportHandler transportHandler = tm.createJingleTransportHandler(sessionHandler); - connection().sendStanza(initiate); - transportHandler.establishOutgoingSession(initiate, new JingleTransportEstablishedCallback() { - @Override - public void onSessionEstablished(BytestreamSession bytestreamSession) { - try { - byte[] filebuf = new byte[(int) file.length()]; - HashElement hashElement = FileAndHashReader.readAndCalculateHash(file, filebuf, HashManager.ALGORITHM.SHA_256); - bytestreamSession.getInputStream().read(filebuf); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - bytestreamSession.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - @Override - public void onSessionFailure(JingleTransportFailureException reason) { - - } - }); + public void addJingleSession(JingleFileTransferSession session) { + jingleSessions.put(session.getFullJidAndSessionId(), session); } - public FullJid ourJid() { - return connection().getUser(); + public JingleFileTransferSession getJingleSession(JingleManager.FullJidAndSessionId fullJidAndSessionId) { + return jingleSessions.get(fullJidAndSessionId); + } + + public void removeJingleSession(JingleFileTransferSession session) { + jingleSessions.remove(session.getFullJidAndSessionId()); } @Override - public IQ handleJingleSessionInitiate(final Jingle jingle) { - if (jingle.getAction() != JingleAction.session_initiate) { - //TODO tie-break? - return null; - } - - notifyIncomingFileTransferListeners(jingle, new JingleFileTransferCallback() { - @Override - public void acceptFileTransfer(final File target) throws Exception { - connection().sendStanza(sessionAccept(jingle)); - ResponderIncomingFileTransferAccepted responded = new ResponderIncomingFileTransferAccepted( - JingleFileTransferManager.this, jingle, target); - jingleManager.registerJingleSessionHandler(jingle.getFrom().asFullJidIfPossible(), jingle.getSessionId(), - responded); - } - - @Override - public void declineFileTransfer() throws SmackException.NotConnectedException, InterruptedException { - connection().sendStanza(decline(jingle)); - } - }); - - return IQ.createResultIQ(jingle); + public IQ handleJingleSessionInitiate(Jingle jingle) { + JingleFileTransferSession fresh = new JingleFileTransferSession(connection(), jingle); + addJingleSession(fresh); + return fresh.handleJingleSessionRequest(jingle); } - public Jingle sessionInitiate(FullJid recipient, JingleContentDescription contentDescription, JingleContentTransport transport) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(StringUtils.randomString(24)) - .setAction(JingleAction.session_initiate) - .setInitiator(connection().getUser()); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setDescription(contentDescription) - .setName(StringUtils.randomString(24)) - .setCreator(JingleContent.Creator.initiator) - .setSenders(JingleContent.Senders.initiator) - .addTransport(transport); - - jb.addJingleContent(cb.build()); - Jingle jingle = jb.build(); - jingle.setFrom(connection().getUser()); - jingle.setTo(recipient); - - return jingle; - } - - public Jingle sessionAccept(Jingle request) throws Exception { - JingleContent content = request.getContents().get(0); - - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(request.getSessionId()) - .setAction(JingleAction.session_accept) - .setResponder(connection().getUser()); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setSenders(content.getSenders()) - .setCreator(content.getCreator()) - .setName(content.getName()) - .setDescription(content.getDescription()); - - AbstractJingleTransportManager tm = JingleTransportManager.getInstanceFor(connection()) - .getJingleContentTransportManager(request); - - JingleContentTransport transport = tm.createJingleContentTransport(request); - cb.addTransport(transport); - - jb.addJingleContent(cb.build()); - Jingle jingle = jb.build(); - jingle.setFrom(connection().getUser()); - jingle.setTo(request.getFrom()); - - return jingle; - } - - public Jingle decline(Jingle request) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setResponder(connection().getUser()) - .setAction(JingleAction.session_terminate) - .setReason(JingleReason.Reason.decline) - .setSessionId(request.getSessionId()); - Jingle jingle = jb.build(); - jingle.setTo(request.getFrom()); - jingle.setFrom(connection().getUser()); - return jingle; - } - - public void receiveFile(Jingle request, BytestreamSession session, File target) { - JingleFileTransferChild file = (JingleFileTransferChild) - request.getContents().get(0).getDescription().getJingleContentDescriptionChildren().get(0); - - InputStream inputStream = null; - FileOutputStream outputStream = null; - - try { - if (!target.exists()) { - target.createNewFile(); - } - - inputStream = session.getInputStream(); - outputStream = new FileOutputStream(target); - - byte[] fileBuf = new byte[file.getSize()]; - byte[] buf = new byte[2048]; - int read = 0; - while (read < fileBuf.length) { - int r = inputStream.read(buf); - if (r >= 0) { - System.arraycopy(buf, 0, fileBuf, read, r); - read += r; - } - } - - outputStream.write(fileBuf); - - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - if (inputStream != null) { - inputStream.close(); - } - if (outputStream != null) { - outputStream.close(); - } - session.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public XMPPConnection getConnection() { - return connection(); + public void sendFile(FullJid recipient, File file) { + JingleFileTransferSession fresh = new JingleFileTransferSession(connection(), recipient, file); + addJingleSession(fresh); } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java new file mode 100644 index 000000000..d0c7758af --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java @@ -0,0 +1,513 @@ +/** + * + * 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.util.Collections; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.hashes.HashManager; +import org.jivesoftware.smackx.hashes.element.HashElement; +import org.jivesoftware.smackx.jingle.AbstractJingleTransportManager; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.JingleTransportEstablishedCallback; +import org.jivesoftware.smackx.jingle.JingleTransportHandler; +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.JingleContentDescriptionChildElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleReason; +import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException; +import org.jivesoftware.smackx.jingle_filetransfer.callback.JingleFileTransferCallback; +import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; +import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferContentDescription; +import org.jxmpp.jid.FullJid; + +/** + * JingleSession. + */ +public class JingleFileTransferSession extends AbstractJingleSession { + + private static final Logger LOGGER = Logger.getLogger(JingleFileTransferSession.class.getName()); + + private final File source; + private File target; + private final JingleContent proposedContent; + private final FullJid remote; + private final String sessionId; + + /** + * Send a file. + * @param connection + * @param send + */ + public JingleFileTransferSession(XMPPConnection connection, FullJid recipient, File send) { + super(connection); + this.remote = recipient; + this.source = send; + this.sessionId = StringUtils.randomString(24); + + JingleFileTransferChild fileTransferChild = fileElementFromFile(send); + JingleContent.Builder cb = JingleContent.getBuilder(); + cb.setSenders(JingleContent.Senders.initiator) + .setCreator(JingleContent.Creator.initiator) + .setName(StringUtils.randomString(24)) + .setDescription(new JingleFileTransferContentDescription( + Collections.singletonList((JingleContentDescriptionChildElement) fileTransferChild))); + try { + cb.addTransport(defaultTransport()); + } catch (Exception e) { + throw new AssertionError("At least IBB should work. " + e); + } + + this.proposedContent = cb.build(); + + try { + connection.sendStanza(createFileOffer()); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Could not send session-initiate: " + e, e); + return; + } + + this.state = new OutgoingInitiated(connection, this); + } + + /** + * Receive a file. + * @param connection + */ + public JingleFileTransferSession(XMPPConnection connection, Jingle initiate) { + super(connection); + this.sessionId = initiate.getSessionId(); + this.remote = initiate.getInitiator(); + this.source = null; + this.proposedContent = initiate.getContents().get(0); + + this.state = new IncomingAccepted(connection, this); + } + + /** + * session-initiate has been sent. + */ + public static class OutgoingInitiated extends AbstractJingleSession { + + private final JingleFileTransferSession parent; + + public OutgoingInitiated(XMPPConnection connection, JingleFileTransferSession parent) { + super(connection); + this.parent = parent; + } + + @Override + protected IQ handleSessionAccept(Jingle jingle) { + parent.state = new OutgoingAccepted(connection, parent); + //TODO: Notify parent + return IQ.createResultIQ(jingle); + } + + @Override + protected IQ handleSessionTerminate(Jingle jingle) { + //TODO: notify client + JingleFileTransferManager.getInstanceFor(connection).removeJingleSession(parent); + return IQ.createResultIQ(jingle); + } + + } + + public static class OutgoingAccepted extends AbstractJingleSession { + private final JingleFileTransferSession parent; + + public OutgoingAccepted(XMPPConnection connection, final JingleFileTransferSession parent) { + super(connection); + this.parent = parent; + + AbstractJingleTransportManager tm; + try { + tm = JingleTransportManager.getJingleContentTransportManager(connection, + parent.proposedContent.getJingleTransports().get(0)); + } catch (UnsupportedJingleTransportException e) { + throw new AssertionError("Since we initiated the transport, we MUST know the transport method."); + } + + JingleTransportHandler transportHandler = tm.createJingleTransportHandler(this); + transportHandler.establishOutgoingSession(parent.getFullJidAndSessionId(), + parent.proposedContent, parent.outgoingFileTransferSessionEstablishedCallback); + } + } + + public static class IncomingFresh extends AbstractJingleSession { + private final JingleFileTransferSession parent; + + public IncomingFresh(XMPPConnection connection, JingleFileTransferSession parent) { + super(connection); + this.parent = parent; + } + + @Override + protected IQ handleSessionInitiate(final Jingle initiate) { + if (initiate.getAction() != JingleAction.session_initiate) { + throw new IllegalArgumentException("Jingle action MUST be session-initiate!"); + } + + //Get + JingleFileTransferChild file = (JingleFileTransferChild) initiate.getContents().get(0) + .getDescription().getJingleContentDescriptionChildren().get(0); + + final JingleFileTransferCallback callback = new JingleFileTransferCallback() { + @Override + public void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException { + Jingle response = null; + try { + response = parent.createSessionAccept(initiate); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Could not create accept-session stanza: " + e, e); + } + + connection.sendStanza(response); + parent.target = target; + parent.state = new IncomingAccepted(connection, parent); + } + + @Override + public void declineFileTransfer() throws SmackException.NotConnectedException, InterruptedException { + connection.sendStanza(parent.createSessionDecline(initiate)); + parent.state = null; + JingleFileTransferManager.getInstanceFor(connection).removeJingleSession(parent); + } + }; + + //Set callback + JingleFileTransferManager.getInstanceFor(connection).notifyIncomingJingleFileTransferListeners(file, callback); + return IQ.createResultIQ(initiate); + } + } + + public static class IncomingAccepted extends AbstractJingleSession { + + public IncomingAccepted(XMPPConnection connection, JingleFileTransferSession parent) { + super(connection); + AbstractJingleTransportManager tm = null; + try { + tm = JingleTransportManager.getJingleContentTransportManager( + connection, parent.proposedContent.getJingleTransports().get(0)); + } catch (UnsupportedJingleTransportException e) { + throw new AssertionError("Since we accepted the transfer, we MUST know the transport method."); + } + + JingleTransportHandler transportHandler = tm.createJingleTransportHandler(this); + transportHandler.establishIncomingSession(parent.getFullJidAndSessionId(), + parent.proposedContent, parent.incomingFileTransferSessionEstablishedCallback); + } + } + + protected Jingle createFileOffer() throws Exception { + Jingle.Builder jb = Jingle.getBuilder(); + jb.setSessionId(sessionId) + .setAction(JingleAction.session_initiate) + .setInitiator(connection.getUser()); + + JingleContent.Builder cb = JingleContent.getBuilder(); + cb.setSenders(JingleContent.Senders.initiator) + .setCreator(JingleContent.Creator.initiator) + .setName(StringUtils.randomString(24)); + + cb.setDescription(new JingleFileTransferContentDescription(Collections.singletonList( + proposedContent.getDescription().getJingleContentDescriptionChildren().get(0)))); + + cb.addTransport(proposedContent.getJingleTransports().get(0)); + jb.addJingleContent(cb.build()); + + Jingle jingle = jb.build(); + jingle.setTo(remote); + jingle.setFrom(connection.getUser()); + + return jingle; + } + + protected Jingle createSessionAccept(Jingle jingle) throws Exception { + JingleContent content = jingle.getContents().get(0); + + Jingle.Builder jb = Jingle.getBuilder(); + jb.setAction(JingleAction.session_accept) + .setResponder(connection.getUser()) + .setSessionId(sessionId); + + JingleContent.Builder cb = JingleContent.getBuilder(); + + AbstractJingleTransportManager tm; + try { + tm = JingleTransportManager.getJingleContentTransportManager( + connection, jingle); + } catch (UnsupportedJingleTransportException e) { + throw new AssertionError("Should never happen."); //TODO: Make sure. + } + + cb.addTransport(tm.createJingleContentTransport(jingle)) + .setDescription(content.getDescription()) + .setName(content.getName()) + .setCreator(content.getCreator()) + .setSenders(content.getSenders()); + + jb.addJingleContent(cb.build()); + Jingle accept = jb.build(); + accept.setTo(remote); + accept.setFrom(connection.getUser()); + + return accept; + } + + public Jingle createSessionDecline(Jingle initiate) { + Jingle.Builder jb = Jingle.getBuilder(); + jb.setAction(JingleAction.session_terminate) + .setReason(JingleReason.Reason.decline) + .setResponder(connection.getUser()) + .setSessionId(sessionId); + + return jb.build(); + } + + static JingleFileTransferChild fileElementFromFile(File file) { + JingleFileTransferChild.Builder fb = JingleFileTransferChild.getBuilder(); + fb.setFile(file) + .setDescription("A File") + .setMediaType("application/octetStream"); + + return fb.build(); + } + + JingleContentTransport defaultTransport() { + JingleTransportManager transportManager = JingleTransportManager.getInstanceFor(connection); + JingleContentTransport transport = null; + Iterator> iterator = + transportManager.getAvailableJingleBytestreamManagers().iterator(); + + while (transport == null && iterator.hasNext()) { + AbstractJingleTransportManager tm = iterator.next(); + try { + transport = tm.createJingleContentTransport(remote); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Could not create JingleContentTransport " + tm.getNamespace() + + ". Skip."); + } + } + + return transport; + } + + protected JingleTransportEstablishedCallback outgoingFileTransferSessionEstablishedCallback = + new JingleTransportEstablishedCallback() { + @Override + public void onSessionEstablished(BytestreamSession bytestreamSession) { + send(bytestreamSession); + } + + @Override + public void onSessionFailure(JingleTransportFailureException reason) { + //TODO: Send transport-failed or so. + } + }; + + protected JingleTransportEstablishedCallback incomingFileTransferSessionEstablishedCallback = + new JingleTransportEstablishedCallback() { + @Override + public void onSessionEstablished(BytestreamSession bytestreamSession) { + read(bytestreamSession); + } + + @Override + public void onSessionFailure(JingleTransportFailureException reason) { + //TODO: Send transport failed + } + }; + + void send(BytestreamSession stream) { + if (source == null || !source.exists()) { + throw new IllegalStateException("Source file MUST NOT be null and MUST exist."); + } + + byte[] filebuf = new byte[(int) source.length()]; + HashElement hashElement = null; + try { + hashElement = FileAndHashReader.readAndCalculateHash(source, filebuf, HashManager.ALGORITHM.SHA_256); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not read file: " + e, e); + //TODO: Terminate session. + return; + } + + //TODO: session-info with hash + + try { + stream.getOutputStream().write(filebuf); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Caught Exception while sending file: " + e, e); + } finally { + try { + stream.close(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not close OutputStream of ByteStream: " + e, e); + } + } + + //TODO: session-info to signalize that file has been sent. + } + + void read(BytestreamSession session) { + if (target == null) { + throw new IllegalStateException("Target file MUST NOT be null."); + } + + //Become mainstream + InputStream inputStream = null; + FileOutputStream fileOutputStream = null; + + try { + inputStream = session.getInputStream(); + fileOutputStream = new FileOutputStream(target); + + int size = ((JingleFileTransferChild) proposedContent.getDescription() + .getJingleContentDescriptionChildren().get(0)).getSize(); + + byte[] filebuf = new byte[size]; + byte[] readbuf = new byte[2048]; + int read = 0; + + while (read < size) { + int r = inputStream.read(readbuf); + + if (r >= 0) { + System.arraycopy(readbuf, 0, filebuf, read, r); + read += r; + } else { + //TODO: Terminate? + } + } + + fileOutputStream.write(filebuf); + + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Caught exception while receiving file: " + e, e); + } finally { + try { + if (fileOutputStream != null) { + fileOutputStream.close(); + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Caught exception while closing FileOutputStream: " + e, e); + } + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Caught exception while closing InputStream: " + e, e); + } + } + } + + public JingleManager.FullJidAndSessionId getFullJidAndSessionId() { + return new JingleManager.FullJidAndSessionId(remote, sessionId); + } + + @Override + protected IQ handleSessionInitiate(Jingle sessionInitiate) { + return state.handleSessionInitiate(sessionInitiate); + } + + @Override + protected IQ handleSessionTerminate(Jingle sessionTerminate) { + return state.handleSessionTerminate(sessionTerminate); + } + + @Override + protected IQ handleSessionInfo(Jingle sessionInfo) { + return state.handleSessionInfo(sessionInfo); + } + + @Override + protected IQ handleSessionAccept(Jingle sessionAccept) { + return state.handleSessionAccept(sessionAccept); + } + + @Override + protected IQ handleContentAdd(Jingle contentAdd) { + return state.handleContentAdd(contentAdd); + } + + @Override + protected IQ handleContentAccept(Jingle contentAccept) { + return state.handleContentAccept(contentAccept); + } + + @Override + protected IQ handleContentModify(Jingle contentModify) { + return state.handleContentModify(contentModify); + } + + @Override + protected IQ handleContentReject(Jingle contentReject) { + return state.handleContentReject(contentReject); + } + + @Override + protected IQ handleContentRemove(Jingle contentRemove) { + return state.handleContentRemove(contentRemove); + } + + @Override + protected IQ handleDescriptionInfo(Jingle descriptionInfo) { + return state.handleDescriptionInfo(descriptionInfo); + } + + @Override + protected IQ handleSecurityInfo(Jingle securityInfo) { + return state.handleSecurityInfo(securityInfo); + } + + @Override + protected IQ handleTransportAccept(Jingle transportAccept) { + return state.handleTransportAccept(transportAccept); + } + + @Override + protected IQ handleTransportInfo(Jingle transportInfo) { + return state.handleTransportInfo(transportInfo); + } + + @Override + protected IQ handleTransportReplace(Jingle transportReplace) { + return state.handleTransportReplace(transportReplace); + } + + @Override + protected IQ handleTransportReject(Jingle transportReject) { + return state.handleTransportReject(transportReject); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/JingleFileTransferCallback.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/JingleFileTransferCallback.java index 3436e3143..3d4239822 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/JingleFileTransferCallback.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/JingleFileTransferCallback.java @@ -25,7 +25,7 @@ import org.jivesoftware.smack.SmackException; */ public interface JingleFileTransferCallback { - void acceptFileTransfer(File target) throws Exception; + void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException; void declineFileTransfer() throws SmackException.NotConnectedException, InterruptedException; } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/InitiatorOutgoingFileTransferInitiated.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/InitiatorOutgoingFileTransferInitiated.java deleted file mode 100644 index f8baba574..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/InitiatorOutgoingFileTransferInitiated.java +++ /dev/null @@ -1,124 +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 java.io.File; -import java.io.IOException; -import java.lang.ref.WeakReference; - -import org.jivesoftware.smack.XMPPConnection; -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.AbstractJingleTransportManager; -import org.jivesoftware.smackx.jingle.JingleManager; -import org.jivesoftware.smackx.jingle.JingleSessionHandler; -import org.jivesoftware.smackx.jingle.JingleTransportEstablishedCallback; -import org.jivesoftware.smackx.jingle.JingleTransportHandler; -import org.jivesoftware.smackx.jingle.JingleTransportManager; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; -import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException; -import org.jivesoftware.smackx.jingle_filetransfer.FileAndHashReader; -import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager; - -/** - * This handler represents the state of the initiators jingle session after session-initiate was sent. - */ -public class InitiatorOutgoingFileTransferInitiated implements JingleSessionHandler { - - private final WeakReference manager; - private final JingleManager.FullJidAndSessionId fullJidAndSessionId; - private final File file; - - public InitiatorOutgoingFileTransferInitiated(JingleFileTransferManager manager, JingleManager.FullJidAndSessionId fullJidAndSessionId, File file) { - this.fullJidAndSessionId = fullJidAndSessionId; - this.file = file; - this.manager = new WeakReference<>(manager); - } - - @Override - public IQ handleJingleSessionRequest(final Jingle jingle, String sessionId) { - final AbstractJingleTransportManager bm; - try { - bm = JingleTransportManager.getInstanceFor(getConnection()) - .getJingleContentTransportManager(jingle); - } catch (UnsupportedJingleTransportException e) { - // TODO - return null; - } - - JingleContentTransport transport = jingle.getContents().get(0).getJingleTransports().get(0); - - switch (jingle.getAction()) { - case session_accept: - bm.createJingleTransportHandler(this).establishOutgoingSession(jingle, new JingleTransportEstablishedCallback() { - @Override - public void onSessionEstablished(final BytestreamSession bytestreamSession) { - new Runnable() { - @Override - public void run() { - startTransfer(bytestreamSession, jingle); - } - }.run(); - } - - @Override - public void onSessionFailure(JingleTransportFailureException reason) { - - } - }); - Runnable transfer = new Runnable() { - @Override - public void run() { - - } - }; - transfer.run(); - - break; - case session_terminate: - break; - default: - break; - - } - return IQ.createResultIQ(jingle); - } - - @Override - public XMPPConnection getConnection() { - JingleFileTransferManager m = manager.get(); - return m != null ? m.getConnection() : null; - } - - public void startTransfer(BytestreamSession session, Jingle jingle) { - 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; - } - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferAccepted.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferAccepted.java deleted file mode 100644 index 96a9f9142..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferAccepted.java +++ /dev/null @@ -1,88 +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 java.io.File; -import java.lang.ref.WeakReference; -import java.util.logging.Logger; - -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.bytestreams.BytestreamSession; -import org.jivesoftware.smackx.jingle.AbstractJingleTransportManager; -import org.jivesoftware.smackx.jingle.JingleSessionHandler; -import org.jivesoftware.smackx.jingle.JingleTransportEstablishedCallback; -import org.jivesoftware.smackx.jingle.JingleTransportManager; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; -import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException; -import org.jivesoftware.smackx.jingle_filetransfer.JingleFileTransferManager; -import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; -import org.jxmpp.jid.FullJid; - -/** - * This handler represents the state of the responders jingle session after the responder sent session-accept. - */ -public class ResponderIncomingFileTransferAccepted implements JingleSessionHandler { - - private static final Logger LOGGER = Logger.getLogger(ResponderIncomingFileTransferAccepted.class.getName()); - - private final WeakReference manager; - private AbstractJingleTransportManager transportManager; - private final File target; - private final int size; - private final FullJid initiator; - private final String sessionId; - - public ResponderIncomingFileTransferAccepted(final JingleFileTransferManager manager, final Jingle initiate, final File target) { - this.manager = new WeakReference<>(manager); - this.target = target; - this.size = ((JingleFileTransferChild) initiate.getContents().get(0).getDescription() - .getJingleContentDescriptionChildren().get(0)).getSize(); - try { - this.transportManager = JingleTransportManager.getInstanceFor(manager.getConnection()).getJingleContentTransportManager(initiate); - } catch (UnsupportedJingleTransportException e) { - e.printStackTrace(); - } - this.initiator = initiate.getInitiator(); - this.sessionId = initiate.getSessionId(); - - transportManager.createJingleTransportHandler(this).establishIncomingSession( - initiate, new JingleTransportEstablishedCallback() { - @Override - public void onSessionEstablished(BytestreamSession bytestreamSession) { - manager.receiveFile(initiate, bytestreamSession, target); - } - - @Override - public void onSessionFailure(JingleTransportFailureException reason) { - - } - }); - } - - @Override - public IQ handleJingleSessionRequest(Jingle jingle, String sessionId) { - return null; - } - - @Override - public XMPPConnection getConnection() { - JingleFileTransferManager m = manager.get(); - return m != null ? m.getConnection() : null; - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferTransportReplaced.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferTransportReplaced.java deleted file mode 100644 index 815412b8e..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/ResponderIncomingFileTransferTransportReplaced.java +++ /dev/null @@ -1,23 +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; - -/** - * This handler represents the state of the responders jingle session after the responder sent session-replace. - */ -public class ResponderIncomingFileTransferTransportReplaced { -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/package-info.java deleted file mode 100644 index 788e85d84..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/package-info.java +++ /dev/null @@ -1,21 +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 XEP-0234: Jingle File Transfer. - */ -package org.jivesoftware.smackx.jingle_filetransfer.handler; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/listener/IncomingJingleFileTransferListener.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/listener/IncomingJingleFileTransferListener.java index f18b0ccd3..fc6b45130 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/listener/IncomingJingleFileTransferListener.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/listener/IncomingJingleFileTransferListener.java @@ -16,13 +16,13 @@ */ package org.jivesoftware.smackx.jingle_filetransfer.listener; -import org.jivesoftware.smackx.jingle.element.Jingle; import org.jivesoftware.smackx.jingle_filetransfer.callback.JingleFileTransferCallback; +import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; /** * Listener for incoming file transfers. */ public interface IncomingJingleFileTransferListener { - void onIncomingJingleFileTransfer(Jingle jingle, JingleFileTransferCallback callback); + void onIncomingJingleFileTransfer(JingleFileTransferChild file, JingleFileTransferCallback callback); } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleIBBTransportHandler.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleIBBTransportHandler.java index 628dfbe96..b69118418 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleIBBTransportHandler.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleIBBTransportHandler.java @@ -1,3 +1,19 @@ +/** + * + * 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.lang.ref.WeakReference; @@ -10,10 +26,11 @@ import org.jivesoftware.smackx.bytestreams.BytestreamRequest; import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession; +import org.jivesoftware.smackx.jingle.JingleManager; import org.jivesoftware.smackx.jingle.JingleSessionHandler; import org.jivesoftware.smackx.jingle.JingleTransportEstablishedCallback; import org.jivesoftware.smackx.jingle.JingleTransportHandler; -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContent; import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; import org.jivesoftware.smackx.jingle_ibb.element.JingleIBBTransport; @@ -29,12 +46,14 @@ public class JingleIBBTransportHandler implements JingleTransportHandler 1) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java index 1558339ad..8d45e2d4e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java @@ -22,7 +22,7 @@ import org.jivesoftware.smackx.jingle.element.Jingle; public interface JingleSessionHandler { - IQ handleJingleSessionRequest(Jingle jingle, String sessionId); + IQ handleJingleSessionRequest(Jingle jingle); XMPPConnection getConnection(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportEstablishedCallback.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportEstablishedCallback.java index 51d501dfb..98c14bdb1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportEstablishedCallback.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportEstablishedCallback.java @@ -1,10 +1,26 @@ +/** + * + * 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 org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; /** - * Created by vanitas on 10.06.17. + * Callback that's used to establish BytestreamSessions from transport methods. */ public interface JingleTransportEstablishedCallback { void onSessionEstablished(BytestreamSession bytestreamSession); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportHandler.java index 2a8d0d72b..2178a4082 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportHandler.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportHandler.java @@ -1,17 +1,37 @@ +/** + * + * 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 org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContent; import org.jivesoftware.smackx.jingle.element.JingleContentTransport; /** - * Handler for JingleTransports + * Handler for JingleTransports. */ public interface JingleTransportHandler { - void establishOutgoingSession(Jingle request, JingleTransportEstablishedCallback callback); + void establishOutgoingSession(JingleManager.FullJidAndSessionId fullJidAndSessionId, + JingleContent content, + JingleTransportEstablishedCallback callback); - void establishIncomingSession(Jingle request, JingleTransportEstablishedCallback callback); + void establishIncomingSession(JingleManager.FullJidAndSessionId fullJidAndSessionId, + JingleContent content, + JingleTransportEstablishedCallback callback); XMPPConnection getConnection(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java index 99b3f2293..d032adeb3 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java @@ -25,6 +25,7 @@ import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException; /** @@ -49,6 +50,18 @@ public final class JingleTransportManager extends Manager { return manager; } + public static AbstractJingleTransportManager getJingleContentTransportManager(XMPPConnection connection, String namespace) throws UnsupportedJingleTransportException { + return getInstanceFor(connection).getJingleContentTransportManager(namespace); + } + + public static AbstractJingleTransportManager getJingleContentTransportManager(XMPPConnection connection, Jingle jingle) throws UnsupportedJingleTransportException { + return getInstanceFor(connection).getJingleContentTransportManager(jingle); + } + + public static AbstractJingleTransportManager getJingleContentTransportManager(XMPPConnection connection, JingleContentTransport transport) throws UnsupportedJingleTransportException { + return getInstanceFor(connection).getJingleContentTransportManager(transport.getNamespace()); + } + public AbstractJingleTransportManager getJingleContentTransportManager(String namespace) throws UnsupportedJingleTransportException { AbstractJingleTransportManager manager = contentTransportManagers.get(namespace); if (manager == null) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/JingleTransportFailureException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/JingleTransportFailureException.java index fbe3561ba..6a259b60a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/JingleTransportFailureException.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/JingleTransportFailureException.java @@ -1,7 +1,23 @@ +/** + * + * 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.exception; /** - * Created by vanitas on 10.06.17. + * Exception that gets thrown when establishing a session using a transport fails. */ public class JingleTransportFailureException extends Exception {