diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferCallback.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferCallback.java new file mode 100644 index 000000000..4782d87ed --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferCallback.java @@ -0,0 +1,26 @@ +package org.jivesoftware.smackx.jft; + +import java.io.File; + +import org.jivesoftware.smackx.jft.internal.JingleIncomingFileOffer; + +/** + * Created by vanitas on 26.07.17. + */ +public class IncomingFileTransferCallback { + + private JingleIncomingFileOffer offer; + + public IncomingFileTransferCallback(JingleIncomingFileOffer offer) { + this.offer = offer; + } + + public JingleIncomingFileOffer accept(File target) { + offer.accept(target); + return offer; + } + + public void decline() { + offer.decline(); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferListener.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferListener.java new file mode 100644 index 000000000..b67776ce5 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/IncomingFileTransferListener.java @@ -0,0 +1,9 @@ +package org.jivesoftware.smackx.jft; + +/** + * Created by vanitas on 26.07.17. + */ +public interface IncomingFileTransferListener { + + void onIncomingFileTransfer(IncomingFileTransferCallback callback); +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferManager.java index aa7a41a1b..50b82aec7 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferManager.java @@ -1,18 +1,30 @@ package org.jivesoftware.smackx.jft; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.WeakHashMap; import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.jft.internal.JingleFileTransfer; +import org.jivesoftware.smackx.jft.internal.JingleIncomingFileOffer; +import org.jivesoftware.smackx.jft.internal.JingleOutgoingFileOffer; import org.jivesoftware.smackx.jft.provider.JingleFileTransferProvider; import org.jivesoftware.smackx.jingle.JingleDescriptionManager; import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.Role; import org.jivesoftware.smackx.jingle.callbacks.ContentAddCallback; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; import org.jivesoftware.smackx.jingle.element.JingleElement; import org.jivesoftware.smackx.jingle.internal.JingleContent; +import org.jivesoftware.smackx.jingle.internal.JingleSession; import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; +import org.jivesoftware.smackx.jingle.transport.JingleTransportManager; + +import org.jxmpp.jid.FullJid; /** * Created by vanitas on 22.07.17. @@ -22,6 +34,9 @@ public final class JingleFileTransferManager extends Manager implements JingleDe private static final WeakHashMap INSTANCES = new WeakHashMap<>(); private final JingleManager jingleManager; + private final List listeners = + Collections.synchronizedList(new ArrayList()); + private JingleFileTransferManager(XMPPConnection connection) { super(connection); ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace()); @@ -41,6 +56,43 @@ public final class JingleFileTransferManager extends Manager implements JingleDe return manager; } + public OutgoingFileHandler sendFile(File file, FullJid to) { + if (file == null || !file.exists()) { + throw new IllegalArgumentException("File MUST NOT be null and MUST exist."); + } + + JingleSession session = jingleManager.createSession(Role.initiator, to); + + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + session.addContent(content); + + JingleOutgoingFileOffer offer = new JingleOutgoingFileOffer(file); + content.setDescription(offer); + + JingleTransportManager transportManager = jingleManager.getBestAvailableTransportManager(); + content.setTransport(transportManager.createTransport(content)); + + OutgoingFileHandler handler = new OutgoingFileHandler(); + + + //TODO + return handler; + } + + public void addIncomingFileTransferListener(IncomingFileTransferListener listener) { + listeners.add(listener); + } + + public void removeIncomingFileTransferListener(IncomingFileTransferListener listener) { + listeners.remove(listener); + } + + public void notifyIncomingFileTransferListeners(JingleIncomingFileOffer offer) { + for (IncomingFileTransferListener l : listeners) { + l.onIncomingFileTransfer(new IncomingFileTransferCallback(offer)); + } + } + @Override public String getNamespace() { return JingleFileTransfer.NAMESPACE; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/OutgoingFileHandler.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/OutgoingFileHandler.java new file mode 100644 index 000000000..119839ec4 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/OutgoingFileHandler.java @@ -0,0 +1,7 @@ +package org.jivesoftware.smackx.jft; + +/** + * Created by vanitas on 26.07.17. + */ +public class OutgoingFileHandler { +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/internal/JingleIncomingFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/internal/JingleIncomingFileOffer.java index f99847ddc..612822005 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/internal/JingleIncomingFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/internal/JingleIncomingFileOffer.java @@ -1,7 +1,7 @@ package org.jivesoftware.smackx.jft.internal; import java.io.IOException; -import java.io.OutputStream; +import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; @@ -21,11 +21,11 @@ public class JingleIncomingFileOffer extends JingleFileOffer { @Override public void onTransportReady(BytestreamSession bytestreamSession) { - OutputStream outputStream; + InputStream inputStream; try { - outputStream = bytestreamSession.getOutputStream(); + inputStream = bytestreamSession.getInputStream(); } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Cannot get OutputStream from BytestreamSession: " + e, e); + LOGGER.log(Level.SEVERE, "Cannot get InputStream from BytestreamSession: " + e, e); return; } } 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 714834b92..51d662209 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 @@ -29,19 +29,21 @@ import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; import org.jivesoftware.smack.iqrequest.IQRequestHandler; import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.jingle.adapter.JingleDescriptionAdapter; -import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter; -import org.jivesoftware.smackx.jingle.element.JingleElement; -import org.jivesoftware.smackx.jingle.exception.UnsupportedTransportException; -import org.jivesoftware.smackx.jingle.provider.JingleContentSecurityProvider; import org.jivesoftware.smackx.jingle.adapter.JingleSecurityAdapter; +import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter; import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleElement; import org.jivesoftware.smackx.jingle.element.JingleReasonElement; import org.jivesoftware.smackx.jingle.exception.UnsupportedDescriptionException; import org.jivesoftware.smackx.jingle.exception.UnsupportedSecurityException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedTransportException; import org.jivesoftware.smackx.jingle.internal.JingleSession; import org.jivesoftware.smackx.jingle.provider.JingleContentDescriptionProvider; +import org.jivesoftware.smackx.jingle.provider.JingleContentSecurityProvider; import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider; +import org.jivesoftware.smackx.jingle.transport.JingleTransportManager; import org.jxmpp.jid.FullJid; @@ -65,6 +67,8 @@ public class JingleManager extends Manager { private final ConcurrentHashMap jingleSessions = new ConcurrentHashMap<>(); + public static boolean ALLOW_MULTIPLE_CONTENT_PER_SESSION = false; + private JingleManager(XMPPConnection connection) { super(connection); @@ -198,7 +202,7 @@ public class JingleManager extends Manager { return getAvailableTransportManagers(Collections.emptySet()); } - private List getAvailableTransportManagers(Set except) { + public List getAvailableTransportManagers(Set except) { Set available = new HashSet<>(transportManagers.keySet()); available.removeAll(except); List remaining = new ArrayList<>(); @@ -207,10 +211,42 @@ public class JingleManager extends Manager { remaining.add(transportManagers.get(namespace)); } + Collections.sort(remaining); + return remaining; } + public JingleTransportManager getBestAvailableTransportManager() { + return getBestAvailableTransportManager(Collections.emptySet()); + } + + public JingleTransportManager getBestAvailableTransportManager(Set except) { + List managers = getAvailableTransportManagers(except); + Collections.sort(managers); + + if (managers.size() > 0) { + return managers.get(0); + } + + return null; + } + public XMPPConnection getConnection() { return connection(); } + + public JingleSession createSession(Role role, FullJid peer) { + JingleSession session; + + if (role == Role.initiator) { + session = new JingleSession(this, connection().getUser().asDomainFullJidOrThrow(), peer, + role, StringUtils.randomString(24)); + } else { + session = new JingleSession(this, peer, connection().getUser().asDomainFullJidOrThrow(), + role, StringUtils.randomString(24)); + } + + jingleSessions.put(new FullJidAndSessionId(peer, session.getSessionId()), session); + return session; + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java index 148688056..febf0308b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java @@ -236,7 +236,7 @@ public final class JingleElement extends IQ { * @param content content * @return session-accept stanza. */ - public JingleElement createSessionAccept(FullJid initiator, + public static JingleElement createSessionAccept(FullJid initiator, FullJid responder, String sessionId, JingleContentElement content) { @@ -252,7 +252,7 @@ public final class JingleElement extends IQ { * @param contents contents * @return session-accept stanza. */ - public JingleElement createSessionAccept(FullJid initiator, + public static JingleElement createSessionAccept(FullJid initiator, FullJid responder, String sessionId, List contents) { @@ -281,7 +281,7 @@ public final class JingleElement extends IQ { * @param content content. * @return session-initiate stanza. */ - public JingleElement createSessionInitiate(FullJid initiator, + public static JingleElement createSessionInitiate(FullJid initiator, FullJid responder, String sessionId, JingleContentElement content) { @@ -297,7 +297,7 @@ public final class JingleElement extends IQ { * @param contents contents. * @return session-initiate stanza. */ - public JingleElement createSessionInitiate(FullJid initiator, + public static JingleElement createSessionInitiate(FullJid initiator, FullJid responder, String sessionId, List contents) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleContent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleContent.java index abce4ca62..7931f8b8c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleContent.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleContent.java @@ -51,6 +51,10 @@ public class JingleContent { private final List callbacks = Collections.synchronizedList(new ArrayList()); private final Set transportBlacklist = Collections.synchronizedSet(new HashSet()); + public JingleContent(JingleContentElement.Creator creator, JingleContentElement.Senders senders) { + this(null, null, null, StringUtils.randomString(24), null, creator, senders); + } + public JingleContent(JingleDescription description, JingleTransport transport, JingleSecurity security, String name, String disposition, JingleContentElement.Creator creator, JingleContentElement.Senders senders) { this.description = description; this.transport = transport; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleSession.java index fe4cd17fa..0527c9233 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleSession.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleSession.java @@ -71,12 +71,12 @@ public class JingleSession { this.sessionId = sessionId; } - void addContent(JingleContent content) { + public void addContent(JingleContent content) { contents.put(content.getName(), content); content.setParent(this); } - void addContent(JingleContentElement content) + public void addContent(JingleContentElement content) throws UnsupportedSecurityException, UnsupportedTransportException, UnsupportedDescriptionException { addContent(JingleContent.fromElement(content)); } @@ -97,6 +97,19 @@ public class JingleSession { return session; } + public JingleElement createSessionInitiate() { + if (role != Role.initiator) { + throw new IllegalStateException("Sessions role is not initiator."); + } + + List contentElements = new ArrayList<>(); + for (JingleContent c : contents.values()) { + contentElements.add(c.getElement()); + } + + return JingleElement.createSessionInitiate(getInitiator(), getResponder(), getSessionId(), contentElements); + } + public IQ handleJingleRequest(JingleElement request) { switch (request.getAction()) { case content_accept: @@ -268,7 +281,7 @@ public class JingleSession { List responses = new ArrayList<>(); for (Map.Entry entry : affectedContents.entrySet()) { - responses.add(entry.getValue().getSecurity().handleSecurityInfo(entry.getKey().getSecurity().getSecurityInfo())); + responses.add(entry.getValue().getSecurity().handleSecurityInfo(entry.getKey().getSecurity().getSecurityInfo(), request)); } for (JingleElement response : responses) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleTransport.java index 14d9262b7..866320eb0 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/internal/JingleTransport.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.SmackFuture; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; @@ -29,7 +30,7 @@ import org.jivesoftware.smackx.jingle.element.JingleElement; /** * Class that represents a contents transport component. */ -public abstract class JingleTransport { +public abstract class JingleTransport extends SmackFuture { private JingleContent parent; private final ArrayList> candidates = new ArrayList<>(); @@ -42,7 +43,7 @@ public abstract class JingleTransport { public abstract D getElement(); public void addCandidate(JingleTransportCandidate candidate) { - // Insert sorted by priority descending + // Insert sorted by descending priority // Empty list -> insert if (candidates.isEmpty()) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportManager.java similarity index 95% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportManager.java index 478c57f0d..60e3dd5ce 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportManager.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle; +package org.jivesoftware.smackx.jingle.transport; import org.jivesoftware.smackx.jingle.internal.JingleContent; import org.jivesoftware.smackx.jingle.internal.JingleTransport; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java index 7349d6786..d4dc4720f 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java @@ -19,6 +19,7 @@ package org.jivesoftware.smackx.jingle.transport.jingle_ibb; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener; @@ -29,7 +30,6 @@ import org.jivesoftware.smackx.jingle.element.JingleElement; import org.jivesoftware.smackx.jingle.internal.JingleSession; import org.jivesoftware.smackx.jingle.internal.JingleTransport; import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate; -import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener; import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; /** @@ -125,4 +125,14 @@ public class JingleIBBTransport extends JingleTransport