aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smackx/packet/StreamInitiation.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jivesoftware/smackx/packet/StreamInitiation.java')
-rw-r--r--src/org/jivesoftware/smackx/packet/StreamInitiation.java419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smackx/packet/StreamInitiation.java b/src/org/jivesoftware/smackx/packet/StreamInitiation.java
new file mode 100644
index 0000000..511a02c
--- /dev/null
+++ b/src/org/jivesoftware/smackx/packet/StreamInitiation.java
@@ -0,0 +1,419 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2003-2006 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.Date;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * The process by which two entities initiate a stream.
+ *
+ * @author Alexander Wenckus
+ */
+public class StreamInitiation extends IQ {
+
+ private String id;
+
+ private String mimeType;
+
+ private File file;
+
+ private Feature featureNegotiation;
+
+ /**
+ * The "id" attribute is an opaque identifier. This attribute MUST be
+ * present on type='set', and MUST be a valid string. This SHOULD NOT be
+ * sent back on type='result', since the <iq/> "id" attribute provides the
+ * only context needed. This value is generated by the Sender, and the same
+ * value MUST be used throughout a session when talking to the Receiver.
+ *
+ * @param id The "id" attribute.
+ */
+ public void setSesssionID(final String id) {
+ this.id = id;
+ }
+
+ /**
+ * Uniquely identifies a stream initiation to the recipient.
+ *
+ * @return The "id" attribute.
+ * @see #setSesssionID(String)
+ */
+ public String getSessionID() {
+ return id;
+ }
+
+ /**
+ * The "mime-type" attribute identifies the MIME-type for the data across
+ * the stream. This attribute MUST be a valid MIME-type as registered with
+ * the Internet Assigned Numbers Authority (IANA) [3] (specifically, as
+ * listed at <http://www.iana.org/assignments/media-types>). During
+ * negotiation, this attribute SHOULD be present, and is otherwise not
+ * required. If not included during negotiation, its value is assumed to be
+ * "binary/octect-stream".
+ *
+ * @param mimeType The valid mime-type.
+ */
+ public void setMimeType(final String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+ /**
+ * Identifies the type of file that is desired to be transfered.
+ *
+ * @return The mime-type.
+ * @see #setMimeType(String)
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ /**
+ * Sets the file which contains the information pertaining to the file to be
+ * transfered.
+ *
+ * @param file The file identified by the stream initiator to be sent.
+ */
+ public void setFile(final File file) {
+ this.file = file;
+ }
+
+ /**
+ * Returns the file containing the information about the request.
+ *
+ * @return Returns the file containing the information about the request.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Sets the data form which contains the valid methods of stream neotiation
+ * and transfer.
+ *
+ * @param form The dataform containing the methods.
+ */
+ public void setFeatureNegotiationForm(final DataForm form) {
+ this.featureNegotiation = new Feature(form);
+ }
+
+ /**
+ * Returns the data form which contains the valid methods of stream
+ * neotiation and transfer.
+ *
+ * @return Returns the data form which contains the valid methods of stream
+ * neotiation and transfer.
+ */
+ public DataForm getFeatureNegotiationForm() {
+ return featureNegotiation.getData();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jivesoftware.smack.packet.IQ#getChildElementXML()
+ */
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ if (this.getType().equals(IQ.Type.SET)) {
+ buf.append("<si xmlns=\"http://jabber.org/protocol/si\" ");
+ if (getSessionID() != null) {
+ buf.append("id=\"").append(getSessionID()).append("\" ");
+ }
+ if (getMimeType() != null) {
+ buf.append("mime-type=\"").append(getMimeType()).append("\" ");
+ }
+ buf
+ .append("profile=\"http://jabber.org/protocol/si/profile/file-transfer\">");
+
+ // Add the file section if there is one.
+ String fileXML = file.toXML();
+ if (fileXML != null) {
+ buf.append(fileXML);
+ }
+ }
+ else if (this.getType().equals(IQ.Type.RESULT)) {
+ buf.append("<si xmlns=\"http://jabber.org/protocol/si\">");
+ }
+ else {
+ throw new IllegalArgumentException("IQ Type not understood");
+ }
+ if (featureNegotiation != null) {
+ buf.append(featureNegotiation.toXML());
+ }
+ buf.append("</si>");
+ return buf.toString();
+ }
+
+ /**
+ * <ul>
+ * <li>size: The size, in bytes, of the data to be sent.</li>
+ * <li>name: The name of the file that the Sender wishes to send.</li>
+ * <li>date: The last modification time of the file. This is specified
+ * using the DateTime profile as described in Jabber Date and Time Profiles.</li>
+ * <li>hash: The MD5 sum of the file contents.</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * &lt;desc&gt; is used to provide a sender-generated description of the
+ * file so the receiver can better understand what is being sent. It MUST
+ * NOT be sent in the result.
+ * <p/>
+ * <p/>
+ * When &lt;range&gt; is sent in the offer, it should have no attributes.
+ * This signifies that the sender can do ranged transfers. When a Stream
+ * Initiation result is sent with the <range> element, it uses these
+ * attributes:
+ * <p/>
+ * <ul>
+ * <li>offset: Specifies the position, in bytes, to start transferring the
+ * file data from. This defaults to zero (0) if not specified.</li>
+ * <li>length - Specifies the number of bytes to retrieve starting at
+ * offset. This defaults to the length of the file from offset to the end.</li>
+ * </ul>
+ * <p/>
+ * <p/>
+ * Both attributes are OPTIONAL on the &lt;range&gt; element. Sending no
+ * attributes is synonymous with not sending the &lt;range&gt; element. When
+ * no &lt;range&gt; element is sent in the Stream Initiation result, the
+ * Sender MUST send the complete file starting at offset 0. More generally,
+ * data is sent over the stream byte for byte starting at the offset
+ * position for the length specified.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class File implements PacketExtension {
+
+ private final String name;
+
+ private final long size;
+
+ private String hash;
+
+ private Date date;
+
+ private String desc;
+
+ private boolean isRanged;
+
+ /**
+ * Constructor providing the name of the file and its size.
+ *
+ * @param name The name of the file.
+ * @param size The size of the file in bytes.
+ */
+ public File(final String name, final long size) {
+ if (name == null) {
+ throw new NullPointerException("name cannot be null");
+ }
+
+ this.name = name;
+ this.size = size;
+ }
+
+ /**
+ * Returns the file's name.
+ *
+ * @return Returns the file's name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the file's size.
+ *
+ * @return Returns the file's size.
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Sets the MD5 sum of the file's contents
+ *
+ * @param hash The MD5 sum of the file's contents.
+ */
+ public void setHash(final String hash) {
+ this.hash = hash;
+ }
+
+ /**
+ * Returns the MD5 sum of the file's contents
+ *
+ * @return Returns the MD5 sum of the file's contents
+ */
+ public String getHash() {
+ return hash;
+ }
+
+ /**
+ * Sets the date that the file was last modified.
+ *
+ * @param date The date that the file was last modified.
+ */
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ /**
+ * Returns the date that the file was last modified.
+ *
+ * @return Returns the date that the file was last modified.
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * Sets the description of the file.
+ *
+ * @param desc The description of the file so that the file reciever can
+ * know what file it is.
+ */
+ public void setDesc(final String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * Returns the description of the file.
+ *
+ * @return Returns the description of the file.
+ */
+ public String getDesc() {
+ return desc;
+ }
+
+ /**
+ * True if a range can be provided and false if it cannot.
+ *
+ * @param isRanged True if a range can be provided and false if it cannot.
+ */
+ public void setRanged(final boolean isRanged) {
+ this.isRanged = isRanged;
+ }
+
+ /**
+ * Returns whether or not the initiator can support a range for the file
+ * tranfer.
+ *
+ * @return Returns whether or not the initiator can support a range for
+ * the file tranfer.
+ */
+ public boolean isRanged() {
+ return isRanged;
+ }
+
+ public String getElementName() {
+ return "file";
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/si/profile/file-transfer";
+ }
+
+ public String toXML() {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append("<").append(getElementName()).append(" xmlns=\"")
+ .append(getNamespace()).append("\" ");
+
+ if (getName() != null) {
+ buffer.append("name=\"").append(StringUtils.escapeForXML(getName())).append("\" ");
+ }
+
+ if (getSize() > 0) {
+ buffer.append("size=\"").append(getSize()).append("\" ");
+ }
+
+ if (getDate() != null) {
+ buffer.append("date=\"").append(StringUtils.formatXEP0082Date(date)).append("\" ");
+ }
+
+ if (getHash() != null) {
+ buffer.append("hash=\"").append(getHash()).append("\" ");
+ }
+
+ if ((desc != null && desc.length() > 0) || isRanged) {
+ buffer.append(">");
+ if (getDesc() != null && desc.length() > 0) {
+ buffer.append("<desc>").append(StringUtils.escapeForXML(getDesc())).append("</desc>");
+ }
+ if (isRanged()) {
+ buffer.append("<range/>");
+ }
+ buffer.append("</").append(getElementName()).append(">");
+ }
+ else {
+ buffer.append("/>");
+ }
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * The feature negotiation portion of the StreamInitiation packet.
+ *
+ * @author Alexander Wenckus
+ *
+ */
+ public class Feature implements PacketExtension {
+
+ private final DataForm data;
+
+ /**
+ * The dataform can be provided as part of the constructor.
+ *
+ * @param data The dataform.
+ */
+ public Feature(final DataForm data) {
+ this.data = data;
+ }
+
+ /**
+ * Returns the dataform associated with the feature negotiation.
+ *
+ * @return Returns the dataform associated with the feature negotiation.
+ */
+ public DataForm getData() {
+ return data;
+ }
+
+ public String getNamespace() {
+ return "http://jabber.org/protocol/feature-neg";
+ }
+
+ public String getElementName() {
+ return "feature";
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf
+ .append("<feature xmlns=\"http://jabber.org/protocol/feature-neg\">");
+ buf.append(data.toXML());
+ buf.append("</feature>");
+ return buf.toString();
+ }
+ }
+}