diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md index 05ffa0b5c..d2764a2d0 100644 --- a/documentation/extensions/index.md +++ b/documentation/extensions/index.md @@ -56,6 +56,7 @@ Smack Extensions and currently supported XEPs of smack-extensions | Stream Initation | [XEP-0095](http://xmpp.org/extensions/xep-0095.html) | Initiating a data stream between any two XMPP entities. | | [SI File Transfer](filetransfer.md) | [XEP-0096](http://xmpp.org/extensions/xep-0096.html) | Transfer files between two users over XMPP. | | [Entity Capabilities](caps.md) | [XEP-0115](http://xmpp.org/extensions/xep-0115.html) | Broadcasting and dynamic discovery of entity capabilities. | +| [Jingle](jingle.html) | [XEP-0116](http://xmpp.org/extensions/xep-0166.html) | Initiate and manage sessions between two XMPP entities. | | Data Forms Validation | [XEP-0122](http://xmpp.org/extensions/xep-0122.html) | Enables an application to specify additional validation guidelines . | | Service Administration | [XEP-0133](http://xmpp.org/extensions/xep-0133.html) | Recommended best practices for service-level administration of servers and components using Ad-Hoc Commands. | | Stream Compression | [XEP-0138](http://xmpp.org/extensions/xep-0138.html) | Support for optional compression of the XMPP stream. diff --git a/documentation/extensions/jingle.md b/documentation/extensions/jingle.md new file mode 100644 index 000000000..926c3aef8 --- /dev/null +++ b/documentation/extensions/jingle.md @@ -0,0 +1,72 @@ +Jingle +====== + +**XEP related:** [XEP-0116: Jingle](http://xmpp.org/extensions/xep-0166.html) + +Jingle Element Structure +------------------------ + +``` +jingle +│ action (REQUIRED, XEP-0166 § 7.2) +| content-accept +| content-add +| content-modify +| content-reject +| content-remove +| description-info +| security-info +| session-accept +| session-info +| session-initiate +| transport-accept +| transport-info +| transport-reject +| transport-replace +│ initator (RECOMMENDED for session initiate, NOT RECOMMENDED otherwise, full JID, XEP-0166 § 7.1) +│ responder (RECOMMENDED for session accept, NOT RECOMMENDED otherwise, full JID. XEP-0166 § 7.1) +│ sid (REQUIRED, SHOULD match XML Nmtoken production) +│ +├── (optional, XEP-0166 § 7.4) +│ │ +│ └──(alternative─session│busy│..) +│ +└── (one or more, XEP-0166 § 7.3) + │ creator (REQUIRED, must be one of) + | initiator + | responder + │ disposition (OPTIONAL) + │ name (REQUIRED) + │ senders (OPTIONAL, except when content-modify then REQUIRED) + | both (default) + | initiator + | none + | responder + │ + ├──description + │ │ media + │ │ xmlns + │ │ + │ ├──payload─type + │ │ + │ └──file (XEP─0234) + │ + └──transport + │ xmlns + │ pwd (OPTIONAL, XEP-0176 Jingle ICE) + │ ufrag (OPTIONAL, XEP-0176 Jingle ICE) + │ mode (XEP-0234 Jingle File Transfer) + │ sid (XEP-0234 Jingle File Transfer) + │ + └──candidate + component + foundation + generation + id + ip + network + port + priority + protocol + type +``` diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java new file mode 100644 index 000000000..4f183fc7c --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java @@ -0,0 +1,26 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.jingle.element.Jingle; + +public interface JingleHandler { + + IQ handleRequest(Jingle jingle); + +} 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 new file mode 100644 index 000000000..03fd4fe40 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java @@ -0,0 +1,136 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; +import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContent; +import org.jivesoftware.smackx.jingle.element.JingleContentDescription; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.Jid; + +public final class JingleManager extends Manager { + + private static final Logger LOGGER = Logger.getLogger(JingleManager.class.getName()); + + private static final Map INSTANCES = new WeakHashMap<>(); + + public static synchronized JingleManager getInstanceFor(XMPPConnection connection) { + JingleManager jingleManager = INSTANCES.get(connection); + if (jingleManager == null) { + jingleManager = new JingleManager(connection); + INSTANCES.put(connection, jingleManager); + } + return jingleManager; + } + + private final Map descriptionHandlers = new ConcurrentHashMap<>(); + + private final Map jingleSessionHandlers = new ConcurrentHashMap<>(); + + private JingleManager(XMPPConnection connection) { + super(connection); + + connection.registerIQRequestHandler( + new AbstractIqRequestHandler(Jingle.ELEMENT, Jingle.NAMESPACE, Type.set, Mode.async) { + @Override + public IQ handleIQRequest(IQ iqRequest) { + final Jingle jingle = (Jingle) iqRequest; + + if (jingle.getContents().isEmpty()) { + Jid from = jingle.getFrom(); + assert (from != null); + FullJid fullFrom = from.asFullJidOrThrow(); + String sid = jingle.getSid(); + FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, sid); + JingleSessionHandler jingleSessionHandler = jingleSessionHandlers.get(fullJidAndSessionId); + if (jingleSessionHandler == null) { + // TODO handle non existing jingle session handler. + return null; + } + return jingleSessionHandler.handleRequest(jingle, sid); + } + + if (jingle.getContents().size() > 1) { + LOGGER.severe("Jingle IQs with more then one content element are currently not supported by Smack"); + return null; + } + + JingleContent content = jingle.getContents().get(0); + JingleContentDescription description = content.getDescription(); + JingleHandler jingleDescriptionHandler = descriptionHandlers.get( + description.getNamespace()); + if (jingleDescriptionHandler == null) { + // TODO handle non existing content description handler. + return null; + } + return jingleDescriptionHandler.handleRequest(jingle); + } + }); + } + + public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) { + return descriptionHandlers.put(namespace, handler); + } + + public JingleSessionHandler registerJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { + FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); + return jingleSessionHandlers.put(fullJidAndSessionId, sessionHandler); + } + + public JingleSessionHandler unregisterJingleSessionhandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { + FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); + return jingleSessionHandlers.remove(fullJidAndSessionId); + } + + private static final class FullJidAndSessionId { + final FullJid fullJid; + final String sessionId; + + private FullJidAndSessionId(FullJid fullJid, String sessionId) { + this.fullJid = fullJid; + this.sessionId = sessionId; + } + + @Override + public int hashCode() { + int hashCode = 31 * fullJid.hashCode(); + hashCode = 31 * hashCode + sessionId.hashCode(); + return hashCode; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof FullJidAndSessionId)) { + return false; + } + FullJidAndSessionId otherFullJidAndSessionId = (FullJidAndSessionId) other; + return fullJid.equals(otherFullJidAndSessionId.fullJid) + && sessionId.equals(otherFullJidAndSessionId.sessionId); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java new file mode 100644 index 000000000..e86223371 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java @@ -0,0 +1,54 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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; + +import org.jxmpp.jid.Jid; + +// TODO: Is this class still required? If not, then remove it. +public class JingleSession { + + private final Jid initiator; + + private final Jid responder; + + private final String sid; + + public JingleSession(Jid initiator, Jid responder, String sid) { + this.initiator = initiator; + this.responder = responder; + this.sid = sid; + } + + @Override + public int hashCode() { + int hashCode = 31 + initiator.hashCode(); + hashCode = 31 * hashCode + responder.hashCode(); + hashCode = 31 * hashCode + sid.hashCode(); + return hashCode; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof JingleSession)) { + return false; + } + + JingleSession otherJingleSession = (JingleSession) other; + return initiator.equals(otherJingleSession.initiator) && responder.equals(otherJingleSession.responder) + && sid.equals(otherJingleSession.sid); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java new file mode 100644 index 000000000..db3cc2f98 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java @@ -0,0 +1,26 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.jingle.element.Jingle; + +public interface JingleSessionHandler { + + IQ handleRequest(Jingle jingle, String sessionId); + +} 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 new file mode 100644 index 000000000..1c5661158 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java @@ -0,0 +1,204 @@ +/** + * + * Copyright 2003-2007 Jive Software, 2014-2017 Florian Schmaus + * + * 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 java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.StringUtils; +import org.jxmpp.jid.FullJid; + +/** + * The Jingle element. + * + * @author Florian Schmaus + */ +public final class Jingle extends IQ { + + public static final String NAMESPACE = "urn:xmpp:jingle:1"; + + public static final String ACTION_ATTRIBUTE_NAME = "action"; + + public static final String INITIATOR_ATTRIBUTE_NAME = "initiator"; + + public static final String RESPONDER_ATTRIBUTE_NAME = "responder"; + + public static final String SESSION_ID_ATTRIBUTE_NAME = "sid"; + + public static final String ELEMENT = "jingle"; + + /** + * The session ID related to this session. The session ID is a unique identifier generated by the initiator. This + * should match the XML Nmtoken production so that XML character escaping is not needed for characters such as &. + */ + private final String sessionId; + + /** + * The jingle action. This attribute is required. + */ + private final JingleAction action; + + private final FullJid initiator; + + private final FullJid responder; + + private final JingleReason reason; + + private final List contents; + + private Jingle(String sessionId, JingleAction action, FullJid initiator, FullJid responder, JingleReason reason, + List contents) { + super(ELEMENT, NAMESPACE); + this.sessionId = StringUtils.requireNotNullOrEmpty(sessionId, "Jingle session ID must not be null"); + this.action = Objects.requireNonNull(action, "Jingle action must not be null"); + this.initiator = initiator; + this.responder = responder; + this.reason = reason; + if (contents != null) { + this.contents = Collections.unmodifiableList(contents); + } + else { + this.contents = Collections.emptyList(); + } + } + + /** + * Get the initiator. The initiator will be the full JID of the entity that has initiated the flow (which may be + * different to the "from" address in the IQ) + * + * @return the initiator + */ + public FullJid getInitiator() { + return initiator; + } + + /** + * Get the responder. The responder is the full JID of the entity that has replied to the initiation (which may be + * different to the "to" addresss in the IQ). + * + * @return the responder + */ + public FullJid getResponder() { + return responder; + } + + /** + * Returns the session ID related to the session. The session ID is a unique identifier generated by the initiator. + * This should match the XML Nmtoken production so that XML character escaping is not needed for characters such as + * &. + * + * @return Returns the session ID related to the session. + */ + public String getSid() { + return sessionId; + } + + /** + * Get the action specified in the jingle IQ. + * + * @return the action. + */ + public JingleAction getAction() { + return action; + } + + /** + * Get a List of the contents. + * + * @return the contents. + */ + public List getContents() { + return contents; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator()); + xml.optAttribute(RESPONDER_ATTRIBUTE_NAME, getResponder()); + xml.optAttribute(ACTION_ATTRIBUTE_NAME, getAction()); + xml.optAttribute(SESSION_ID_ATTRIBUTE_NAME, getSid()); + xml.rightAngleBracket(); + + xml.optElement(reason); + + xml.append(contents); + + return xml; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static final class Builder { + private String sid; + + private JingleAction action; + + private FullJid initiator; + + private FullJid responder; + + private JingleReason reason; + + private List contents; + + private Builder() { + } + + public Builder setSessionId(String sessionId) { + this.sid = sessionId; + return this; + } + + public Builder setAction(JingleAction action) { + this.action = action; + return this; + } + + public Builder setInitiator(FullJid initator) { + this.initiator = initator; + return this; + } + + public Builder setResponder(FullJid responder) { + this.responder = responder; + return this; + } + + public Builder addJingleContent(JingleContent content) { + if (contents == null) { + contents = new ArrayList<>(1); + } + contents.add(content); + return this; + } + + public Builder setReason(JingleReason.Reason reason) { + this.reason = new JingleReason(reason); + return this; + } + + public Jingle build() { + return new Jingle(sid, action, initiator, responder, reason, contents); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java new file mode 100644 index 000000000..81daeb227 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java @@ -0,0 +1,72 @@ +/** + * + * Copyright © 2014-2017 Florian Schmaus + * + * 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 java.util.HashMap; +import java.util.Map; + +/** + * The "action" in the jingle packet, as an enum. + * + * + * @author Florian Schmaus + */ +public enum JingleAction { + + content_accept, + content_add, + content_modify, + content_reject, + content_remove, + description_info, + session_accept, + session_info, + session_initiate, + sessio_terminate, + transport_accept, + transport_info, + transport_reject, + transport_replace, + ; + + private static final Map map = new HashMap( + JingleAction.values().length); + static { + for (JingleAction jingleAction : JingleAction.values()) { + map.put(jingleAction.toString(), jingleAction); + } + } + + private final String asString; + + private JingleAction() { + asString = this.name().replace('_', '-'); + } + + @Override + public String toString() { + return asString; + } + + public static JingleAction fromString(String string) { + JingleAction jingleAction = map.get(string); + if (jingleAction == null) { + throw new IllegalArgumentException("Unknown jingle action: " + string); + } + return jingleAction; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java new file mode 100644 index 000000000..ca5696bff --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java @@ -0,0 +1,218 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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 java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * Jingle content element. + */ +public final class JingleContent implements NamedElement { + + public static final String ELEMENT = "content"; + + public static final String CREATOR_ATTRIBUTE_NAME = "creator"; + + public enum Creator { + initiator, + responder, + } + + /** + * Which party originally generated the content type. Defined values are 'initiator' and 'responder'. Default is + * 'initiator'. + */ + private final Creator creator; + + public static final String DISPOSITION_ATTRIBUTE_NAME = "disposition"; + + private final String disposition; + + public static final String NAME_ATTRIBUTE_NAME = "name"; + + private final String name; + + public static final String SENDERS_ATTRIBUTE_NAME = "senders"; + + public enum Senders { + both, + initiator, + none, + responder, + } + + /** + * Which parties in the session will be generation the content. Defined values are 'both', 'initiator', 'none' and + * 'responder. Default is 'both'. + */ + private final Senders senders; + + private final JingleContentDescription description; + + private final List transports; + + /** + * Creates a content description.. + */ + private JingleContent(Creator creator, String disposition, String name, Senders senders, + JingleContentDescription description, List transports) { + this.creator = Objects.requireNonNull(creator, "Jingle content creator must not be null"); + this.disposition = disposition; + this.name = StringUtils.requireNotNullOrEmpty(name, "Jingle content name must not be null or empty"); + this.senders = senders; + this.description = description; + if (transports != null) { + this.transports = Collections.unmodifiableList(transports); + } + else { + this.transports = Collections.emptyList(); + } + } + + public Creator getCreator() { + return creator; + } + + public String getDisposition() { + return disposition; + } + + public String getName() { + return name; + } + + public Senders getSenders() { + return senders; + } + + /** + * Gets the description for this Jingle content. + * + * @return The description. + */ + public JingleContentDescription getDescription() { + return description; + } + + /** + * Returns an Iterator for the JingleTransports in the packet. + * + * @return an Iterator for the JingleTransports in the packet. + */ + public List getJingleTransports() { + return transports; + } + + /** + * Returns a count of the JingleTransports in the Jingle packet. + * + * @return the number of the JingleTransports in the Jingle packet. + */ + public int getJingleTransportsCount() { + return transports.size(); + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.attribute(CREATOR_ATTRIBUTE_NAME, creator); + xml.optAttribute(DISPOSITION_ATTRIBUTE_NAME, disposition); + xml.attribute(NAME_ATTRIBUTE_NAME, name); + xml.optAttribute(SENDERS_ATTRIBUTE_NAME, senders); + xml.rightAngleBracket(); + + xml.optAppend(description); + + xml.append(transports); + + xml.closeElement(this); + return xml; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static final class Builder { + private Creator creator; + + private String disposition; + + private String name; + + private Senders senders; + + private JingleContentDescription description; + + private List transports; + + private Builder() { + } + + public Builder setCreator(Creator creator) { + this.creator = creator; + return this; + } + + public Builder setDisposition(String disposition) { + this.disposition = disposition; + return this; + } + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setSenders(Senders senders) { + this.senders = senders; + return this; + } + + public Builder setDescription(JingleContentDescription description) { + if (this.description != null) { + throw new IllegalStateException("Jingle content description already set"); + } + this.description = description; + return this; + } + + public Builder addTransport(JingleContentTransport transport) { + if (transports == null) { + transports = new ArrayList<>(4); + } + transports.add(transport); + return this; + } + + public JingleContent build() { + return new JingleContent(creator, disposition, name, senders, description, transports); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java new file mode 100644 index 000000000..7a1e6463f --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java @@ -0,0 +1,68 @@ +/** + * + * Copyright 2017 Florian Schmaus. + * + * 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 java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * Jingle content description. + * + */ +public abstract class JingleContentDescription implements ExtensionElement { + + public static final String ELEMENT = "description"; + + private final List payloads; + + protected JingleContentDescription(List payloads) { + if (payloads != null) { + this.payloads = Collections.unmodifiableList(payloads); + } + else { + this.payloads = Collections.emptyList(); + } + } + + @Override + public String getElementName() { + return ELEMENT; + } + + public List getJinglePayloadTypes() { + return payloads; + } + + protected void addExtraAttributes(XmlStringBuilder xml) { + + } + + @Override + public final XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + addExtraAttributes(xml); + xml.rightAngleBracket(); + + xml.append(payloads); + + return xml; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionPayloadType.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionPayloadType.java new file mode 100644 index 000000000..ff525b0c1 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionPayloadType.java @@ -0,0 +1,33 @@ +/** + * + * Copyright © 2014-2017 Florian Schmaus + * + * 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; + +/** + * An element found usually in 'description' elements. + * + */ +public abstract class JingleContentDescriptionPayloadType implements NamedElement { + + public static final String ELEMENT = "payload-type"; + + @Override + public String getElementName() { + return ELEMENT; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java new file mode 100644 index 000000000..5885c5ad8 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java @@ -0,0 +1,69 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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 java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * A jingle transport extension. + * + */ +public abstract class JingleContentTransport implements ExtensionElement { + + public static final String ELEMENT = "transport"; + + protected final List candidates; + + protected JingleContentTransport(List candidates) { + if (candidates != null) { + this.candidates = Collections.unmodifiableList(candidates); + } + else { + this.candidates = Collections.emptyList(); + } + } + + public List getCandidates() { + return candidates; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + protected void addExtraAttributes(XmlStringBuilder xml) { + + } + + @Override + public final XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + addExtraAttributes(xml); + xml.rightAngleBracket(); + + xml.append(candidates); + + xml.closeElement(this); + return xml; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java new file mode 100644 index 000000000..be38c8864 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java @@ -0,0 +1,33 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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; + +/** + * An element found usually in Jingle 'transport' elements. + * + */ +public abstract class JingleContentTransportCandidate implements NamedElement { + + public static final String ELEMENT = "candidate"; + + @Override + public String getElementName() { + return ELEMENT; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java new file mode 100644 index 000000000..6fa132893 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java @@ -0,0 +1,98 @@ +/** + * + * Copyright 2003-2005 Jive Software, 2017 Florian Schmaus. + * + * 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 java.util.Locale; + +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public final class JingleError implements ExtensionElement { + + public static String NAMESPACE = "urn:xmpp:jingle:errors:1"; + + public static final JingleError OUT_OF_ORDER = new JingleError("out-of-order"); + + public static final JingleError UNKNOWN_SESSION = new JingleError("unknown-session"); + + public static final JingleError UNSUPPORTED_CONTENT = new JingleError("unsupported-content"); + + public static final JingleError UNSUPPORTED_TRANSPORTS = new JingleError("unsupported-transports"); + + private final String errorName; + + /** + * Creates a new error with the specified code and errorName. + * + * @param message a message describing the error. + */ + private JingleError(final String errorName) { + this.errorName = errorName; + } + + /** + * Returns the name of the Jingle error. + * + * @return the name of the error. + */ + public String getMessage() { + return errorName; + } + + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.closeEmptyElement(); + return xml; + } + + /** + * Returns a Action instance associated with the String value. + */ + public static JingleError fromString(String value) { + value = value.toLowerCase(Locale.US); + switch (value) { + case "out-of-order": + return OUT_OF_ORDER; + case "unknown-session": + return UNKNOWN_SESSION; + case "unsupported-content": + return UNSUPPORTED_CONTENT; + case "unsupported-transports": + return UNSUPPORTED_TRANSPORTS; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public String toString() { + return getMessage(); + } + + @Override + public String getElementName() { + return errorName; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java new file mode 100644 index 000000000..b150832d3 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java @@ -0,0 +1,105 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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 java.util.HashMap; +import java.util.Map; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +/** + * The Jingle 'reason' element. + * + * @see XEP-0166 § 7.4 + * + */ +public class JingleReason implements NamedElement { + + public static final String ELEMENT = "reason"; + + public enum Reason { + alternative_session, + busy, + cancel, + connectivity_error, + decline, + expired, + failed_application, + failed_transport, + general_error, + gone, + incompatible_parameters, + media_error, + security_error, + success, + timeout, + unsupported_applications, + unsupported_transports, + ; + + private static final Map LUT = new HashMap<>(Reason.values().length); + + static { + for (Reason reason : Reason.values()) { + LUT.put(reason.toString(), reason); + } + } + + private final String asString; + + private Reason() { + asString = name().replace('_', '-'); + } + + @Override + public String toString() { + return asString; + } + + public static Reason fromString(String string) { + Reason reason = LUT.get(string); + if (reason == null) { + throw new IllegalArgumentException("Unknown reason: " + string); + } + return reason; + } + } + + private final Reason reason; + + public JingleReason(Reason reason) { + this.reason = reason; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.rightAngleBracket(); + + xml.emptyElement(reason); + + xml.closeElement(this); + return xml; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/package-info.java new file mode 100644 index 000000000..49fdcc362 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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. + */ + +/** + * Stanzas and Extension Elements for XEP-0166: Jingle. + */ +package org.jivesoftware.smackx.jingle.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java new file mode 100644 index 000000000..2e7a2ec90 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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-0166: Jingle. + */ +package org.jivesoftware.smackx.jingle; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java new file mode 100644 index 000000000..ac69e7783 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java @@ -0,0 +1,29 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.jingle.element.JingleContentDescription; +import org.xmlpull.v1.XmlPullParser; + +public abstract class JingleContentDescriptionProvider + extends ExtensionElementProvider { + + @Override + public abstract D parse(XmlPullParser parser, int initialDepth) throws Exception; + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java new file mode 100644 index 000000000..a4592e45d --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java @@ -0,0 +1,45 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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.provider; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class JingleContentProviderManager { + + private static final Map> jingleContentDescriptionProviders = new ConcurrentHashMap<>(); + + private static final Map> jingleContentTransportProviders = new ConcurrentHashMap<>(); + + public static JingleContentDescriptionProvider addJingleContentDescrptionProvider(String namespace, + JingleContentDescriptionProvider provider) { + return jingleContentDescriptionProviders.put(namespace, provider); + } + + public static JingleContentDescriptionProvider getJingleContentDescriptionProvider(String namespace) { + return jingleContentDescriptionProviders.get(namespace); + } + + public static JingleContentTransportProvider addJingleContentDescrptionProvider(String namespace, + JingleContentTransportProvider provider) { + return jingleContentTransportProviders.put(namespace, provider); + } + + public static JingleContentTransportProvider getJingleContentTransportProvider(String namespace) { + return jingleContentTransportProviders.get(namespace); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java new file mode 100644 index 000000000..e9e1774f5 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java @@ -0,0 +1,29 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.xmlpull.v1.XmlPullParser; + +public abstract class JingleContentTransportProvider + extends ExtensionElementProvider { + + @Override + public abstract T parse(XmlPullParser parser, int initialDepth) throws Exception; + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java new file mode 100644 index 000000000..12be5370d --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java @@ -0,0 +1,31 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.jingle.element.JingleError; +import org.xmlpull.v1.XmlPullParser; + +public class JingleErrorProvider extends ExtensionElementProvider { + + @Override + public JingleError parse(XmlPullParser parser, int initialDepth) throws Exception { + String errorName = parser.getName(); + return JingleError.fromString(errorName); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java new file mode 100644 index 000000000..f00ebfc0b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java @@ -0,0 +1,149 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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.provider; + +import java.util.logging.Logger; + +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smack.util.ParserUtils; +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.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleReason; +import org.jivesoftware.smackx.jingle.element.JingleReason.Reason; +import org.jxmpp.jid.FullJid; +import org.xmlpull.v1.XmlPullParser; + +public class JingleProvider extends IQProvider { + + private static final Logger LOGGER = Logger.getLogger(JingleProvider.class.getName()); + + @Override + public Jingle parse(XmlPullParser parser, int initialDepth) throws Exception { + Jingle.Builder builder = Jingle.getBuilder(); + + String actionString = parser.getAttributeValue("", Jingle.ACTION_ATTRIBUTE_NAME); + if (actionString != null) { + JingleAction action = JingleAction.fromString(actionString); + builder.setAction(action); + } + + FullJid initiator = ParserUtils.getFullJidAttribute(parser, Jingle.INITIATOR_ATTRIBUTE_NAME); + builder.setInitiator(initiator); + + FullJid responder = ParserUtils.getFullJidAttribute(parser, Jingle.RESPONDER_ATTRIBUTE_NAME); + builder.setResponder(responder); + + String sessionId = parser.getAttributeValue("", Jingle.SESSION_ID_ATTRIBUTE_NAME); + builder.setSessionId(sessionId); + + + outerloop: while (true) { + int eventType = parser.next(); + switch (eventType) { + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + switch (tagName) { + case JingleContent.ELEMENT: + JingleContent content = parseJingleContent(parser, parser.getDepth()); + builder.addJingleContent(content); + break; + case JingleReason.ELEMENT: + parser.next(); + String reasonString = parser.getName(); + Reason reason = Reason.fromString(reasonString); + builder.setReason(reason); + break; + default: + LOGGER.severe("Unknown Jingle element: " + tagName); + break; + } + break; + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return builder.build(); + } + + public static JingleContent parseJingleContent(XmlPullParser parser, final int initialDepth) + throws Exception { + JingleContent.Builder builder = JingleContent.getBuilder(); + + String creatorString = parser.getAttributeValue("", JingleContent.CREATOR_ATTRIBUTE_NAME); + JingleContent.Creator creator = JingleContent.Creator.valueOf(creatorString); + builder.setCreator(creator); + + String disposition = parser.getAttributeValue("", JingleContent.DISPOSITION_ATTRIBUTE_NAME); + builder.setDisposition(disposition); + + String name = parser.getAttributeValue("", JingleContent.NAME_ATTRIBUTE_NAME); + builder.setName(name); + + String sendersString = parser.getAttributeValue("", JingleContent.SENDERS_ATTRIBUTE_NAME); + if (sendersString != null) { + JingleContent.Senders senders = JingleContent.Senders.valueOf(sendersString); + builder.setSenders(senders); + } + + outerloop: while (true) { + int eventType = parser.next(); + switch (eventType) { + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + String namespace = parser.getNamespace(); + switch (tagName) { + case JingleContentDescription.ELEMENT: { + JingleContentDescriptionProvider provider = JingleContentProviderManager.getJingleContentDescriptionProvider(namespace); + if (provider == null) { + // TODO handle this case (DefaultExtensionElement wrapped in something?) + break; + } + JingleContentDescription description = provider.parse(parser); + builder.setDescription(description); + break; + } + case JingleContentTransport.ELEMENT: { + JingleContentTransportProvider provider = JingleContentProviderManager.getJingleContentTransportProvider(namespace); + if (provider == null) { + // TODO handle this case (DefaultExtensionElement wrapped in something?) + break; + } + JingleContentTransport transport = provider.parse(parser); + builder.addTransport(transport); + break; + } + default: + LOGGER.severe("Unknown Jingle content element: " + tagName); + break; + } + break; + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return builder.build(); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/package-info.java new file mode 100644 index 000000000..feb0e8d86 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/package-info.java @@ -0,0 +1,21 @@ +/** + * + * Copyright 2017 Florian Schmaus + * + * 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. + */ + +/** + * Providers and parsers for XEP-0166: Jingle. + */ +package org.jivesoftware.smackx.jingle.provider; diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers index 41705f0ca..fc23362a1 100644 --- a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers +++ b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers @@ -544,4 +544,35 @@ org.jivesoftware.smackx.bob.provider.BoBIQProvider + + + jingle + urn:xmpp:jingle:1 + org.jivesoftware.smackx.jingle.provider.JingleProvider + + + + out-of-order + urn:xmpp:jingle:errors:1 + org.jivesoftware.smackx.jingle.provider.JingleErrorProvider + + + + unknown-session + urn:xmpp:jingle:errors:1 + org.jivesoftware.smackx.jingle.provider.JingleErrorProvider + + + + unsupported-content + urn:xmpp:jingle:errors:1 + org.jivesoftware.smackx.jingle.provider.JingleErrorProvider + + + + unsupported-transports + urn:xmpp:jingle:errors:1 + org.jivesoftware.smackx.jingle.provider.JingleErrorProvider + +