001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.bytestreams.ibb.packet; 018 019import org.jivesoftware.smack.packet.ExtensionElement; 020import org.jivesoftware.smack.packet.IQ.IQChildElementXmlStringBuilder; 021import org.jivesoftware.smack.util.XmlStringBuilder; 022import org.jivesoftware.smack.util.stringencoder.Base64; 023 024/** 025 * Represents a chunk of data of an In-Band Bytestream within an IQ stanza or a 026 * message stanza. 027 * 028 * @author Henning Staib 029 */ 030public class DataPacketExtension implements ExtensionElement { 031 032 /** 033 * The element name of the data stanza extension. 034 */ 035 public static final String ELEMENT = "data"; 036 037 /** 038 * The XMPP namespace of the In-Band Bytestream. 039 */ 040 public static final String NAMESPACE = "http://jabber.org/protocol/ibb"; 041 042 /* unique session ID identifying this In-Band Bytestream */ 043 private final String sessionID; 044 045 /* sequence of this packet in regard to the other data packets */ 046 private final long seq; 047 048 /* the data contained in this packet */ 049 private final String data; 050 051 private byte[] decodedData; 052 053 /** 054 * Creates a new In-Band Bytestream data packet. 055 * 056 * @param sessionID unique session ID identifying this In-Band Bytestream 057 * @param seq sequence of this stanza in regard to the other data packets 058 * @param data the base64 encoded data contained in this packet 059 */ 060 public DataPacketExtension(String sessionID, long seq, String data) { 061 if (sessionID == null || "".equals(sessionID)) { 062 throw new IllegalArgumentException("Session ID must not be null or empty"); 063 } 064 if (seq < 0 || seq > 65535) { 065 throw new IllegalArgumentException("Sequence must not be between 0 and 65535"); 066 } 067 if (data == null) { 068 throw new IllegalArgumentException("Data must not be null"); 069 } 070 this.sessionID = sessionID; 071 this.seq = seq; 072 this.data = data; 073 } 074 075 /** 076 * Returns the unique session ID identifying this In-Band Bytestream. 077 * 078 * @return the unique session ID identifying this In-Band Bytestream 079 */ 080 public String getSessionID() { 081 return sessionID; 082 } 083 084 /** 085 * Returns the sequence of this stanza in regard to the other data packets. 086 * 087 * @return the sequence of this stanza in regard to the other data packets. 088 */ 089 public long getSeq() { 090 return seq; 091 } 092 093 /** 094 * Returns the data contained in this packet. 095 * 096 * @return the data contained in this packet. 097 */ 098 public String getData() { 099 return data; 100 } 101 102 /** 103 * Returns the decoded data or null if data could not be decoded. 104 * <p> 105 * The encoded data is invalid if it contains bad Base64 input characters or 106 * if it contains the pad ('=') character on a position other than the last 107 * character(s) of the data. See <a 108 * href="http://xmpp.org/extensions/xep-0047.html#sec">XEP-0047</a> Section 109 * 6. 110 * 111 * @return the decoded data 112 */ 113 public byte[] getDecodedData() { 114 // return cached decoded data 115 if (this.decodedData != null) { 116 return this.decodedData; 117 } 118 119 // data must not contain the pad (=) other than end of data 120 if (data.matches(".*={1,2}+.+")) { 121 return null; 122 } 123 124 // decodeBase64 will return null if bad characters are included 125 this.decodedData = Base64.decode(data); 126 return this.decodedData; 127 } 128 129 @Override 130 public String getElementName() { 131 return ELEMENT; 132 } 133 134 @Override 135 public String getNamespace() { 136 return NAMESPACE; 137 } 138 139 @Override 140 public XmlStringBuilder toXML(String enclosingNamespace) { 141 XmlStringBuilder xml = getIQChildElementBuilder(new IQChildElementXmlStringBuilder(this)); 142 xml.closeElement(this); 143 return xml; 144 } 145 146 protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { 147 xml.attribute("seq", Long.toString(seq)); 148 xml.attribute("sid", sessionID); 149 xml.rightAngleBracket(); 150 xml.append(data); 151 return xml; 152 } 153}