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 08b31bd63..339ab9e18 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
@@ -166,7 +166,7 @@ public final class JingleFileTransferManager extends Manager implements JingleDe
}
@Override
- public void notifyContentAdd(JingleContent content) {
+ public void notifyContentAdd(JingleSession session, JingleContent content) {
notifyTransfer((JingleFileTransfer) content.getDescription());
}
}
diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/package-info.java
new file mode 100644
index 000000000..bb55e4942
--- /dev/null
+++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/package-info.java
@@ -0,0 +1,22 @@
+/**
+ *
+ * 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.
+ * Adapters.
+ */
+package org.jivesoftware.smackx.jft.adapter;
diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/controller/IncomingFileOfferController.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/controller/IncomingFileOfferController.java
index 50f27cb33..56c665519 100644
--- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/controller/IncomingFileOfferController.java
+++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/controller/IncomingFileOfferController.java
@@ -19,9 +19,13 @@ package org.jivesoftware.smackx.jft.controller;
import java.io.File;
import java.util.concurrent.Future;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+
/**
* Created by vanitas on 27.07.17.
*/
public interface IncomingFileOfferController extends JingleFileTransferController {
- Future accept(File target);
+ Future accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException;
}
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 2d593149d..5621be947 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
@@ -23,6 +23,9 @@ import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
import org.jivesoftware.smackx.jft.controller.IncomingFileOfferController;
import org.jivesoftware.smackx.jft.element.JingleFileTransferChildElement;
@@ -69,10 +72,12 @@ public class JingleIncomingFileOffer extends AbstractJingleFileOffer
}
@Override
- public Future accept(File target) {
+ public Future accept(XMPPConnection connection, File target)
+ throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException,
+ SmackException.NoResponseException {
JingleSession session = getParent().getParent();
if (session.getSessionState() == JingleSession.SessionState.pending) {
- //session.accept();
+ session.accept(connection);
}
return null;
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java
index db908830f..6acc585d8 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java
@@ -28,5 +28,5 @@ public interface JingleDescriptionManager {
void notifySessionInitiate(JingleSession session);
- void notifyContentAdd(JingleContent content);
+ void notifyContentAdd(JingleSession session, JingleContent content);
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleContent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleContent.java
index 0c4990c1e..39a4386ee 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleContent.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleContent.java
@@ -27,6 +27,7 @@ import java.util.logging.Logger;
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.jingle.Callback;
@@ -62,6 +63,69 @@ public class JingleContent implements JingleTransportCallback {
private final List callbacks = Collections.synchronizedList(new ArrayList());
private final Set transportBlacklist = Collections.synchronizedSet(new HashSet());
+ public IQ handleJingleRequest(JingleElement request, XMPPConnection connection) {
+ switch (request.getAction()) {
+ case content_modify:
+ return handleContentModify(request, connection);
+ case description_info:
+ return handleDescriptionInfo(request, connection);
+ case security_info:
+ return handleSecurityInfo(request, connection);
+ case session_info:
+ return handleSessionInfo(request, connection);
+ case transport_accept:
+ return handleTransportAccept(request, connection);
+ case transport_info:
+ return handleTransportInfo(request, connection);
+ case transport_reject:
+ return handleTransportReject(request, connection);
+ case transport_replace:
+ return handleTransportReplace(request, connection);
+ default:
+ throw new AssertionError("Illegal jingle action: " + request.getAction() + " is not allowed here.");
+ }
+ }
+
+ public IQ handleSessionAccept(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleContentModify(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleDescriptionInfo(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public void handleContentRemove(JingleSession session, XMPPConnection connection) {
+
+ }
+
+ public IQ handleSecurityInfo(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleSessionInfo(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleTransportAccept(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleTransportInfo(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleTransportReject(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
+ public IQ handleTransportReplace(JingleElement request, XMPPConnection connection) {
+ return IQ.createResultIQ(request);
+ }
+
public enum STATE {
pending_accept,
pending_transmission_start,
@@ -77,9 +141,9 @@ public class JingleContent implements JingleTransportCallback {
}
public JingleContent(JingleDescription> description, JingleTransport> transport, JingleSecurity> security, String name, String disposition, JingleContentElement.Creator creator, JingleContentElement.Senders senders) {
- this.description = description;
- this.transport = transport;
- this.security = security;
+ setDescription(description);
+ setTransport(transport);
+ setSecurity(security);
this.name = name;
this.disposition = disposition;
this.creator = creator;
@@ -178,7 +242,7 @@ public class JingleContent implements JingleTransportCallback {
}
public void setDescription(JingleDescription> description) {
- if (this.description != description) {
+ if (description != null && this.description != description) {
this.description = description;
description.setParent(this);
}
@@ -189,7 +253,7 @@ public class JingleContent implements JingleTransportCallback {
}
public void setTransport(JingleTransport> transport) {
- if (this.transport != transport) {
+ if (transport != null && this.transport != transport) {
this.transport = transport;
transport.setParent(this);
}
@@ -200,7 +264,7 @@ public class JingleContent implements JingleTransportCallback {
}
public void setSecurity(JingleSecurity> security) {
- if (this.security != security) {
+ if (security != null && this.security != security) {
this.security = security;
security.setParent(this);
}
@@ -266,13 +330,16 @@ public class JingleContent implements JingleTransportCallback {
connection.createStanzaCollectorAndSend(transportReplace).nextResultOrThrow();
}
- public void onContentAccept(XMPPConnection connection)
- throws SmackException.NotConnectedException, InterruptedException {
+ public void handleContentAccept(JingleElement request, XMPPConnection connection) {
//Establish transport
- if (isReceiving()) {
- getTransport().establishIncomingBytestreamSession(connection, this, getParent());
- } else if (isSending()) {
- getTransport().establishOutgoingBytestreamSession(connection, this, getParent());
+ try {
+ if (isReceiving()) {
+ getTransport().establishIncomingBytestreamSession(connection, this, getParent());
+ } else if (isSending()) {
+ getTransport().establishOutgoingBytestreamSession(connection, this, getParent());
+ }
+ } catch (SmackException.NotConnectedException | InterruptedException e) {
+ LOGGER.log(Level.SEVERE, "Error establishing connection: " + e, e);
}
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleSession.java
index 6f0cc0d71..fbfa7ba5a 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleSession.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleSession.java
@@ -21,7 +21,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -33,12 +32,8 @@ import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smackx.jingle.JingleDescriptionManager;
import org.jivesoftware.smackx.jingle.JingleManager;
-import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter;
import org.jivesoftware.smackx.jingle.element.JingleAction;
-import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement;
import org.jivesoftware.smackx.jingle.element.JingleContentElement;
-import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
-import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement;
import org.jivesoftware.smackx.jingle.element.JingleElement;
import org.jivesoftware.smackx.jingle.element.JingleReasonElement;
import org.jivesoftware.smackx.jingle.exception.UnsupportedDescriptionException;
@@ -55,6 +50,7 @@ public class JingleSession {
private static final Logger LOGGER = Logger.getLogger(JingleSession.class.getName());
private final ConcurrentHashMap contents = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap proposedContents = new ConcurrentHashMap<>();
private final JingleManager jingleManager;
private final FullJid initiator, responder;
@@ -82,36 +78,6 @@ public class JingleSession {
this.sessionState = SessionState.fresh;
}
- public void addContent(JingleContent content) {
- contents.put(content.getName(), content);
- content.setParent(this);
- }
-
- public void addContent(JingleContentElement content)
- throws UnsupportedSecurityException, UnsupportedTransportException, UnsupportedDescriptionException {
- addContent(JingleContent.fromElement(content));
- }
-
- public ConcurrentHashMap getContents() {
- return contents;
- }
-
- public JingleContent getContent(String name) {
- return contents.get(name);
- }
-
- public JingleContent getSoleContentOrThrow() {
- if (contents.isEmpty()) {
- return null;
- }
-
- if (contents.size() > 1) {
- throw new IllegalStateException();
- }
-
- return contents.values().iterator().next();
- }
-
public static JingleSession fromSessionInitiate(JingleManager manager, JingleElement initiate)
throws UnsupportedSecurityException, UnsupportedDescriptionException, UnsupportedTransportException {
if (initiate.getAction() != JingleAction.session_initiate) {
@@ -131,10 +97,23 @@ public class JingleSession {
}
public void initiate(XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException {
+ if (this.sessionState != SessionState.fresh) {
+ throw new IllegalStateException("Session is not in fresh state.");
+ }
+
connection.createStanzaCollectorAndSend(createSessionInitiate()).nextResultOrThrow();
this.sessionState = SessionState.pending;
}
+ public void accept(XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException {
+ if (this.sessionState != SessionState.pending) {
+ throw new IllegalStateException("Session is not in pending state.");
+ }
+
+ connection.createStanzaCollectorAndSend(createSessionAccept()).nextResultOrThrow();
+ this.sessionState = SessionState.active;
+ }
+
public JingleElement createSessionInitiate() {
if (role != Role.initiator) {
throw new IllegalStateException("Sessions role is not initiator.");
@@ -148,87 +127,81 @@ public class JingleSession {
return JingleElement.createSessionInitiate(getInitiator(), getResponder(), getSessionId(), contentElements);
}
+ public JingleElement createSessionAccept() {
+ if (role != Role.responder) {
+ throw new IllegalStateException("Sessions role is not responder.");
+ }
+
+ List contentElements = new ArrayList<>();
+ for (JingleContent c : contents.values()) {
+ contentElements.add(c.getElement());
+ }
+
+ return JingleElement.createSessionAccept(getInitiator(), getResponder(), getSessionId(), contentElements);
+ }
+
public IQ handleJingleRequest(JingleElement request) {
switch (request.getAction()) {
+ case content_modify:
+ case description_info:
+ case security_info:
+ case session_info:
+ case transport_accept:
+ case transport_info:
+ case transport_reject:
+ case transport_replace:
+ return getSoleAffectedContentOrThrow(request).handleJingleRequest(request, jingleManager.getConnection());
case content_accept:
return handleContentAccept(request);
case content_add:
return handleContentAdd(request);
- case content_modify:
- return handleContentModify(request);
case content_reject:
return handleContentReject(request);
case content_remove:
return handleContentRemove(request);
- case description_info:
- return handleDescriptionInfo(request);
- case session_info:
- return handleSessionInfo(request);
- case security_info:
- return handleSecurityInfo(request);
case session_accept:
return handleSessionAccept(request);
- case transport_accept:
- return handleTransportAccept(request);
- case transport_info:
- return handleTransportInfo(request);
case session_initiate:
return handleSessionInitiate(request);
- case transport_reject:
- return handleTransportReject(request);
case session_terminate:
return handleSessionTerminate(request);
- case transport_replace:
- return handleTransportReplace(request);
default:
- throw new AssertionError("Unknown Jingle Action enum! " + request.getAction());
+ throw new AssertionError("Illegal jingle action: " + request.getAction());
}
}
- private IQ handleTransportReplace(final JingleElement request) {
- Async.go(new Runnable() {
- @Override
- public void run() {
- List affectedContents = request.getContents();
- List responses = new ArrayList<>();
+ /* ############## Processed in this class ############## */
- for (JingleContentElement affected : affectedContents) {
- JingleContent content = contents.get(affected.getName());
- JingleContentTransportElement newTransport = affected.getTransport();
- Set blacklist = content.getTransportBlacklist();
+ /**
+ * Handle incoming session-accept stanza.
+ * @param request session-accept stanza.
+ * @return result.
+ */
+ private IQ handleSessionAccept(final JingleElement request) {
+ this.sessionState = SessionState.active;
- // Proposed transport method might already be on the blacklist (eg. because of previous failures)
- if (blacklist.contains(newTransport.getNamespace())) {
- responses.add(JingleElement.createTransportReject(getInitiator(), getPeer(), getSessionId(),
- content.getCreator(), content.getName(), newTransport));
- continue;
- }
-
- JingleTransportAdapter> transportAdapter = JingleManager.getJingleTransportAdapter(
- newTransport.getNamespace());
- // This might be an unknown transport.
- if (transportAdapter == null) {
- responses.add(JingleElement.createTransportReject(getInitiator(), getPeer(), getSessionId(),
- content.getCreator(), content.getName(), newTransport));
- continue;
- }
-
- //Otherwise, when all went well so far, accept the transport-replace
- content.setTransport(JingleManager.getJingleTransportAdapter(newTransport.getNamespace())
- .transportFromElement(newTransport));
- responses.add(JingleElement.createTransportAccept(getInitiator(), getPeer(), getSessionId(),
- content.getCreator(), content.getName(), newTransport));
+ for (final JingleContent content : contents.values()) {
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleSessionAccept(request, jingleManager.getConnection());
}
+ });
+ }
- for (JingleElement response : responses) {
- try {
- jingleManager.getConnection().createStanzaCollectorAndSend(response).nextResultOrThrow();
- } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException | SmackException.NotConnectedException e) {
- LOGGER.log(Level.SEVERE, "Could not send response to transport-replace: " + e, e);
- }
- }
- }
- });
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleSessionInitiate(JingleElement request) {
+ JingleDescription> description = getSoleContentOrThrow().getDescription();
+ JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(description.getNamespace());
+
+ if (descriptionManager == null) {
+ LOGGER.log(Level.WARNING, "Unsupported description type: " + description.getNamespace());
+ return JingleElement.createSessionTerminate(getPeer(), getSessionId(), JingleReasonElement.Reason.unsupported_applications);
+ }
+
+ descriptionManager.notifySessionInitiate(this);
return IQ.createResultIQ(request);
}
@@ -247,168 +220,193 @@ public class JingleSession {
return IQ.createResultIQ(request);
}
- private IQ handleTransportReject(JingleElement request) {
- HashMap affectedContents = getAffectedContents(request);
- for (JingleContent c : affectedContents.values()) {
+ private IQ handleContentAccept(final JingleElement request) {
+ for (JingleContentElement a : request.getContents()) {
+ final JingleContent accepted = proposedContents.get(a.getName());
- }
- return null;
- }
-
- private IQ handleSessionInitiate(JingleElement request) {
- JingleDescription> description = getSoleContentOrThrow().getDescription();
- JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(description.getNamespace());
-
- if (descriptionManager == null) {
- LOGGER.log(Level.WARNING, "Unsupported description type: " + description.getNamespace());
- return JingleElement.createSessionTerminate(getPeer(), getSessionId(), JingleReasonElement.Reason.unsupported_applications);
- }
-
- descriptionManager.notifySessionInitiate(this);
-
- return IQ.createResultIQ(request);
- }
-
- private IQ handleTransportInfo(JingleElement request) {
- HashMap affectedContents = getAffectedContents(request);
-
- for (Map.Entry entry : affectedContents.entrySet()) {
- JingleTransport> transport = entry.getValue().getTransport();
- JingleContentTransportInfoElement info = entry.getKey().getTransport().getInfo();
- transport.handleTransportInfo(info, request);
- }
-
- return IQ.createResultIQ(request);
- }
-
- private IQ handleTransportAccept(JingleElement request) {
- HashMap affectedContents = getAffectedContents(request);
- for (Map.Entry entry : affectedContents.entrySet()) {
-
- PendingJingleAction pending = pendingJingleActions.get(entry.getValue());
- if (pending == null) {
- continue;
+ if (accepted == null) {
+ throw new AssertionError("Illegal content name!");
}
- if (pending.getAction() != JingleAction.transport_replace) {
- //TODO: Are multiple contents even possible here?
- //TODO: How to react to partially illegal requests?
- return JingleElement.createJingleErrorOutOfOrder(request);
- }
+ proposedContents.remove(accepted.getName());
+ contents.put(accepted.getName(), accepted);
- entry.getValue().setTransport(((PendingJingleAction.TransportReplace) pending).getNewTransport());
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ accepted.handleContentAccept(request, jingleManager.getConnection());
+ }
+ });
}
return IQ.createResultIQ(request);
}
- private IQ handleSessionAccept(JingleElement request) {
- this.sessionState = SessionState.active;
-
- return null;
- }
-
- private IQ handleSecurityInfo(JingleElement request) {
- HashMap affectedContents = getAffectedContents(request);
- List responses = new ArrayList<>();
-
- for (Map.Entry entry : affectedContents.entrySet()) {
- responses.add(entry.getValue().getSecurity().handleSecurityInfo(entry.getKey().getSecurity().getSecurityInfo(), request));
- }
-
- for (JingleElement response : responses) {
- try {
- getJingleManager().getConnection().createStanzaCollectorAndSend(response).nextResultOrThrow();
- } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException e) {
- LOGGER.log(Level.SEVERE, "Could not send response to security-info: " + e, e);
- }
- }
-
- return IQ.createResultIQ(request);
- }
-
- private IQ handleSessionInfo(JingleElement request) {
- return null;
- }
-
- private IQ handleDescriptionInfo(JingleElement request) {
- HashMap affectedContents = getAffectedContents(request);
- List responses = new ArrayList<>();
-
- for (Map.Entry entry : affectedContents.entrySet()) {
- responses.add(entry.getValue().getDescription().handleDescriptionInfo(entry.getKey().getDescription().getDescriptionInfo()));
- }
-
- for (JingleElement response : responses) {
- try {
- getJingleManager().getConnection().createStanzaCollectorAndSend(response).nextResultOrThrow();
- } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException e) {
- LOGGER.log(Level.SEVERE, "Could not send response to description-info: " + e, e);
- }
- }
-
- return IQ.createResultIQ(request);
- }
-
- private IQ handleContentRemove(JingleElement request) {
- return null;
- }
-
- private IQ handleContentReject(JingleElement request) {
- return null;
- }
-
- private IQ handleContentModify(JingleElement request) {
- return null;
- }
-
private IQ handleContentAdd(JingleElement request) {
- final List proposedContents = request.getContents();
- final List acceptedContents = new ArrayList<>();
+ final JingleContent proposed = getSoleProposedContentOrThrow(request);
- final HashMap> contentsByDescription = new HashMap<>();
+ final JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(proposed.getDescription().getNamespace());
- for (JingleContentElement p : proposedContents) {
- JingleContentDescriptionElement description = p.getDescription();
- List list = contentsByDescription.get(description.getNamespace());
- if (list == null) {
- list = new ArrayList<>();
- contentsByDescription.put(description.getNamespace(), list);
- }
- list.add(JingleContent.fromElement(p));
+ if (descriptionManager == null) {
+ throw new AssertionError("DescriptionManager is null: " + proposed.getDescription().getNamespace());
}
- for (Map.Entry> descriptionCategory : contentsByDescription.entrySet()) {
- JingleDescriptionManager descriptionManager = JingleManager.getInstanceFor(getJingleManager().getConnection()).getDescriptionManager(descriptionCategory.getKey());
-
- if (descriptionManager == null) {
- //blabla
- continue;
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ descriptionManager.notifyContentAdd(JingleSession.this, proposed);
}
-
- for (final JingleContent content : descriptionCategory.getValue()) {
- descriptionManager.notifyContentAdd(content);
- }
- }
-
- if (acceptedContents.size() > 0) {
- JingleElement accept = JingleElement.createContentAccept(getPeer(), getSessionId(), acceptedContents);
- try {
- getJingleManager().getConnection().createStanzaCollectorAndSend(accept).nextResultOrThrow();
- } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException | SmackException.NotConnectedException e) {
- LOGGER.log(Level.SEVERE, "Could not send response to content-add: " + e, e);
- }
- }
-
- //TODO: send content-reject for rejected contents!
+ });
return IQ.createResultIQ(request);
}
- private IQ handleContentAccept(JingleElement request) {
- return null;
+ private IQ handleContentReject(JingleElement request) {
+ for (JingleContentElement r : request.getContents()) {
+ final JingleContent rejected = proposedContents.get(r.getName());
+
+ if (rejected == null) {
+ throw new AssertionError("Illegal content name!");
+ }
+
+ proposedContents.remove(rejected.getName());
+
+ /*
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ rejected.handleContentReject(request, jingleManager.getConnection());
+ }
+ });
+ */
+ }
+
+ return IQ.createResultIQ(request);
}
+ private IQ handleContentRemove(final JingleElement request) {
+ for (JingleContentElement r : request.getContents()) {
+ final JingleContent removed = contents.get(r.getName());
+
+ if (removed == null) {
+ throw new AssertionError("Illegal content name!");
+ }
+
+ contents.remove(removed.getName());
+
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ removed.handleContentRemove(JingleSession.this, jingleManager.getConnection());
+ }
+ });
+ }
+
+ return IQ.createResultIQ(request);
+ }
+
+ /* ############## Processed further down ############## */
+
+ private IQ handleContentModify(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleContentModify(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleDescriptionInfo(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleDescriptionInfo(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleSecurityInfo(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleSecurityInfo(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleSessionInfo(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleSessionInfo(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleTransportAccept(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleTransportAccept(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleTransportInfo(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleTransportInfo(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleTransportReject(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleTransportReject(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ private IQ handleTransportReplace(final JingleElement request) {
+ final JingleContent content = getSoleAffectedContentOrThrow(request);
+ Async.go(new Runnable() {
+ @Override
+ public void run() {
+ content.handleTransportReplace(request, jingleManager.getConnection());
+ }
+ });
+
+ return IQ.createResultIQ(request);
+ }
+
+ /* ################ Other getters and setters ############### */
+
public FullJid getInitiator() {
return initiator;
}
@@ -453,6 +451,57 @@ public class JingleSession {
return map;
}
+ private JingleContent getSoleAffectedContentOrThrow(JingleElement request) {
+ if (request.getContents().size() != 1) {
+ throw new AssertionError("More/less than 1 content in request!");
+ }
+
+ JingleContent content = contents.get(request.getContents().get(0).getName());
+ if (content == null) {
+ throw new AssertionError("Illegal content name!");
+ }
+
+ return content;
+ }
+
+ private JingleContent getSoleProposedContentOrThrow(JingleElement request) {
+ if (request.getContents().size() != 1) {
+ throw new AssertionError("More/less than 1 content in request!");
+ }
+
+ return JingleContent.fromElement(request.getContents().get(0));
+ }
+
+ public void addContent(JingleContent content) {
+ contents.put(content.getName(), content);
+ content.setParent(this);
+ }
+
+ public void addContent(JingleContentElement content)
+ throws UnsupportedSecurityException, UnsupportedTransportException, UnsupportedDescriptionException {
+ addContent(JingleContent.fromElement(content));
+ }
+
+ public ConcurrentHashMap getContents() {
+ return contents;
+ }
+
+ public JingleContent getContent(String name) {
+ return contents.get(name);
+ }
+
+ public JingleContent getSoleContentOrThrow() {
+ if (contents.isEmpty()) {
+ return null;
+ }
+
+ if (contents.size() > 1) {
+ throw new IllegalStateException();
+ }
+
+ return contents.values().iterator().next();
+ }
+
public SessionState getSessionState() {
return sessionState;
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java
index af1785dbe..1287970fe 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.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.element;
import org.jivesoftware.smack.packet.NamedElement;
diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferTest.java
index 95b68c28f..a89be4bb8 100644
--- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferTest.java
+++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jft/JingleFileTransferTest.java
@@ -27,6 +27,8 @@ import java.util.ArrayList;
import java.util.concurrent.Future;
import java.util.logging.Level;
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
import org.jivesoftware.smackx.jft.controller.IncomingFileOfferController;
import org.jivesoftware.smackx.jft.controller.OutgoingFileOfferController;
@@ -86,6 +88,7 @@ public class JingleFileTransferTest extends AbstractSmackIntegrationTest {
@Override
public void onIncomingFileOffer(IncomingFileOfferController offer) {
LOGGER.log(Level.INFO, "INCOMING FILE TRANSFER!");
+
offer.addProgressListener(new ProgressListener() {
@Override
public void started() {
@@ -102,11 +105,17 @@ public class JingleFileTransferTest extends AbstractSmackIntegrationTest {
resultSyncPoint2.signal();
}
});
- receiveFuture.add(offer.accept(target));
+
+ try {
+ receiveFuture.add(offer.accept(conTwo, target));
+ } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
+ fail(e.toString());
+ }
}
});
OutgoingFileOfferController sending = aftm.sendFile(source, bob);
+
sending.addProgressListener(new ProgressListener() {
@Override
public void started() {