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 d24fd1581..6dded03a2 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 @@ -17,7 +17,9 @@ 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.ArrayList; import java.util.Date; import java.util.HashMap; @@ -32,7 +34,9 @@ import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.XMPPError; +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.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.hash.HashManager; @@ -46,6 +50,7 @@ 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.JingleError; +import org.jivesoftware.smackx.jingle.element.JingleReason; import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingJingleFileTransferCallback; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChildElement; @@ -80,10 +85,8 @@ public final class JingleFileTransferManager extends Manager implements JingleHa super(connection); ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); sdm.addFeature(NAMESPACE_V5); - JingleManager.getInstanceFor(connection).registerDescriptionHandler( NAMESPACE_V5, this); - JingleContentProviderManager.addJingleContentDescriptionProvider( NAMESPACE_V5, new JingleFileTransferContentDescriptionProvider()); @@ -121,20 +124,60 @@ public final class JingleFileTransferManager extends Manager implements JingleHa } @Override - public IQ handleJingleRequest(Jingle jingle) { - JingleSession session = new JingleSession(jingle.getInitiator(), jingle.getResponder(), jingle.getSid()); + public IQ handleJingleRequest(final Jingle jingle) { + LOGGER.log(Level.INFO, "handleJingleRequest"); + final JingleSession session = new JingleSession(jingle.getInitiator(), jingle.getResponder(), jingle.getSid()); sessions.put(jingle.getSid(), session); + JingleManager.getInstanceFor(connection()).registerJingleSessionHandler(jingle.getInitiator(), session.getSid(), this); for (IncomingJingleFileTransferListener l : incomingJingleFileTransferListeners) { l.onIncomingJingleFileTransfer(jingle, new IncomingJingleFileTransferCallback() { @Override - public void acceptFileTransfer(File target) { + public void acceptFileTransfer(final File target) throws SmackException.NotConnectedException, InterruptedException { + InBandBytestreamManager.getByteStreamManager(connection()).addIncomingBytestreamListener(new InBandBytestreamListener() { + @Override + public void incomingBytestreamRequest(InBandBytestreamRequest request) { + try { + if (!target.exists()) { + target.createNewFile(); + } + int s = ((JingleFileTransferChildElement)jingle.getContents().get(0).getDescription().getJinglePayloadTypes().get(0)) + .getSize(); + byte[] recv = new byte[s]; + FileOutputStream o = new FileOutputStream(target); + InputStream i = request.accept().getInputStream(); + i.read(recv); + i.close(); + o.write(recv); + o.close(); + } catch (IOException | SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + } + }); + + Jingle.Builder jb = Jingle.getBuilder(); + jb.setAction(JingleAction.session_accept) + .setSessionId(jingle.getSid()) + .setInitiator(jingle.getInitiator()) + .setResponder(jingle.getResponder()) + .addJingleContent(jingle.getContents().get(0)); + Jingle j = jb.build(); + j.setTo(jingle.getFrom()); + j.setType(IQ.Type.set); + connection().sendStanza(j); } @Override - public void cancelFileTransfer() { - + public void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException { + Jingle.Builder jb = Jingle.getBuilder(); + jb.setInitiator(jingle.getInitiator()) + .setResponder(jingle.getResponder()) + .setSessionId(jingle.getSid()) + .setAction(JingleAction.session_terminate) + .setReason(JingleReason.Reason.decline); + connection().sendStanza(jb.build()); } }); } @@ -144,6 +187,7 @@ public final class JingleFileTransferManager extends Manager implements JingleHa @Override public IQ handleJingleSessionRequest(Jingle jingle, String sessionId) { + LOGGER.log(Level.INFO, "handleJingleSessionRequest"); JingleSession session = sessions.get(sessionId); if (session == null) { @@ -155,13 +199,35 @@ public final class JingleFileTransferManager extends Manager implements JingleHa } for (int i = 0; i < jingle.getContents().size() && i < 1; i++) { //TODO: Remove && i<1 later - JingleContent content = jingle.getContents().get(i); switch (jingle.getAction()) { case session_initiate: throw new AssertionError("Session is already initiated."); case session_accept: + try { + connection().sendStanza(IQ.createResultIQ(jingle)); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + LOGGER.log(Level.INFO, "Received session-accept"); // Remote accepts our session-initiate - session.setState(JingleSession.State.active); + InBandBytestreamSession ibs; + try { + ibs = InBandBytestreamManager.getByteStreamManager(connection()) + .establishSession(jingle.getResponder(), sessionId); + } catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { + LOGGER.log(Level.SEVERE, "Fail in handle request: " + e, e); + return null; + } + + try { + LOGGER.log(Level.INFO, "Writing bytes..."); + OutgoingJingleFileTransferSession outgoing = (OutgoingJingleFileTransferSession) session; + ibs.getOutputStream().write(outgoing.getBytes()); + ibs.close(); + LOGGER.log(Level.INFO, "Bytes written."); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Fail while writing: " + e, e); + } // ACK return IQ.createResultIQ(jingle); case session_info: @@ -233,32 +299,13 @@ public final class JingleFileTransferManager extends Manager implements JingleHa .addJingleContent(content) .setSessionId(sid); Jingle jingle = jb.build(); + jingle.setTo(recipient); + jingle.setType(IQ.Type.set); - JingleManager.getInstanceFor(connection()).registerJingleSessionHandler(recipient, sid, new JingleSessionHandler() { - @Override - public IQ handleJingleSessionRequest(Jingle jingle, String sessionId) { - if (sessionId.equals(sid)) { - if (jingle.getAction() == JingleAction.session_accept) { - - InBandBytestreamSession session; - try { - session = InBandBytestreamManager.getByteStreamManager(connection()) - .establishSession(recipient, sid); - } catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { - LOGGER.log(Level.SEVERE, "Fail in handle request: " + e, e); - return null; - } - - try { - session.getOutputStream().write(bytes); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Fail while writing: " + e, e); - } - } - } - return null; - } - }); + OutgoingJingleFileTransferSession session = new OutgoingJingleFileTransferSession(jingle); + session.setBytes(bytes); + sessions.put(sid, session); + JingleManager.getInstanceFor(connection()).registerJingleSessionHandler(jingle.getResponder(), session.getSid(), this); connection().sendStanza(jingle); } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileTransferSession.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileTransferSession.java new file mode 100644 index 000000000..b03e3a4ef --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileTransferSession.java @@ -0,0 +1,24 @@ +package org.jivesoftware.smackx.jingle_filetransfer; + +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.element.Jingle; + +/** + * Created by vanitas on 04.06.17. + */ +public class OutgoingJingleFileTransferSession extends JingleSession { + + private byte[] bytes; + + public OutgoingJingleFileTransferSession(Jingle jingle) { + super(jingle.getInitiator(), jingle.getResponder(), jingle.getSid()); + } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + public byte[] getBytes() { + return bytes; + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/IncomingJingleFileTransferCallback.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/IncomingJingleFileTransferCallback.java index 7039ae3a0..633c80fa0 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/IncomingJingleFileTransferCallback.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/callback/IncomingJingleFileTransferCallback.java @@ -18,12 +18,14 @@ package org.jivesoftware.smackx.jingle_filetransfer.callback; import java.io.File; +import org.jivesoftware.smack.SmackException; + /** * Callback that allows the user to accept or cancel file transfers. */ public interface IncomingJingleFileTransferCallback { - void acceptFileTransfer(File target); + void acceptFileTransfer(File target) throws SmackException.NotConnectedException, InterruptedException; - void cancelFileTransfer(); + void cancelFileTransfer() throws SmackException.NotConnectedException, InterruptedException; } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileOfferHandler.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileOfferHandler.java index 160cedd76..6ae177296 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileOfferHandler.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileOfferHandler.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_filetransfer.handler; import org.jivesoftware.smackx.jingle.element.Jingle; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileRequestHandler.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileRequestHandler.java index 2627eb633..797d7207f 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileRequestHandler.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/FileRequestHandler.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_filetransfer.handler; import org.jivesoftware.smack.packet.IQ; 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 new file mode 100644 index 000000000..788e85d84 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/handler/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java index 8b200dbe9..1ccc38ce7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java @@ -19,6 +19,7 @@ package org.jivesoftware.smackx.jingle; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.Manager; @@ -31,6 +32,7 @@ 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_ibb.JingleInBandByteStreamManager; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; @@ -60,6 +62,7 @@ public final class JingleManager extends Manager { new AbstractIqRequestHandler(Jingle.ELEMENT, Jingle.NAMESPACE, Type.set, Mode.async) { @Override public IQ handleIQRequest(IQ iqRequest) { + LOGGER.log(Level.INFO, "handleIQRequest"); final Jingle jingle = (Jingle) iqRequest; if (jingle.getAction() != JingleAction.session_initiate) { @@ -92,6 +95,7 @@ public final class JingleManager extends Manager { return jingleDescriptionHandler.handleJingleRequest(jingle); } }); + JingleInBandByteStreamManager.getInstanceFor(connection); } public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java index 98097662e..f49447999 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java @@ -16,12 +16,12 @@ */ package org.jivesoftware.smackx.jingle.element; -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.util.XmlStringBuilder; - import java.util.Collections; import java.util.List; +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + /** * Jingle content description. * diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleInBandByteStreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleInBandByteStreamManager.java index 4b2622fe0..1d48c5124 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleInBandByteStreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleInBandByteStreamManager.java @@ -16,14 +16,15 @@ */ package org.jivesoftware.smackx.jingle_ibb; +import java.util.WeakHashMap; + import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; import org.jivesoftware.smackx.jingle_ibb.provider.JingleInBandByteStreamTransportProvider; -import java.util.WeakHashMap; - /** * Manager for Jingle In-Band-ByteStreams. */ @@ -36,6 +37,7 @@ public final class JingleInBandByteStreamManager extends Manager { private JingleInBandByteStreamManager(XMPPConnection connection) { super(connection); JingleContentProviderManager.addJingleContentTransportProvider(NAMESPACE_V1, new JingleInBandByteStreamTransportProvider()); + ServiceDiscoveryManager.getInstanceFor(connection).addFeature(NAMESPACE_V1); } public static JingleInBandByteStreamManager getInstanceFor(XMPPConnection connection) {