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 faa2ce472..3ae6eb9be 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.Collections; import java.util.HashSet; import java.util.WeakHashMap; @@ -26,21 +28,26 @@ import java.util.logging.Logger; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; 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.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; @@ -48,7 +55,7 @@ import org.jivesoftware.smackx.jingle_filetransfer.handler.InitiatorOutgoingFile 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; /** @@ -80,8 +87,8 @@ public final class JingleFileTransferManager extends Manager implements JingleHa NAMESPACE_V5, this); JingleContentProviderManager.addJingleContentDescriptionProvider( NAMESPACE_V5, new JingleFileTransferContentDescriptionProvider()); - //JingleIBBTransportManager.getInstanceFor(connection); - JingleS5BTransportManager.getInstanceFor(connection); + JingleIBBTransportManager.getInstanceFor(connection); + //JingleS5BTransportManager.getInstanceFor(connection); } /** @@ -121,7 +128,7 @@ public final class JingleFileTransferManager extends Manager implements JingleHa * QnD method. * @param file */ - public void sendFile(File file, final FullJid recipient) throws IOException, SmackException, InterruptedException, XMPPException { + public void sendFile(final File file, final FullJid recipient) throws Exception { AbstractJingleTransportManager tm = JingleTransportManager.getInstanceFor(connection()) .getAvailableJingleBytestreamManagers().iterator().next(); @@ -132,15 +139,43 @@ public final class JingleFileTransferManager extends Manager implements JingleHa JingleFileTransferContentDescription description = new JingleFileTransferContentDescription( Collections.singletonList((JingleContentDescriptionChildElement) b.build())); - Jingle initiate = tm.createSessionInitiate(recipient, description); + + JingleContentTransport transport = tm.createJingleContentTransport(recipient); + Jingle initiate = sessionInitiate(recipient, description, transport); JingleManager.FullJidAndSessionId fullJidAndSessionId = new JingleManager.FullJidAndSessionId(recipient, initiate.getSid()); - jingleManager.registerJingleSessionHandler(recipient, initiate.getSid(), - new InitiatorOutgoingFileTransferInitiated(this, fullJidAndSessionId, file)); + InitiatorOutgoingFileTransferInitiated sessionHandler = + new InitiatorOutgoingFileTransferInitiated(this, fullJidAndSessionId, file); + jingleManager.registerJingleSessionHandler(recipient, initiate.getSid(), sessionHandler); + + JingleTransportHandler transportHandler = tm.createJingleTransportHandler(sessionHandler); connection().sendStanza(initiate); + transportHandler.establishOutgoingSession(fullJidAndSessionId, transport, 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 FullJid ourJid() { @@ -173,8 +208,8 @@ public final class JingleFileTransferManager extends Manager implements JingleHa notifyIncomingFileTransferListeners(jingle, new JingleFileTransferCallback() { @Override - public void accept(File target) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, UnsupportedJingleTransportException, SmackException.NoResponseException { - connection().sendStanza(finalTransportManager.createSessionAccept(jingle)); + public void accept(final File target) throws Exception { + connection().sendStanza(sessionAccept(jingle)); JingleManager.FullJidAndSessionId fullJidAndSessionId = new JingleManager.FullJidAndSessionId( @@ -192,7 +227,7 @@ public final class JingleFileTransferManager extends Manager implements JingleHa new JingleTransportEstablishedCallback() { @Override public void onSessionEstablished(BytestreamSession bytestreamSession) { - + receiveFile(jingle, bytestreamSession, target); } @Override @@ -211,6 +246,100 @@ public final class JingleFileTransferManager extends Manager implements JingleHa return IQ.createResultIQ(jingle); } + protected 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; + } + + protected Jingle sessionAccept(Jingle request) throws Exception { + JingleContent content = request.getContents().get(0); + + Jingle.Builder jb = Jingle.getBuilder(); + jb.setSessionId(request.getSid()) + .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 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(); } 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 e6f3158b5..f0eed70d0 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 @@ -27,7 +27,7 @@ import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportExcept */ public interface JingleFileTransferCallback { - void accept(File target) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, UnsupportedJingleTransportException, SmackException.NoResponseException; + void accept(File target) throws Exception; void decline() 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 index dadc8d8ae..a12204de3 100644 --- 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 @@ -28,8 +28,11 @@ 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.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; @@ -60,13 +63,30 @@ public class InitiatorOutgoingFileTransferInitiated implements JingleSessionHand return null; } + JingleContentTransport transport = jingle.getContents().get(0).getJingleTransports().get(0); + switch (jingle.getAction()) { case session_accept: + bm.createJingleTransportHandler(this).establishOutgoingSession(fullJidAndSessionId, transport, 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() { - startTransfer(bm, jingle); + } }; transfer.run(); @@ -87,16 +107,7 @@ public class InitiatorOutgoingFileTransferInitiated implements JingleSessionHand return m != null ? m.getConnection() : null; } - public void startTransfer(AbstractJingleTransportManager transportManager, Jingle jingle) { - BytestreamSession session; - - try { - session = transportManager.outgoingInitiatedSession(jingle); - } catch (Exception e) { - //TODO - return; - } - + public void startTransfer(BytestreamSession session, Jingle jingle) { HashElement fileHash; byte[] buf = new byte[(int) file.length()]; 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 index a766653db..cdaeb445d 100644 --- 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 @@ -17,19 +17,11 @@ 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.XMPPConnection; 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.AbstractJingleTransportManager; import org.jivesoftware.smackx.jingle.JingleSessionHandler; import org.jivesoftware.smackx.jingle.JingleTransportManager; @@ -42,7 +34,7 @@ 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, BytestreamListener { +public class ResponderIncomingFileTransferAccepted implements JingleSessionHandler { private static final Logger LOGGER = Logger.getLogger(ResponderIncomingFileTransferAccepted.class.getName()); @@ -67,63 +59,14 @@ public class ResponderIncomingFileTransferAccepted implements JingleSessionHandl 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); - } - transportManager.removeIncomingRespondedSessionListener(this); - } - } - @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_ibb/JingleIBBTransportHandler.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_ibb/JingleIBBTransportHandler.java index 57e29dca9..3468130e5 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 @@ -14,6 +14,7 @@ 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.JingleContentTransport; import org.jivesoftware.smackx.jingle.exception.JingleTransportFailureException; import org.jivesoftware.smackx.jingle_ibb.element.JingleIBBTransport; @@ -29,7 +30,7 @@ public class JingleIBBTransportHandler implements JingleTransportHandler createJingleTransportHandler(JingleSessionHandler sessionHandler); - public abstract D createJingleContentTransport(JingleManager.FullJidAndSessionId target) throws Exception; + public abstract D createJingleContentTransport(FullJid target) throws Exception; public abstract D createJingleContentTransport(Jingle remotesRequest) throws Exception; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java index 210874ce3..44e60b81c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java @@ -199,7 +199,9 @@ public final class Jingle extends IQ { } public Jingle build() { - return new Jingle(sid, action, initiator, responder, reason, contents); + Jingle jingle = new Jingle(sid, action, initiator, responder, reason, contents); + jingle.setType(Type.set); + return jingle; } } } 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 fc329600b..fbe3561ba 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 @@ -5,6 +5,8 @@ package org.jivesoftware.smackx.jingle.exception; */ public class JingleTransportFailureException extends Exception { + private static final long serialVersionUID = 1L; + public JingleTransportFailureException(Throwable wrapped) { super(wrapped); }