Pass events down to contents

This commit is contained in:
vanitasvitae 2017-07-29 19:31:16 +02:00
parent 185d569b89
commit af069ffc49
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
9 changed files with 423 additions and 251 deletions

View File

@ -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());
}
}

View File

@ -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 <a href="https://xmpp.org/extensions/xep-0234.html">XEP-0234: Jingle File Transfer</a>.
* Adapters.
*/
package org.jivesoftware.smackx.jft.adapter;

View File

@ -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<Void> accept(File target);
Future<Void> accept(XMPPConnection connection, File target) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException;
}

View File

@ -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<RemoteFile>
}
@Override
public Future<Void> accept(File target) {
public Future<Void> 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;

View File

@ -28,5 +28,5 @@ public interface JingleDescriptionManager {
void notifySessionInitiate(JingleSession session);
void notifyContentAdd(JingleContent content);
void notifyContentAdd(JingleSession session, JingleContent content);
}

View File

@ -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<Callback> callbacks = Collections.synchronizedList(new ArrayList<Callback>());
private final Set<String> transportBlacklist = Collections.synchronizedSet(new HashSet<String>());
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);
}
}

View File

@ -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<String, JingleContent> contents = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, JingleContent> 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<String, JingleContent> 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<JingleContentElement> 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<JingleContentElement> affectedContents = request.getContents();
List<JingleElement> responses = new ArrayList<>();
/* ############## Processed in this class ############## */
for (JingleContentElement affected : affectedContents) {
JingleContent content = contents.get(affected.getName());
JingleContentTransportElement newTransport = affected.getTransport();
Set<String> 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<JingleContentElement, JingleContent> 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<JingleContentElement, JingleContent> affectedContents = getAffectedContents(request);
for (Map.Entry<JingleContentElement, JingleContent> 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<JingleContentElement, JingleContent> affectedContents = getAffectedContents(request);
for (Map.Entry<JingleContentElement, JingleContent> 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<JingleContentElement, JingleContent> affectedContents = getAffectedContents(request);
List<JingleElement> responses = new ArrayList<>();
for (Map.Entry<JingleContentElement, JingleContent> 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<JingleContentElement, JingleContent> affectedContents = getAffectedContents(request);
List<JingleElement> responses = new ArrayList<>();
for (Map.Entry<JingleContentElement, JingleContent> 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<JingleContentElement> proposedContents = request.getContents();
final List<JingleContentElement> acceptedContents = new ArrayList<>();
final JingleContent proposed = getSoleProposedContentOrThrow(request);
final HashMap<String, List<JingleContent>> contentsByDescription = new HashMap<>();
final JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(proposed.getDescription().getNamespace());
for (JingleContentElement p : proposedContents) {
JingleContentDescriptionElement description = p.getDescription();
List<JingleContent> 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<String, List<JingleContent>> 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<String, JingleContent> 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;
}

View File

@ -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;

View File

@ -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() {