diff options
Diffstat (limited to 'protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Jingle.java')
-rw-r--r-- | protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Jingle.java | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Jingle.java b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Jingle.java new file mode 100644 index 000000000..800e42898 --- /dev/null +++ b/protocols/bundles/org.jivesoftware.smack/src/org/jivesoftware/smackx/packet/Jingle.java @@ -0,0 +1,589 @@ +/** + * $RCSfile: Jingle.java,v $ + * $Revision: 1.1 $ + * $Date: 2006/10/17 19:14:14 $ + * + * Copyright 2003-2004 Jive Software. + * + * All rights reserved. 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.packet; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; + +/** + * An Jingle sub-packet, which is used by XMPP clients to exchange info like + * descriptions and transports. <p/> The following link summarizes the + * requirements of Jingle IM: <a + * href="http://www.jabber.org/jeps/jep-0166.html">Valid tags</a>. + * <p> + * <p/> Warning: this is an non-standard protocol documented by <a + * href="http://www.jabber.org/jeps/jep-0166.html">JEP-166</a>. Because this is + * a non-standard protocol, it is subject to change. + * + * @author Alvaro Saurin + */ +public class Jingle extends IQ { + + // static + + public static final String NAMESPACE = "http://jabber.org/protocol/jingle"; + + public static final String NODENAME = "jingle"; + + // non-static + + private String sid; // The session id + + private Action action; // The action associated to the Jingle + + private String initiator; // The initiator as a "user@host/resource" + + private String responder; // The responder + + // Sub-elements of a Jingle object. + + private final List descriptions = new ArrayList(); + + private final List transports = new ArrayList(); + + private JingleContentInfo contentInfo; + + /** + * A constructor where the main components can be initialized. + */ + public Jingle(final List descs, final List trans, final JingleContentInfo mi, + final String sid) { + super(); + + if (descs != null) { + descriptions.addAll(descs); + } + + if (trans != null) { + transports.addAll(trans); + } + + setContentInfo(mi); + setSid(sid); + + // Set null all other fields in the packet + initiator = null; + responder = null; + action = null; + } + + /** + * Constructor with a description. + * + * @param descr a description + */ + public Jingle(final JingleContentDescription descr) { + super(); + + addDescription(descr); + + // Set null all other fields in the packet + initiator = null; + responder = null; + + // Some default values for the most common situation... + action = Jingle.Action.CONTENTINFO; + this.setType(IQ.Type.SET); + } + + /** + * Constructor with a transport. + * + * @param trans a transport + */ + public Jingle(final JingleTransport trans) { + super(); + + addTransport(trans); + + // Set null all other fields in the packet + initiator = null; + responder = null; + + // Some default values for the most common situation... + action = Jingle.Action.TRANSPORTINFO; + this.setType(IQ.Type.SET); + } + + /** + * Constructor with a content info. + * + * @param info The content info + */ + public Jingle(final JingleContentInfo info) { + super(); + + setContentInfo(info); + + // Set null all other fields in the packet + initiator = null; + responder = null; + + // Some default values for the most common situation... + action = Jingle.Action.CONTENTINFO; + this.setType(IQ.Type.SET); + } + + /** + * A constructor where the action can be specified. + * + * @param action The action. + */ + public Jingle(final Jingle.Action action) { + this(null, null, null, null); + this.action = action; + + // In general, a Jingle with an action is used in a SET packet... + this.setType(IQ.Type.SET); + } + + /** + * A constructor where the session ID can be specified. + * + * @param sid The session ID related to the negotiation. + * @see #setSid(String) + */ + public Jingle(final String sid) { + this(null, null, null, sid); + } + + /** + * The default constructor + */ + public Jingle() { + super(); + } + + /** + * Set 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 &. + * + * @param sid the session ID + */ + public final void setSid(final String sid) { + this.sid = sid; + } + + /** + * 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. + * @see #setSid(String) + */ + public String getSid() { + return sid; + } + + /** + * Returns the XML element name of the extension sub-packet root element. + * Always returns "jingle" + * + * @return the XML element name of the packet extension. + */ + public static String getElementName() { + return NODENAME; + } + + /** + * Returns the XML namespace of the extension sub-packet root element. + * According the specification the namespace is always + * "http://jabber.org/protocol/jingle" + * + * @return the XML namespace of the packet extension. + */ + public static String getNamespace() { + return NAMESPACE; + } + + /** + * @return the audioInfo + */ + public JingleContentInfo getContentInfo() { + return contentInfo; + } + + /** + * @param contentInfo the audioInfo to set + */ + public void setContentInfo(final JingleContentInfo contentInfo) { + this.contentInfo = contentInfo; + } + + /** + * Get an iterator for the content descriptions + * + * @return the descriptions + */ + public Iterator getDescriptions() { + synchronized (descriptions) { + return Collections.unmodifiableList(new ArrayList(descriptions)).iterator(); + } + } + + /** + * Get an iterator for the content descriptions + * + * @return the descriptions + */ + public ArrayList getDescriptionsList() { + synchronized (descriptions) { + return new ArrayList(descriptions); + } + } + + /** + * Add a new content description. + * + * @param desc the descriptions to add + */ + public void addDescription(final JingleContentDescription desc) { + if (desc != null) { + synchronized (descriptions) { + descriptions.add(desc); + } + } + } + + /** + * Add a list of JingleContentDescription elements + * + * @param descsList the list of transports to add + */ + public void addDescriptions(final List descsList) { + if (descsList != null) { + synchronized (descriptions) { + descriptions.addAll(descsList); + } + } + } + + /** + * Get an iterator for the transport. + * + * @return the transports + */ + public Iterator getTransports() { + synchronized (transports) { + return Collections.unmodifiableList(new ArrayList(transports)).iterator(); + } + } + + /** + * Get the list of transports. + * + * @return the transports list. + */ + public ArrayList getTransportsList() { + synchronized (transports) { + return new ArrayList(transports); + } + } + + /** + * Add a new JingleTransport element + * + * @param trans the transports to add + */ + public void addTransport(final JingleTransport trans) { + if (trans != null) { + synchronized (transports) { + transports.add(trans); + } + } + } + + /** + * Add a list of JingleTransport elements + * + * @param transList the list of transports to add + */ + public void addTransports(final List transList) { + if (transList != null) { + synchronized (transports) { + transports.addAll(transList); + } + } + } + + /** + * Get the action specified in the packet + * + * @return the action + */ + public Action getAction() { + return action; + } + + /** + * Set the action in the packet + * + * @param action the action to set + */ + public void setAction(final Action action) { + this.action = action; + } + + /** + * 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 String getInitiator() { + return initiator; + } + + /** + * Set the initiator. The initiator must be the full JID of the entity that + * has initiated the flow (which may be different to the "from" address in + * the IQ) + * + * @param initiator the initiator to set + */ + public void setInitiator(final String initiator) { + this.initiator = 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 String getResponder() { + return responder; + } + + /** + * Set the responder. The responder must be the full JID of the entity that + * has replied to the initiation (which may be different to the "to" + * addresss in the IQ). + * + * @param resp the responder to set + */ + public void setResponder(final String resp) { + responder = resp; + } + + /** + * Get a hash key for the session this packet belongs to. + * + * @param sid The session id + * @param initiator The initiator + * @return A hash key + */ + public static int getSessionHash(final String sid, final String initiator) { + final int PRIME = 31; + int result = 1; + result = PRIME * result + (initiator == null ? 0 : initiator.hashCode()); + result = PRIME * result + (sid == null ? 0 : sid.hashCode()); + return result; + } + + /** + * Return the XML representation of the packet. + * + * @return the XML string + */ + public String getChildElementXML() { + StringBuffer buf = new StringBuffer(); + + buf.append("<").append(getElementName()); + buf.append(" xmlns=\"").append(getNamespace()).append("\""); + if (getInitiator() != null) { + buf.append(" initiator=\"").append(getInitiator()).append("\""); + } + if (getResponder() != null) { + buf.append(" responder=\"").append(getResponder()).append("\""); + } + if (getAction() != null) { + buf.append(" action=\"").append(getAction()).append("\""); + } + if (getSid() != null) { + buf.append(" sid=\"").append(getSid()).append("\""); + } + buf.append(">"); + + // Look for possible payload types, and dump them. + synchronized (descriptions) { + for (int i = 0; i < descriptions.size(); i++) { + JingleContentDescription desc = (JingleContentDescription) descriptions + .get(i); + buf.append(desc.toXML()); + } + } + + // If the packet has transports, dump them. + synchronized (transports) { + for (int i = 0; i < transports.size(); i++) { + JingleTransport trans = (JingleTransport) transports.get(i); + buf.append(trans.toXML()); + } + } + + // and the same for audio media info + if (contentInfo != null) { + buf.append(contentInfo.toXML()); + } + + buf.append("</").append(getElementName()).append(">"); + return buf.toString(); + } + + /** + * The "action" in the jingle packet, as an enum. + */ + public static class Action { + + public static final Action CONTENTACCEPT = new Action("description-accept"); + + public static final Action CONTENTDECLINE = new Action("description-decline"); + + public static final Action CONTENTINFO = new Action("description-info"); + + public static final Action CONTENTMODIFY = new Action("description-modify"); + + public static final Action SESSIONACCEPT = new Action("session-accept"); + + public static final Action SESSIONINFO = new Action("session-info"); + + public static final Action SESSIONINITIATE = new Action("session-initiate"); + + public static final Action SESSIONREDIRECT = new Action("session-redirect"); + + public static final Action SESSIONEXTEND = new Action("session-extend"); + + public static final Action SESSIONREDUCE = new Action("session-reduce"); + + public static final Action SESSIONTERMINATE = new Action("session-terminate"); + + public static final Action TRANSPORTACCEPT = new Action("transport-accept"); + + public static final Action TRANSPORTDECLINE = new Action("transport-decline"); + + public static final Action TRANSPORTINFO = new Action("transport-info"); + + public static final Action TRANSPORTMODIFY = new Action("transport-modify"); + + private String value; + + public Action(final String value) { + this.value = value; + } + + /** + * Returns the String value for an Action. + */ + public String toString() { + return value; + } + + /** + * Returns a Action instance associated with the String value. + */ + public static Action fromString(String value) { + if (value != null) { + value = value.toLowerCase(); + if (value.equals("description-accept")) { + return CONTENTACCEPT; + } else if (value.equals("description-decline")) { + return CONTENTDECLINE; + } else if (value.equals("description-info")) { + return CONTENTINFO; + } else if (value.equals("description-modify")) { + return CONTENTMODIFY; + } else if (value.equals("session-accept")) { + return SESSIONACCEPT; + } else if (value.equals("session-info")) { + return SESSIONINFO; + } else if (value.equals("session-initiate")) { + return SESSIONINITIATE; + } else if (value.equals("session-redirect")) { + return SESSIONACCEPT; + } else if (value.equals("session-extend")) { + return SESSIONEXTEND; + } else if (value.equals("session-reduce")) { + return SESSIONREDUCE; + } else if (value.equals("session-terminate")) { + return SESSIONTERMINATE; + } else if (value.equals("transport-accept")) { + return TRANSPORTACCEPT; + } else if (value.equals("transport-decline")) { + return TRANSPORTDECLINE; + } else if (value.equals("transport-info")) { + return TRANSPORTINFO; + } else if (value.equals("transport-modify")) { + return TRANSPORTMODIFY; + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + (value == null ? 0 : value.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Action other = (Action) obj; + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } + } +} |