- * - * This allows event-style programming -- every time a new packet is found, - * the {@link #interceptPacket(Packet)} method will be called. - * - * @see Connection#addPacketInterceptor(PacketInterceptor, org.jivesoftware.smack.filter.PacketFilter) - * @author Gaston Dombiak - */ -public interface PacketInterceptor { - - /** - * Process the packet that is about to be sent to the server. The intercepted - * packet can be modified by the interceptor.
- * - * Interceptors are invoked using the same thread that requested the packet - * to be sent, so it's very important that implementations of this method - * not block for any extended period of time. - * - * @param packet the packet to is going to be sent to the server. - */ - public void interceptPacket(Packet packet); -} +/** + * + * Copyright 2003-2005 Jive Software. + * + * 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.smack; + +import org.jivesoftware.smack.packet.Packet; + +/** + * Provides a mechanism to intercept and modify packets that are going to be + * sent to the server. PacketInterceptors are added to the {@link Connection} + * together with a {@link org.jivesoftware.smack.filter.PacketFilter} so that only + * certain packets are intercepted and processed by the interceptor.
+ * + * This allows event-style programming -- every time a new packet is found, + * the {@link #interceptPacket(Packet)} method will be called. + * + * @see Connection#addPacketInterceptor(PacketInterceptor, org.jivesoftware.smack.filter.PacketFilter) + * @author Gaston Dombiak + */ +public interface PacketInterceptor { + + /** + * Process the packet that is about to be sent to the server. The intercepted + * packet can be modified by the interceptor.
+ * + * Interceptors are invoked using the same thread that requested the packet + * to be sent, so it's very important that implementations of this method + * not block for any extended period of time. + * + * @param packet the packet to is going to be sent to the server. + */ + public void interceptPacket(Packet packet); +} diff --git a/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java b/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java index 00526994e..2c9599bf5 100644 --- a/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java +++ b/core/src/main/java/org/jivesoftware/smack/ReconnectionManager.java @@ -14,215 +14,215 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smack; - -import org.jivesoftware.smack.packet.StreamError; -import java.util.Random; +package org.jivesoftware.smack; + +import org.jivesoftware.smack.packet.StreamError; +import java.util.Random; import java.util.logging.Logger; -/** - * Handles the automatic reconnection process. Every time a connection is dropped without - * the application explictly closing it, the manager automatically tries to reconnect to - * the server.
- * - * The reconnection mechanism will try to reconnect periodically: - *
+ * + * The reconnection mechanism will try to reconnect periodically: + *
This class is responsible authenticating the user using SASL, binding the resource - * to the connection and establishing a session with the server.
- * - *Once TLS has been negotiated (i.e. the connection has been secured) it is possible to - * register with the server, authenticate using Non-SASL or authenticate using SASL. If the - * server supports SASL then Smack will first try to authenticate using SASL. But if that - * fails then Non-SASL will be tried.
- * - *The server may support many SASL mechanisms to use for authenticating. Out of the box - * Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use - * {@link #registerSASLMechanism(String, Class)} to register a new mechanisms. A registered - * mechanism wont be used until {@link #supportSASLMechanism(String, int)} is called. By default, - * the list of supported SASL mechanisms is determined from the {@link SmackConfiguration}.
- * - *Once the user has been authenticated with SASL, it is necessary to bind a resource for - * the connection. If no resource is passed in {@link #authenticate(String, String, String)} - * then the server will assign a resource for the connection. In case a resource is passed - * then the server will receive the desired resource but may assign a modified resource for - * the connection.
- * - *Once a resource has been binded and if the server supports sessions then Smack will establish - * a session so that instant messaging and presence functionalities may be used.
- * - * @see org.jivesoftware.smack.sasl.SASLMechanism - * - * @author Gaston Dombiak - * @author Jay Kline - */ -public class SASLAuthentication implements UserAuthentication { - - private static Map- * - * The server may assign a full JID with a username or resource different than the requested - * by this method. - * - * @param username the username that is authenticating with the server. - * @param resource the desired resource. - * @param cbh the CallbackHandler used to get information from the user - * @return the full JID provided by the server while binding a resource to the connection. - * @throws XMPPException if an error occures while authenticating. - */ - public String authenticate(String username, String resource, CallbackHandler cbh) - throws XMPPException { - // Locate the SASLMechanism to use - String selectedMechanism = null; - for (String mechanism : mechanismsPreferences) { - if (implementedMechanisms.containsKey(mechanism) && - serverMechanisms.contains(mechanism)) { - selectedMechanism = mechanism; - break; - } - } - if (selectedMechanism != null) { - // A SASL mechanism was found. Authenticate using the selected mechanism and then - // proceed to bind a resource - try { - Class extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism); - Constructor extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class); - currentMechanism = constructor.newInstance(this); - // Trigger SASL authentication with the selected mechanism. We use - // connection.getHost() since GSAPI requires the FQDN of the server, which - // may not match the XMPP domain. - currentMechanism.authenticate(username, connection.getHost(), cbh); - - // Wait until SASL negotiation finishes - synchronized (this) { - if (!saslNegotiated && !saslFailed) { - try { - wait(30000); - } - catch (InterruptedException e) { - // Ignore - } - } - } - - if (saslFailed) { - // SASL authentication failed and the server may have closed the connection - // so throw an exception - if (errorCondition != null) { - throw new XMPPException("SASL authentication " + - selectedMechanism + " failed: " + errorCondition); - } - else { - throw new XMPPException("SASL authentication failed using mechanism " + - selectedMechanism); - } - } - - if (saslNegotiated) { - // Bind a resource for this connection and - return bindResourceAndEstablishSession(resource); - } else { - // SASL authentication failed - } - } - catch (XMPPException e) { - throw e; - } - catch (Exception e) { - e.printStackTrace(); - } - } - else { - throw new XMPPException("SASL Authentication failed. No known authentication mechanisims."); - } - throw new XMPPException("SASL authentication failed"); - } - - /** - * Performs SASL authentication of the specified user. If SASL authentication was successful - * then resource binding and session establishment will be performed. This method will return - * the full JID provided by the server while binding a resource to the connection.
- * - * The server may assign a full JID with a username or resource different than the requested - * by this method. - * - * @param username the username that is authenticating with the server. - * @param password the password to send to the server. - * @param resource the desired resource. - * @return the full JID provided by the server while binding a resource to the connection. - * @throws XMPPException if an error occures while authenticating. - */ - public String authenticate(String username, String password, String resource) - throws XMPPException { - // Locate the SASLMechanism to use - String selectedMechanism = null; - for (String mechanism : mechanismsPreferences) { - if (implementedMechanisms.containsKey(mechanism) && - serverMechanisms.contains(mechanism)) { - selectedMechanism = mechanism; - break; - } - } - if (selectedMechanism != null) { - // A SASL mechanism was found. Authenticate using the selected mechanism and then - // proceed to bind a resource - try { - Class extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism); - Constructor extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class); - currentMechanism = constructor.newInstance(this); - // Trigger SASL authentication with the selected mechanism. We use - // connection.getHost() since GSAPI requires the FQDN of the server, which - // may not match the XMPP domain. - - //The serviceName is basically the value that XMPP server sends to the client as being the location - //of the XMPP service we are trying to connect to. This should have the format: host [ "/" serv-name ] - //as per RFC-2831 guidelines - String serviceName = connection.getServiceName(); - currentMechanism.authenticate(username, connection.getHost(), serviceName, password); - - // Wait until SASL negotiation finishes - synchronized (this) { - if (!saslNegotiated && !saslFailed) { - try { - wait(30000); - } - catch (InterruptedException e) { - // Ignore - } - } - } - - if (saslFailed) { - // SASL authentication failed and the server may have closed the connection - // so throw an exception - if (errorCondition != null) { - throw new XMPPException("SASL authentication " + - selectedMechanism + " failed: " + errorCondition); - } - else { - throw new XMPPException("SASL authentication failed using mechanism " + - selectedMechanism); - } - } - - if (saslNegotiated) { - // Bind a resource for this connection and - return bindResourceAndEstablishSession(resource); - } - else { - // SASL authentication failed so try a Non-SASL authentication - return new NonSASLAuthentication(connection) - .authenticate(username, password, resource); - } - } - catch (XMPPException e) { - throw e; - } - catch (Exception e) { - e.printStackTrace(); - // SASL authentication failed so try a Non-SASL authentication - return new NonSASLAuthentication(connection) - .authenticate(username, password, resource); - } - } - else { - // No SASL method was found so try a Non-SASL authentication - return new NonSASLAuthentication(connection).authenticate(username, password, resource); - } - } - - /** - * Performs ANONYMOUS SASL authentication. If SASL authentication was successful - * then resource binding and session establishment will be performed. This method will return - * the full JID provided by the server while binding a resource to the connection.
- *
- * The server will assign a full JID with a randomly generated resource and possibly with
- * no username.
- *
- * @return the full JID provided by the server while binding a resource to the connection.
- * @throws XMPPException if an error occures while authenticating.
- */
- public String authenticateAnonymously() throws XMPPException {
- try {
- currentMechanism = new SASLAnonymous(this);
- currentMechanism.authenticate(null,null,null,"");
-
- // Wait until SASL negotiation finishes
- synchronized (this) {
- if (!saslNegotiated && !saslFailed) {
- try {
- wait(5000);
- }
- catch (InterruptedException e) {
- // Ignore
- }
- }
- }
-
- if (saslFailed) {
- // SASL authentication failed and the server may have closed the connection
- // so throw an exception
- if (errorCondition != null) {
- throw new XMPPException("SASL authentication failed: " + errorCondition);
- }
- else {
- throw new XMPPException("SASL authentication failed");
- }
- }
-
- if (saslNegotiated) {
- // Bind a resource for this connection and
- return bindResourceAndEstablishSession(null);
- }
- else {
- return new NonSASLAuthentication(connection).authenticateAnonymously();
- }
- } catch (IOException e) {
- return new NonSASLAuthentication(connection).authenticateAnonymously();
- }
- }
-
- private String bindResourceAndEstablishSession(String resource) throws XMPPException {
- // Wait until server sends response containing the This class is responsible authenticating the user using SASL, binding the resource
+ * to the connection and establishing a session with the server. Once TLS has been negotiated (i.e. the connection has been secured) it is possible to
+ * register with the server, authenticate using Non-SASL or authenticate using SASL. If the
+ * server supports SASL then Smack will first try to authenticate using SASL. But if that
+ * fails then Non-SASL will be tried. The server may support many SASL mechanisms to use for authenticating. Out of the box
+ * Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use
+ * {@link #registerSASLMechanism(String, Class)} to register a new mechanisms. A registered
+ * mechanism wont be used until {@link #supportSASLMechanism(String, int)} is called. By default,
+ * the list of supported SASL mechanisms is determined from the {@link SmackConfiguration}. Once the user has been authenticated with SASL, it is necessary to bind a resource for
+ * the connection. If no resource is passed in {@link #authenticate(String, String, String)}
+ * then the server will assign a resource for the connection. In case a resource is passed
+ * then the server will receive the desired resource but may assign a modified resource for
+ * the connection. Once a resource has been binded and if the server supports sessions then Smack will establish
+ * a session so that instant messaging and presence functionalities may be used.
+ *
+ * The server may assign a full JID with a username or resource different than the requested
+ * by this method.
+ *
+ * @param username the username that is authenticating with the server.
+ * @param resource the desired resource.
+ * @param cbh the CallbackHandler used to get information from the user
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticate(String username, String resource, CallbackHandler cbh)
+ throws XMPPException {
+ // Locate the SASLMechanism to use
+ String selectedMechanism = null;
+ for (String mechanism : mechanismsPreferences) {
+ if (implementedMechanisms.containsKey(mechanism) &&
+ serverMechanisms.contains(mechanism)) {
+ selectedMechanism = mechanism;
+ break;
+ }
+ }
+ if (selectedMechanism != null) {
+ // A SASL mechanism was found. Authenticate using the selected mechanism and then
+ // proceed to bind a resource
+ try {
+ Class extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
+ Constructor extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
+ currentMechanism = constructor.newInstance(this);
+ // Trigger SASL authentication with the selected mechanism. We use
+ // connection.getHost() since GSAPI requires the FQDN of the server, which
+ // may not match the XMPP domain.
+ currentMechanism.authenticate(username, connection.getHost(), cbh);
+
+ // Wait until SASL negotiation finishes
+ synchronized (this) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(30000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication " +
+ selectedMechanism + " failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed using mechanism " +
+ selectedMechanism);
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(resource);
+ } else {
+ // SASL authentication failed
+ }
+ }
+ catch (XMPPException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ else {
+ throw new XMPPException("SASL Authentication failed. No known authentication mechanisims.");
+ }
+ throw new XMPPException("SASL authentication failed");
+ }
+
+ /**
+ * Performs SASL authentication of the specified user. If SASL authentication was successful
+ * then resource binding and session establishment will be performed. This method will return
+ * the full JID provided by the server while binding a resource to the connection.
+ *
+ * The server may assign a full JID with a username or resource different than the requested
+ * by this method.
+ *
+ * @param username the username that is authenticating with the server.
+ * @param password the password to send to the server.
+ * @param resource the desired resource.
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticate(String username, String password, String resource)
+ throws XMPPException {
+ // Locate the SASLMechanism to use
+ String selectedMechanism = null;
+ for (String mechanism : mechanismsPreferences) {
+ if (implementedMechanisms.containsKey(mechanism) &&
+ serverMechanisms.contains(mechanism)) {
+ selectedMechanism = mechanism;
+ break;
+ }
+ }
+ if (selectedMechanism != null) {
+ // A SASL mechanism was found. Authenticate using the selected mechanism and then
+ // proceed to bind a resource
+ try {
+ Class extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
+ Constructor extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
+ currentMechanism = constructor.newInstance(this);
+ // Trigger SASL authentication with the selected mechanism. We use
+ // connection.getHost() since GSAPI requires the FQDN of the server, which
+ // may not match the XMPP domain.
+
+ //The serviceName is basically the value that XMPP server sends to the client as being the location
+ //of the XMPP service we are trying to connect to. This should have the format: host [ "/" serv-name ]
+ //as per RFC-2831 guidelines
+ String serviceName = connection.getServiceName();
+ currentMechanism.authenticate(username, connection.getHost(), serviceName, password);
+
+ // Wait until SASL negotiation finishes
+ synchronized (this) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(30000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication " +
+ selectedMechanism + " failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed using mechanism " +
+ selectedMechanism);
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(resource);
+ }
+ else {
+ // SASL authentication failed so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection)
+ .authenticate(username, password, resource);
+ }
+ }
+ catch (XMPPException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ // SASL authentication failed so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection)
+ .authenticate(username, password, resource);
+ }
+ }
+ else {
+ // No SASL method was found so try a Non-SASL authentication
+ return new NonSASLAuthentication(connection).authenticate(username, password, resource);
+ }
+ }
+
+ /**
+ * Performs ANONYMOUS SASL authentication. If SASL authentication was successful
+ * then resource binding and session establishment will be performed. This method will return
+ * the full JID provided by the server while binding a resource to the connection.
+ *
+ * The server will assign a full JID with a randomly generated resource and possibly with
+ * no username.
+ *
+ * @return the full JID provided by the server while binding a resource to the connection.
+ * @throws XMPPException if an error occures while authenticating.
+ */
+ public String authenticateAnonymously() throws XMPPException {
+ try {
+ currentMechanism = new SASLAnonymous(this);
+ currentMechanism.authenticate(null,null,null,"");
+
+ // Wait until SASL negotiation finishes
+ synchronized (this) {
+ if (!saslNegotiated && !saslFailed) {
+ try {
+ wait(5000);
+ }
+ catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (saslFailed) {
+ // SASL authentication failed and the server may have closed the connection
+ // so throw an exception
+ if (errorCondition != null) {
+ throw new XMPPException("SASL authentication failed: " + errorCondition);
+ }
+ else {
+ throw new XMPPException("SASL authentication failed");
+ }
+ }
+
+ if (saslNegotiated) {
+ // Bind a resource for this connection and
+ return bindResourceAndEstablishSession(null);
+ }
+ else {
+ return new NonSASLAuthentication(connection).authenticateAnonymously();
+ }
+ } catch (IOException e) {
+ return new NonSASLAuthentication(connection).authenticateAnonymously();
+ }
+ }
+
+ private String bindResourceAndEstablishSession(String resource) throws XMPPException {
+ // Wait until server sends response containing the
- * Any implementation of this class MUST have a default constructor.
- *
- * @author Robin Collier
- *
- */
-public interface SmackInitializer {
- void initialize();
- List
+ * Any implementation of this class MUST have a default constructor.
+ *
+ * @author Robin Collier
+ *
+ */
+public interface SmackInitializer {
+ void initialize();
+ List
- *
- * For more information refer to the following
- * link.
- *
- * @author Gaston Dombiak
- */
-public class Bind extends IQ {
-
- private String resource = null;
- private String jid = null;
-
- public Bind() {
- setType(IQ.Type.SET);
- }
-
- public String getResource() {
- return resource;
- }
-
- public void setResource(String resource) {
- this.resource = resource;
- }
-
- public String getJid() {
- return jid;
- }
-
- public void setJid(String jid) {
- this.jid = jid;
- }
-
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("
+ *
+ * For more information refer to the following
+ * link.
+ *
+ * @author Gaston Dombiak
+ */
+public class Bind extends IQ {
+
+ private String resource = null;
+ private String jid = null;
+
+ public Bind() {
+ setType(IQ.Type.SET);
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ public void setResource(String resource) {
+ this.resource = resource;
+ }
+
+ public String getJid() {
+ return jid;
+ }
+
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("
- *
- * If a server supports sessions, it MUST include a session element in the
- * stream features it advertises to a client after the completion of stream authentication.
- * Upon being informed that session establishment is required by the server the client MUST
- * establish a session if it desires to engage in instant messaging and presence functionality.
- *
- * For more information refer to the following
- * link.
- *
- * @author Gaston Dombiak
- */
-public class Session extends IQ {
-
- public Session() {
- setType(IQ.Type.SET);
- }
-
- public String getChildElementXML() {
- return "
+ *
+ * If a server supports sessions, it MUST include a session element in the
+ * stream features it advertises to a client after the completion of stream authentication.
+ * Upon being informed that session establishment is required by the server the client MUST
+ * establish a session if it desires to engage in instant messaging and presence functionality.
+ *
+ * For more information refer to the following
+ * link.
+ *
+ * @author Gaston Dombiak
+ */
+public class Session extends IQ {
+
+ public Session() {
+ setType(IQ.Type.SET);
+ }
+
+ public String getChildElementXML() {
+ return "
- *
- *
+ *
+ * To use this class, you simply register your subclasses as extension providers in the
- * smack.properties file. Then they will be automatically picked up and used to parse
- * any child elements.
- *
- * To use this class, you simply register your subclasses as extension providers in the
+ * smack.properties file. Then they will be automatically picked up and used to parse
+ * any child elements.
+ *
+ *
- * Kept for backward compatibility only.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param password the password for this account.
- * @throws IOException If a network error occurs while authenticating.
- * @throws XMPPException If a protocol error occurs or the user is not authenticated.
- * @deprecated Please use {@link #authenticate(String, String, String, String)} instead.
- */
- public void authenticate(String username, String host, String password) throws IOException, XMPPException {
- authenticate(username, host, host, password);
- }
-
- /**
- * Builds and sends the auth stanza to the server. The callback handler will handle
- * any additional information, such as the authentication ID or realm, if it is needed.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param cbh the CallbackHandler to obtain user information.
- * @throws IOException If a network error occures while authenticating.
- * @throws XMPPException If a protocol error occurs or the user is not authenticated.
- */
- public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
- String[] mechanisms = { getName() };
- Map
+ * Kept for backward compatibility only.
+ *
+ * @param username the username of the user being authenticated.
+ * @param host the hostname where the user account resides.
+ * @param password the password for this account.
+ * @throws IOException If a network error occurs while authenticating.
+ * @throws XMPPException If a protocol error occurs or the user is not authenticated.
+ * @deprecated Please use {@link #authenticate(String, String, String, String)} instead.
+ */
+ public void authenticate(String username, String host, String password) throws IOException, XMPPException {
+ authenticate(username, host, host, password);
+ }
+
+ /**
+ * Builds and sends the auth stanza to the server. The callback handler will handle
+ * any additional information, such as the authentication ID or realm, if it is needed.
+ *
+ * @param username the username of the user being authenticated.
+ * @param host the hostname where the user account resides.
+ * @param cbh the CallbackHandler to obtain user information.
+ * @throws IOException If a network error occures while authenticating.
+ * @throws XMPPException If a protocol error occurs or the user is not authenticated.
+ */
+ public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
+ String[] mechanisms = { getName() };
+ Map Encodes and decodes to and from Base64 notation. Encodes up to three bytes of the array source
- * and writes the resulting four Base64 bytes to destination.
- * The source and destination arrays can be manipulated
- * anywhere along their length by specifying
- * srcOffset and destOffset.
- * This method does not check to make sure your arrays
- * are large enough to accomodate srcOffset + 3 for
- * the source array or destOffset + 4 for
- * the destination array.
- * The actual number of significant bytes in your array is
- * given by numSigBytes. This is the lowest level of the encoding methods with
- * all possible parameters.
- * Valid options:
- * Example:
- * Example:
- * Valid options:
- * Example:
- * Example:
- * Valid options:
- * Example:
- * Example: Encodes and decodes to and from Base64 notation. Encodes up to three bytes of the array source
+ * and writes the resulting four Base64 bytes to destination.
+ * The source and destination arrays can be manipulated
+ * anywhere along their length by specifying
+ * srcOffset and destOffset.
+ * This method does not check to make sure your arrays
+ * are large enough to accomodate srcOffset + 3 for
+ * the source array or destOffset + 4 for
+ * the destination array.
+ * The actual number of significant bytes in your array is
+ * given by numSigBytes. This is the lowest level of the encoding methods with
+ * all possible parameters.
+ * Valid options:
+ * Example:
+ * Example:
+ * Valid options:
+ * Example:
+ * Example:
+ * Valid options:
+ * Example:
+ * Example: This is the lowest level of the decoding methods with
- * all possible parameters. This is the lowest level of the decoding methods with
+ * all possible parameters.
- * Valid options:
- * Example:
+ * Valid options:
+ * Example:
- * Valid options:
- * Example:
+ * Valid options:
+ * Example:
- * It accomplishes this by wrapping a {@link Forwarded} packet in a sent
- * or received element
- *
- * @author Georg Lukas
- */
-public class CarbonExtension implements PacketExtension {
- public static final String NAMESPACE = "urn:xmpp:carbons:2";
-
- private Direction dir;
- private Forwarded fwd;
-
- /**
- * Construct a Carbon message extension.
- *
- * @param dir Determines if the carbon is being sent/received
- * @param fwd The forwarded message.
- */
- public CarbonExtension(Direction dir, Forwarded fwd) {
- this.dir = dir;
- this.fwd = fwd;
- }
-
- /**
- * Get the direction (sent or received) of the carbon.
- *
- * @return the {@link Direction} of the carbon.
- */
- public Direction getDirection() {
- return dir;
- }
-
- /**
- * Get the forwarded packet.
- *
- * @return the {@link Forwarded} message contained in this Carbon.
- */
- public Forwarded getForwarded() {
- return fwd;
- }
-
- @Override
- public String getElementName() {
- return dir.toString();
- }
-
- @Override
- public String getNamespace() {
- return NAMESPACE;
- }
-
- @Override
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<").append(getElementName()).append(" xmlns=\"")
- .append(getNamespace()).append("\">");
-
- buf.append(fwd.toXML());
-
- buf.append("").append(getElementName()).append(">");
- return buf.toString();
- }
-
- /**
- * Defines the direction of a {@link CarbonExtension} message.
- */
- public static enum Direction {
- received,
- sent
- }
-
- /**
- * Packet extension indicating that a message may not be carbon-copied. Adding this
- * extension to any message will disallow that message from being copied.
- */
- public static class Private implements PacketExtension {
- public static final String ELEMENT = "private";
-
- public String getElementName() {
- return ELEMENT;
- }
-
- public String getNamespace() {
- return CarbonExtension.NAMESPACE;
- }
-
- public String toXML() {
- return "<" + ELEMENT + " xmlns=\"" + CarbonExtension.NAMESPACE + "\"/>";
- }
- }
-}
+/**
+ *
+ * Copyright 2013 Georg Lukas
+ *
+ * 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.carbons.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smackx.forward.Forwarded;
+
+/**
+ * Packet extension for XEP-0280: Message Carbons. The extension
+ * XEP-0280 is
+ * meant to synchronize a message flow to multiple presences of a user.
+ *
+ *
+ * It accomplishes this by wrapping a {@link Forwarded} packet in a sent
+ * or received element
+ *
+ * @author Georg Lukas
+ */
+public class CarbonExtension implements PacketExtension {
+ public static final String NAMESPACE = "urn:xmpp:carbons:2";
+
+ private Direction dir;
+ private Forwarded fwd;
+
+ /**
+ * Construct a Carbon message extension.
+ *
+ * @param dir Determines if the carbon is being sent/received
+ * @param fwd The forwarded message.
+ */
+ public CarbonExtension(Direction dir, Forwarded fwd) {
+ this.dir = dir;
+ this.fwd = fwd;
+ }
+
+ /**
+ * Get the direction (sent or received) of the carbon.
+ *
+ * @return the {@link Direction} of the carbon.
+ */
+ public Direction getDirection() {
+ return dir;
+ }
+
+ /**
+ * Get the forwarded packet.
+ *
+ * @return the {@link Forwarded} message contained in this Carbon.
+ */
+ public Forwarded getForwarded() {
+ return fwd;
+ }
+
+ @Override
+ public String getElementName() {
+ return dir.toString();
+ }
+
+ @Override
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ @Override
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(" xmlns=\"")
+ .append(getNamespace()).append("\">");
+
+ buf.append(fwd.toXML());
+
+ buf.append("").append(getElementName()).append(">");
+ return buf.toString();
+ }
+
+ /**
+ * Defines the direction of a {@link CarbonExtension} message.
+ */
+ public static enum Direction {
+ received,
+ sent
+ }
+
+ /**
+ * Packet extension indicating that a message may not be carbon-copied. Adding this
+ * extension to any message will disallow that message from being copied.
+ */
+ public static class Private implements PacketExtension {
+ public static final String ELEMENT = "private";
+
+ public String getElementName() {
+ return ELEMENT;
+ }
+
+ public String getNamespace() {
+ return CarbonExtension.NAMESPACE;
+ }
+
+ public String toXML() {
+ return "<" + ELEMENT + " xmlns=\"" + CarbonExtension.NAMESPACE + "\"/>";
+ }
+ }
+}
diff --git a/experimental/src/main/java/org/jivesoftware/smackx/carbons/provider/CarbonManagerProvider.java b/experimental/src/main/java/org/jivesoftware/smackx/carbons/provider/CarbonManagerProvider.java
index 128a61343..dace0e6dc 100644
--- a/experimental/src/main/java/org/jivesoftware/smackx/carbons/provider/CarbonManagerProvider.java
+++ b/experimental/src/main/java/org/jivesoftware/smackx/carbons/provider/CarbonManagerProvider.java
@@ -1,53 +1,53 @@
-/**
- *
- * Copyright 2013 Georg Lukas
- *
- * 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.carbons.provider;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
-import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Direction;
-import org.jivesoftware.smackx.forward.Forwarded;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * This class implements the {@link PacketExtensionProvider} to parse
- * cabon copied messages from a packet. It will return a {@link CarbonExtension} packet extension.
- *
- * @author Georg Lukas
- *
- */
-public class CarbonManagerProvider implements PacketExtensionProvider {
-
- public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
- Direction dir = Direction.valueOf(parser.getName());
- Forwarded fwd = null;
-
- boolean done = false;
- while (!done) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getName().equals("forwarded")) {
- fwd = (Forwarded) PacketParserUtils.parsePacketExtension(Forwarded.ELEMENT_NAME, Forwarded.NAMESPACE, parser);
- }
- else if (eventType == XmlPullParser.END_TAG && dir == Direction.valueOf(parser.getName()))
- done = true;
- }
- if (fwd == null)
- throw new Exception("sent/received must contain exactly one
- * BytestreamListener can be registered at the {@link Socks5BytestreamManager} or the
- * {@link InBandBytestreamManager}.
- *
- * There are two ways to add this listener. See
- * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for further
- * details.
- *
- * {@link Socks5BytestreamListener} or {@link InBandBytestreamListener} provide a more specific
- * interface of the BytestreamListener.
- *
- * @author Henning Staib
- */
-public interface BytestreamListener {
-
- /**
- * This listener is notified if a bytestream request from another user has been received.
- *
- * @param request the incoming bytestream request
- */
- public void incomingBytestreamRequest(BytestreamRequest request);
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams;
+
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+
+/**
+ * BytestreamListener are notified if a remote user wants to initiate a bytestream. Implement this
+ * interface to handle incoming bytestream requests.
+ *
+ * BytestreamListener can be registered at the {@link Socks5BytestreamManager} or the
+ * {@link InBandBytestreamManager}.
+ *
+ * There are two ways to add this listener. See
+ * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for further
+ * details.
+ *
+ * {@link Socks5BytestreamListener} or {@link InBandBytestreamListener} provide a more specific
+ * interface of the BytestreamListener.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamListener {
+
+ /**
+ * This listener is notified if a bytestream request from another user has been received.
+ *
+ * @param request the incoming bytestream request
+ */
+ public void incomingBytestreamRequest(BytestreamRequest request);
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamManager.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
index 8fc14f731..15a979c0d 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamManager.java
@@ -1,117 +1,117 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams;
-
-import java.io.IOException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
-
-/**
- * BytestreamManager provides a generic interface for bytestream managers.
- *
- * There are two implementations of the interface. See {@link Socks5BytestreamManager} and
- * {@link InBandBytestreamManager}.
- *
- * @author Henning Staib
- */
-public interface BytestreamManager {
-
- /**
- * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
- * there is a user specific {@link BytestreamListener} registered.
- *
- * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} for further
- * details.
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener);
-
- /**
- * Removes the given listener from the list of listeners for all incoming bytestream requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener);
-
- /**
- * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
- * there is a user specific {@link BytestreamListener} registered.
- *
- * Use this method if you are awaiting an incoming bytestream request from a specific user.
- *
- * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
- * and {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
- * for further details.
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish a bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID);
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID);
-
- /**
- * Establishes a bytestream with the given user and returns the session to send/receive data
- * to/from the user.
- *
- * Use this method to establish bytestreams to users accepting all incoming bytestream requests
- * since this method doesn't provide a way to tell the user something about the data to be sent.
- *
- * To establish a bytestream after negotiation the kind of data to be sent (e.g. file transfer)
- * use {@link #establishSession(String, String)}.
- *
- * See {@link Socks5BytestreamManager#establishSession(String)} and
- * {@link InBandBytestreamManager#establishSession(String)} for further details.
- *
- * @param targetJID the JID of the user a bytestream should be established
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if an error occurred while establishing the session
- * @throws IOException if an IO error occurred while establishing the session
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession establishSession(String targetJID) throws XMPPException, IOException,
- InterruptedException;
-
- /**
- * Establishes a bytestream with the given user and returns the session to send/receive data
- * to/from the user.
- *
- * See {@link Socks5BytestreamManager#establishSession(String)} and
- * {@link InBandBytestreamManager#establishSession(String)} for further details.
- *
- * @param targetJID the JID of the user a bytestream should be established
- * @param sessionID the session ID for the bytestream request
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if an error occurred while establishing the session
- * @throws IOException if an IO error occurred while establishing the session
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException, IOException, InterruptedException;
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams;
+
+import java.io.IOException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
+
+/**
+ * BytestreamManager provides a generic interface for bytestream managers.
+ *
+ * There are two implementations of the interface. See {@link Socks5BytestreamManager} and
+ * {@link InBandBytestreamManager}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamManager {
+
+ /**
+ * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
+ * there is a user specific {@link BytestreamListener} registered.
+ *
+ * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} for further
+ * details.
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener);
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming bytestream requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener);
+
+ /**
+ * Adds {@link BytestreamListener} that is called for every incoming bytestream request unless
+ * there is a user specific {@link BytestreamListener} registered.
+ *
+ * Use this method if you are awaiting an incoming bytestream request from a specific user.
+ *
+ * See {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
+ * and {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)}
+ * for further details.
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish a bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID);
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID);
+
+ /**
+ * Establishes a bytestream with the given user and returns the session to send/receive data
+ * to/from the user.
+ *
+ * Use this method to establish bytestreams to users accepting all incoming bytestream requests
+ * since this method doesn't provide a way to tell the user something about the data to be sent.
+ *
+ * To establish a bytestream after negotiation the kind of data to be sent (e.g. file transfer)
+ * use {@link #establishSession(String, String)}.
+ *
+ * See {@link Socks5BytestreamManager#establishSession(String)} and
+ * {@link InBandBytestreamManager#establishSession(String)} for further details.
+ *
+ * @param targetJID the JID of the user a bytestream should be established
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if an error occurred while establishing the session
+ * @throws IOException if an IO error occurred while establishing the session
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession establishSession(String targetJID) throws XMPPException, IOException,
+ InterruptedException;
+
+ /**
+ * Establishes a bytestream with the given user and returns the session to send/receive data
+ * to/from the user.
+ *
+ * See {@link Socks5BytestreamManager#establishSession(String)} and
+ * {@link InBandBytestreamManager#establishSession(String)} for further details.
+ *
+ * @param targetJID the JID of the user a bytestream should be established
+ * @param sessionID the session ID for the bytestream request
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if an error occurred while establishing the session
+ * @throws IOException if an IO error occurred while establishing the session
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException, IOException, InterruptedException;
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
index 381e356fc..94f9280a3 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamRequest.java
@@ -1,62 +1,62 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
-
-/**
- * BytestreamRequest provides an interface to handle incoming bytestream requests.
- *
- * There are two implementations of the interface. See {@link Socks5BytestreamRequest} and
- * {@link InBandBytestreamRequest}.
- *
- * @author Henning Staib
- */
-public interface BytestreamRequest {
-
- /**
- * Returns the sender of the bytestream open request.
- *
- * @return the sender of the bytestream open request
- */
- public String getFrom();
-
- /**
- * Returns the session ID of the bytestream open request.
- *
- * @return the session ID of the bytestream open request
- */
- public String getSessionID();
-
- /**
- * Accepts the bytestream open request and returns the session to send/receive data.
- *
- * @return the session to send/receive data
- * @throws XMPPException if an error occurred while accepting the bytestream request
- * @throws InterruptedException if the thread was interrupted while waiting in a blocking
- * operation
- */
- public BytestreamSession accept() throws XMPPException, InterruptedException;
-
- /**
- * Rejects the bytestream request by sending a reject error to the initiator.
- */
- public void reject();
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
+
+/**
+ * BytestreamRequest provides an interface to handle incoming bytestream requests.
+ *
+ * There are two implementations of the interface. See {@link Socks5BytestreamRequest} and
+ * {@link InBandBytestreamRequest}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamRequest {
+
+ /**
+ * Returns the sender of the bytestream open request.
+ *
+ * @return the sender of the bytestream open request
+ */
+ public String getFrom();
+
+ /**
+ * Returns the session ID of the bytestream open request.
+ *
+ * @return the session ID of the bytestream open request
+ */
+ public String getSessionID();
+
+ /**
+ * Accepts the bytestream open request and returns the session to send/receive data.
+ *
+ * @return the session to send/receive data
+ * @throws XMPPException if an error occurred while accepting the bytestream request
+ * @throws InterruptedException if the thread was interrupted while waiting in a blocking
+ * operation
+ */
+ public BytestreamSession accept() throws XMPPException, InterruptedException;
+
+ /**
+ * Rejects the bytestream request by sending a reject error to the initiator.
+ */
+ public void reject();
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamSession.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
index 799190415..4e57d257d 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/BytestreamSession.java
@@ -1,84 +1,84 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
-import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
-
-/**
- * BytestreamSession provides an interface for established bytestream sessions.
- *
- * There are two implementations of the interface. See {@link Socks5BytestreamSession} and
- * {@link InBandBytestreamSession}.
- *
- * @author Henning Staib
- */
-public interface BytestreamSession {
-
- /**
- * Returns the InputStream associated with this session to send data.
- *
- * @return the InputStream associated with this session to send data
- * @throws IOException if an error occurs while retrieving the input stream
- */
- public InputStream getInputStream() throws IOException;
-
- /**
- * Returns the OutputStream associated with this session to receive data.
- *
- * @return the OutputStream associated with this session to receive data
- * @throws IOException if an error occurs while retrieving the output stream
- */
- public OutputStream getOutputStream() throws IOException;
-
- /**
- * Closes the bytestream session.
- *
- * Closing the session will also close the input stream and the output stream associated to this
- * session.
- *
- * @throws IOException if an error occurs while closing the session
- */
- public void close() throws IOException;
-
- /**
- * Returns the timeout for read operations of the input stream associated with this session. 0
- * returns implies that the option is disabled (i.e., timeout of infinity). Default is 0.
- *
- * @return the timeout for read operations
- * @throws IOException if there is an error in the underlying protocol
- */
- public int getReadTimeout() throws IOException;
-
- /**
- * Sets the specified timeout, in milliseconds. With this option set to a non-zero timeout, a
- * read() call on the input stream associated with this session will block for only this amount
- * of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the
- * session is still valid. The option must be enabled prior to entering the blocking operation
- * to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite
- * timeout. Default is 0.
- *
- * @param timeout the specified timeout, in milliseconds
- * @throws IOException if there is an error in the underlying protocol
- */
- public void setReadTimeout(int timeout) throws IOException;
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
+import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
+
+/**
+ * BytestreamSession provides an interface for established bytestream sessions.
+ *
+ * There are two implementations of the interface. See {@link Socks5BytestreamSession} and
+ * {@link InBandBytestreamSession}.
+ *
+ * @author Henning Staib
+ */
+public interface BytestreamSession {
+
+ /**
+ * Returns the InputStream associated with this session to send data.
+ *
+ * @return the InputStream associated with this session to send data
+ * @throws IOException if an error occurs while retrieving the input stream
+ */
+ public InputStream getInputStream() throws IOException;
+
+ /**
+ * Returns the OutputStream associated with this session to receive data.
+ *
+ * @return the OutputStream associated with this session to receive data
+ * @throws IOException if an error occurs while retrieving the output stream
+ */
+ public OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Closes the bytestream session.
+ *
+ * Closing the session will also close the input stream and the output stream associated to this
+ * session.
+ *
+ * @throws IOException if an error occurs while closing the session
+ */
+ public void close() throws IOException;
+
+ /**
+ * Returns the timeout for read operations of the input stream associated with this session. 0
+ * returns implies that the option is disabled (i.e., timeout of infinity). Default is 0.
+ *
+ * @return the timeout for read operations
+ * @throws IOException if there is an error in the underlying protocol
+ */
+ public int getReadTimeout() throws IOException;
+
+ /**
+ * Sets the specified timeout, in milliseconds. With this option set to a non-zero timeout, a
+ * read() call on the input stream associated with this session will block for only this amount
+ * of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the
+ * session is still valid. The option must be enabled prior to entering the blocking operation
+ * to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite
+ * timeout. Default is 0.
+ *
+ * @param timeout the specified timeout, in milliseconds
+ * @throws IOException if there is an error in the underlying protocol
+ */
+ public void setReadTimeout(int timeout) throws IOException;
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
index eebb66482..395e61dba 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/CloseListener.java
@@ -1,78 +1,78 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
-
-/**
- * CloseListener handles all In-Band Bytestream close requests.
- *
- * If a close request is received it looks if a stored In-Band Bytestream
- * session exists and closes it. If no session with the given session ID exists
- * an <item-not-found/> error is returned to the sender.
- *
- * @author Henning Staib
- */
-class CloseListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream close requests */
- private final PacketFilter closeFilter = new AndFilter(new PacketTypeFilter(
- Close.class), new IQTypeFilter(IQ.Type.SET));
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- protected CloseListener(InBandBytestreamManager manager) {
- this.manager = manager;
- }
-
- public void processPacket(Packet packet) {
- Close closeRequest = (Close) packet;
- InBandBytestreamSession ibbSession = this.manager.getSessions().get(
- closeRequest.getSessionID());
- if (ibbSession == null) {
- this.manager.replyItemNotFoundPacket(closeRequest);
- }
- else {
- ibbSession.closeByPeer(closeRequest);
- this.manager.getSessions().remove(closeRequest.getSessionID());
- }
-
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream close requests.
- *
- * @return the packet filter for In-Band Bytestream close requests
- */
- protected PacketFilter getFilter() {
- return this.closeFilter;
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
+
+/**
+ * CloseListener handles all In-Band Bytestream close requests.
+ *
+ * If a close request is received it looks if a stored In-Band Bytestream
+ * session exists and closes it. If no session with the given session ID exists
+ * an <item-not-found/> error is returned to the sender.
+ *
+ * @author Henning Staib
+ */
+class CloseListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream close requests */
+ private final PacketFilter closeFilter = new AndFilter(new PacketTypeFilter(
+ Close.class), new IQTypeFilter(IQ.Type.SET));
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ protected CloseListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ }
+
+ public void processPacket(Packet packet) {
+ Close closeRequest = (Close) packet;
+ InBandBytestreamSession ibbSession = this.manager.getSessions().get(
+ closeRequest.getSessionID());
+ if (ibbSession == null) {
+ this.manager.replyItemNotFoundPacket(closeRequest);
+ }
+ else {
+ ibbSession.closeByPeer(closeRequest);
+ this.manager.getSessions().remove(closeRequest.getSessionID());
+ }
+
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream close requests.
+ *
+ * @return the packet filter for In-Band Bytestream close requests
+ */
+ protected PacketFilter getFilter() {
+ return this.closeFilter;
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
index c45813fbd..6b694d1ee 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/DataListener.java
@@ -1,76 +1,76 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
-
-/**
- * DataListener handles all In-Band Bytestream IQ stanzas containing a data
- * packet extension that don't belong to an existing session.
- *
- * If a data packet is received it looks if a stored In-Band Bytestream session
- * exists. If no session with the given session ID exists an
- * <item-not-found/> error is returned to the sender.
- *
- * Data packets belonging to a running In-Band Bytestream session are processed
- * by more specific listeners registered when an {@link InBandBytestreamSession}
- * is created.
- *
- * @author Henning Staib
- */
-class DataListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream data packets */
- private final PacketFilter dataFilter = new AndFilter(
- new PacketTypeFilter(Data.class));
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- public DataListener(InBandBytestreamManager manager) {
- this.manager = manager;
- }
-
- public void processPacket(Packet packet) {
- Data data = (Data) packet;
- InBandBytestreamSession ibbSession = this.manager.getSessions().get(
- data.getDataPacketExtension().getSessionID());
- if (ibbSession == null) {
- this.manager.replyItemNotFoundPacket(data);
- }
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream data packets.
- *
- * @return the packet filter for In-Band Bytestream data packets
- */
- protected PacketFilter getFilter() {
- return this.dataFilter;
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
+
+/**
+ * DataListener handles all In-Band Bytestream IQ stanzas containing a data
+ * packet extension that don't belong to an existing session.
+ *
+ * If a data packet is received it looks if a stored In-Band Bytestream session
+ * exists. If no session with the given session ID exists an
+ * <item-not-found/> error is returned to the sender.
+ *
+ * Data packets belonging to a running In-Band Bytestream session are processed
+ * by more specific listeners registered when an {@link InBandBytestreamSession}
+ * is created.
+ *
+ * @author Henning Staib
+ */
+class DataListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream data packets */
+ private final PacketFilter dataFilter = new AndFilter(
+ new PacketTypeFilter(Data.class));
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ public DataListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ }
+
+ public void processPacket(Packet packet) {
+ Data data = (Data) packet;
+ InBandBytestreamSession ibbSession = this.manager.getSessions().get(
+ data.getDataPacketExtension().getSessionID());
+ if (ibbSession == null) {
+ this.manager.replyItemNotFoundPacket(data);
+ }
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream data packets.
+ *
+ * @return the packet filter for In-Band Bytestream data packets
+ */
+ protected PacketFilter getFilter() {
+ return this.dataFilter;
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
index 65006c839..c810e41bd 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamListener.java
@@ -1,49 +1,49 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb;
-
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
-
-/**
- * InBandBytestreamListener are informed if a remote user wants to initiate an In-Band Bytestream.
- * Implement this interface to handle incoming In-Band Bytestream requests.
- *
- * There are two ways to add this listener. See
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
- * further details.
- *
- * @author Henning Staib
- */
-public abstract class InBandBytestreamListener implements BytestreamListener {
-
-
-
- public void incomingBytestreamRequest(BytestreamRequest request) {
- incomingBytestreamRequest((InBandBytestreamRequest) request);
- }
-
- /**
- * This listener is notified if an In-Band Bytestream request from another user has been
- * received.
- *
- * @param request the incoming In-Band Bytestream request
- */
- public abstract void incomingBytestreamRequest(InBandBytestreamRequest request);
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+
+/**
+ * InBandBytestreamListener are informed if a remote user wants to initiate an In-Band Bytestream.
+ * Implement this interface to handle incoming In-Band Bytestream requests.
+ *
+ * There are two ways to add this listener. See
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link InBandBytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
+ * further details.
+ *
+ * @author Henning Staib
+ */
+public abstract class InBandBytestreamListener implements BytestreamListener {
+
+
+
+ public void incomingBytestreamRequest(BytestreamRequest request) {
+ incomingBytestreamRequest((InBandBytestreamRequest) request);
+ }
+
+ /**
+ * This listener is notified if an In-Band Bytestream request from another user has been
+ * received.
+ *
+ * @param request the incoming In-Band Bytestream request
+ */
+ public abstract void incomingBytestreamRequest(InBandBytestreamRequest request);
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
index a9a04b875..21bca28d2 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java
@@ -1,561 +1,561 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.jivesoftware.smack.AbstractConnectionListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.ConnectionCreationListener;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamManager;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-import org.jivesoftware.smackx.filetransfer.FileTransferManager;
-
-/**
- * The InBandBytestreamManager class handles establishing In-Band Bytestreams as specified in the XEP-0047.
- *
- * The In-Band Bytestreams (IBB) enables two entities to establish a virtual bytestream over which
- * they can exchange Base64-encoded chunks of data over XMPP itself. It is the fall-back mechanism
- * in case the Socks5 bytestream method of transferring data is not available.
- *
- * There are two ways to send data over an In-Band Bytestream. It could either use IQ stanzas to
- * send data packets or message stanzas. If IQ stanzas are used every data packet is acknowledged by
- * the receiver. This is the recommended way to avoid possible rate-limiting penalties. Message
- * stanzas are not acknowledged because most XMPP server implementation don't support stanza
- * flow-control method like Advanced Message
- * Processing. To set the stanza that should be used invoke {@link #setStanza(StanzaType)}.
- *
- * To establish an In-Band Bytestream invoke the {@link #establishSession(String)} method. This will
- * negotiate an in-band bytestream with the given target JID and return a session.
- *
- * If a session ID for the In-Band Bytestream was already negotiated (e.g. while negotiating a file
- * transfer) invoke {@link #establishSession(String, String)}.
- *
- * To handle incoming In-Band Bytestream requests add an {@link InBandBytestreamListener} to the
- * manager. There are two ways to add this listener. If you want to be informed about incoming
- * In-Band Bytestreams from a specific user add the listener by invoking
- * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
- * respond to all In-Band Bytestream requests invoke
- * {@link #addIncomingBytestreamListener(BytestreamListener)}.
- *
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * In-Band bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * If no {@link InBandBytestreamListener}s are registered, all incoming In-Band bytestream requests
- * will be rejected by returning a <not-acceptable/> error to the initiator.
- *
- * @author Henning Staib
- */
-public class InBandBytestreamManager implements BytestreamManager {
-
- /**
- * Stanzas that can be used to encapsulate In-Band Bytestream data packets.
- */
- public enum StanzaType {
-
- /**
- * IQ stanza.
- */
- IQ,
-
- /**
- * Message stanza.
- */
- MESSAGE
- }
-
- /*
- * create a new InBandBytestreamManager and register its shutdown listener on every established
- * connection
- */
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
- public void connectionCreated(final Connection connection) {
- // create the manager for this connection
- InBandBytestreamManager.getByteStreamManager(connection);
-
- // register shutdown listener
- connection.addConnectionListener(new AbstractConnectionListener() {
-
- @Override
- public void connectionClosed() {
- InBandBytestreamManager.getByteStreamManager(connection).disableService();
- }
-
- @Override
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jivesoftware.smack.AbstractConnectionListener;
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.ConnectionCreationListener;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamManager;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+import org.jivesoftware.smackx.filetransfer.FileTransferManager;
+
+/**
+ * The InBandBytestreamManager class handles establishing In-Band Bytestreams as specified in the XEP-0047.
+ *
+ * The In-Band Bytestreams (IBB) enables two entities to establish a virtual bytestream over which
+ * they can exchange Base64-encoded chunks of data over XMPP itself. It is the fall-back mechanism
+ * in case the Socks5 bytestream method of transferring data is not available.
+ *
+ * There are two ways to send data over an In-Band Bytestream. It could either use IQ stanzas to
+ * send data packets or message stanzas. If IQ stanzas are used every data packet is acknowledged by
+ * the receiver. This is the recommended way to avoid possible rate-limiting penalties. Message
+ * stanzas are not acknowledged because most XMPP server implementation don't support stanza
+ * flow-control method like Advanced Message
+ * Processing. To set the stanza that should be used invoke {@link #setStanza(StanzaType)}.
+ *
+ * To establish an In-Band Bytestream invoke the {@link #establishSession(String)} method. This will
+ * negotiate an in-band bytestream with the given target JID and return a session.
+ *
+ * If a session ID for the In-Band Bytestream was already negotiated (e.g. while negotiating a file
+ * transfer) invoke {@link #establishSession(String, String)}.
+ *
+ * To handle incoming In-Band Bytestream requests add an {@link InBandBytestreamListener} to the
+ * manager. There are two ways to add this listener. If you want to be informed about incoming
+ * In-Band Bytestreams from a specific user add the listener by invoking
+ * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
+ * respond to all In-Band Bytestream requests invoke
+ * {@link #addIncomingBytestreamListener(BytestreamListener)}.
+ *
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * In-Band bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * If no {@link InBandBytestreamListener}s are registered, all incoming In-Band bytestream requests
+ * will be rejected by returning a <not-acceptable/> error to the initiator.
+ *
+ * @author Henning Staib
+ */
+public class InBandBytestreamManager implements BytestreamManager {
+
+ /**
+ * Stanzas that can be used to encapsulate In-Band Bytestream data packets.
+ */
+ public enum StanzaType {
+
+ /**
+ * IQ stanza.
+ */
+ IQ,
+
+ /**
+ * Message stanza.
+ */
+ MESSAGE
+ }
+
+ /*
+ * create a new InBandBytestreamManager and register its shutdown listener on every established
+ * connection
+ */
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+ public void connectionCreated(final Connection connection) {
+ // create the manager for this connection
+ InBandBytestreamManager.getByteStreamManager(connection);
+
+ // register shutdown listener
+ connection.addConnectionListener(new AbstractConnectionListener() {
+
+ @Override
+ public void connectionClosed() {
+ InBandBytestreamManager.getByteStreamManager(connection).disableService();
+ }
+
+ @Override
public void connectionClosedOnError(Exception e) {
- InBandBytestreamManager.getByteStreamManager(connection).disableService();
- }
-
- @Override
- public void reconnectionSuccessful() {
- // re-create the manager for this connection
- InBandBytestreamManager.getByteStreamManager(connection);
- }
-
- });
-
- }
- });
- }
-
- /**
- * The XMPP namespace of the In-Band Bytestream
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/ibb";
-
- /**
- * Maximum block size that is allowed for In-Band Bytestreams
- */
- public static final int MAXIMUM_BLOCK_SIZE = 65535;
-
- /* prefix used to generate session IDs */
- private static final String SESSION_ID_PREFIX = "jibb_";
-
- /* random generator to create session IDs */
- private final static Random randomGenerator = new Random();
-
- /* stores one InBandBytestreamManager for each XMPP connection */
- private final static Map
- * If no listeners are registered all In-Band Bytestream request are rejected with a
- * <not-acceptable/> error.
- *
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * Socks5 bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.add(listener);
- }
-
- /**
- * Removes the given listener from the list of listeners for all incoming In-Band Bytestream
- * requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.remove(listener);
- }
-
- /**
- * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
- * from the given user.
- *
- * Use this method if you are awaiting an incoming Socks5 bytestream request from a specific
- * user.
- *
- * If no listeners are registered all In-Band Bytestream request are rejected with a
- * <not-acceptable/> error.
- *
- * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
- * Socks5 bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish an In-Band Bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
- this.userListeners.put(initiatorJID, listener);
- }
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID) {
- this.userListeners.remove(initiatorJID);
- }
-
- /**
- * Use this method to ignore the next incoming In-Band Bytestream request containing the given
- * session ID. No listeners will be notified for this request and and no error will be returned
- * to the initiator.
- *
- * This method should be used if you are awaiting an In-Band Bytestream request as a reply to
- * another packet (e.g. file transfer).
- *
- * @param sessionID to be ignored
- */
- public void ignoreBytestreamRequestOnce(String sessionID) {
- this.ignoredBytestreamRequests.add(sessionID);
- }
-
- /**
- * Returns the default block size that is used for all outgoing in-band bytestreams for this
- * connection.
- *
- * The recommended default block size is 4096 bytes. See XEP-0047 Section 5.
- *
- * @return the default block size
- */
- public int getDefaultBlockSize() {
- return defaultBlockSize;
- }
-
- /**
- * Sets the default block size that is used for all outgoing in-band bytestreams for this
- * connection.
- *
- * The default block size must be between 1 and 65535 bytes. The recommended default block size
- * is 4096 bytes. See XEP-0047
- * Section 5.
- *
- * @param defaultBlockSize the default block size to set
- */
- public void setDefaultBlockSize(int defaultBlockSize) {
- if (defaultBlockSize <= 0 || defaultBlockSize > MAXIMUM_BLOCK_SIZE) {
- throw new IllegalArgumentException("Default block size must be between 1 and "
- + MAXIMUM_BLOCK_SIZE);
- }
- this.defaultBlockSize = defaultBlockSize;
- }
-
- /**
- * Returns the maximum block size that is allowed for In-Band Bytestreams for this connection.
- *
- * Incoming In-Band Bytestream open request will be rejected with an
- * <resource-constraint/> error if the block size is greater then the maximum allowed
- * block size.
- *
- * The default maximum block size is 65535 bytes.
- *
- * @return the maximum block size
- */
- public int getMaximumBlockSize() {
- return maximumBlockSize;
- }
-
- /**
- * Sets the maximum block size that is allowed for In-Band Bytestreams for this connection.
- *
- * The maximum block size must be between 1 and 65535 bytes.
- *
- * Incoming In-Band Bytestream open request will be rejected with an
- * <resource-constraint/> error if the block size is greater then the maximum allowed
- * block size.
- *
- * @param maximumBlockSize the maximum block size to set
- */
- public void setMaximumBlockSize(int maximumBlockSize) {
- if (maximumBlockSize <= 0 || maximumBlockSize > MAXIMUM_BLOCK_SIZE) {
- throw new IllegalArgumentException("Maximum block size must be between 1 and "
- + MAXIMUM_BLOCK_SIZE);
- }
- this.maximumBlockSize = maximumBlockSize;
- }
-
- /**
- * Returns the stanza used to send data packets.
- *
- * Default is {@link StanzaType#IQ}. See XEP-0047 Section 4.
- *
- * @return the stanza used to send data packets
- */
- public StanzaType getStanza() {
- return stanza;
- }
-
- /**
- * Sets the stanza used to send data packets.
- *
- * The use of {@link StanzaType#IQ} is recommended. See XEP-0047 Section 4.
- *
- * @param stanza the stanza to set
- */
- public void setStanza(StanzaType stanza) {
- this.stanza = stanza;
- }
-
- /**
- * Establishes an In-Band Bytestream with the given user and returns the session to send/receive
- * data to/from the user.
- *
- * Use this method to establish In-Band Bytestreams to users accepting all incoming In-Band
- * Bytestream requests since this method doesn't provide a way to tell the user something about
- * the data to be sent.
- *
- * To establish an In-Band Bytestream after negotiation the kind of data to be sent (e.g. file
- * transfer) use {@link #establishSession(String, String)}.
- *
- * @param targetJID the JID of the user an In-Band Bytestream should be established
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
- * user prefers smaller block sizes
- */
- public InBandBytestreamSession establishSession(String targetJID) throws XMPPException {
- String sessionID = getNextSessionID();
- return establishSession(targetJID, sessionID);
- }
-
- /**
- * Establishes an In-Band Bytestream with the given user using the given session ID and returns
- * the session to send/receive data to/from the user.
- *
- * @param targetJID the JID of the user an In-Band Bytestream should be established
- * @param sessionID the session ID for the In-Band Bytestream request
- * @return the session to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
- * user prefers smaller block sizes
- */
- public InBandBytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException {
- Open byteStreamRequest = new Open(sessionID, this.defaultBlockSize, this.stanza);
- byteStreamRequest.setTo(targetJID);
-
- // sending packet will throw exception on timeout or error reply
- SyncPacketSend.getReply(this.connection, byteStreamRequest);
-
- InBandBytestreamSession inBandBytestreamSession = new InBandBytestreamSession(
- this.connection, byteStreamRequest, targetJID);
- this.sessions.put(sessionID, inBandBytestreamSession);
-
- return inBandBytestreamSession;
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream is
- * not accepted.
- *
- * @param request IQ packet that should be answered with a not-acceptable error
- */
- protected void replyRejectPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream open
- * request is rejected because its block size is greater than the maximum allowed block size.
- *
- * @param request IQ packet that should be answered with a resource-constraint error
- */
- protected void replyResourceConstraintPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.resource_constraint);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream
- * session could not be found.
- *
- * @param request IQ packet that should be answered with a item-not-found error
- */
- protected void replyItemNotFoundPacket(IQ request) {
- XMPPError xmppError = new XMPPError(XMPPError.Condition.item_not_found);
- IQ error = IQ.createErrorResponse(request, xmppError);
- this.connection.sendPacket(error);
- }
-
- /**
- * Returns a new unique session ID.
- *
- * @return a new unique session ID
- */
- private String getNextSessionID() {
- StringBuilder buffer = new StringBuilder();
- buffer.append(SESSION_ID_PREFIX);
- buffer.append(Math.abs(randomGenerator.nextLong()));
- return buffer.toString();
- }
-
- /**
- * Returns the XMPP connection.
- *
- * @return the XMPP connection
- */
- protected Connection getConnection() {
- return this.connection;
- }
-
- /**
- * Returns the {@link InBandBytestreamListener} that should be informed if a In-Band Bytestream
- * request from the given initiator JID is received.
- *
- * @param initiator the initiator's JID
- * @return the listener
- */
- protected BytestreamListener getUserListener(String initiator) {
- return this.userListeners.get(initiator);
- }
-
- /**
- * Returns a list of {@link InBandBytestreamListener} that are informed if there are no
- * listeners for a specific initiator.
- *
- * @return list of listeners
- */
- protected List
+ * If no listeners are registered all In-Band Bytestream request are rejected with a
+ * <not-acceptable/> error.
+ *
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * Socks5 bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming In-Band Bytestream
+ * requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.remove(listener);
+ }
+
+ /**
+ * Adds InBandBytestreamListener that is called for every incoming in-band bytestream request
+ * from the given user.
+ *
+ * Use this method if you are awaiting an incoming Socks5 bytestream request from a specific
+ * user.
+ *
+ * If no listeners are registered all In-Band Bytestream request are rejected with a
+ * <not-acceptable/> error.
+ *
+ * Note that the registered {@link InBandBytestreamListener} will NOT be notified on incoming
+ * Socks5 bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish an In-Band Bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
+ this.userListeners.put(initiatorJID, listener);
+ }
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID) {
+ this.userListeners.remove(initiatorJID);
+ }
+
+ /**
+ * Use this method to ignore the next incoming In-Band Bytestream request containing the given
+ * session ID. No listeners will be notified for this request and and no error will be returned
+ * to the initiator.
+ *
+ * This method should be used if you are awaiting an In-Band Bytestream request as a reply to
+ * another packet (e.g. file transfer).
+ *
+ * @param sessionID to be ignored
+ */
+ public void ignoreBytestreamRequestOnce(String sessionID) {
+ this.ignoredBytestreamRequests.add(sessionID);
+ }
+
+ /**
+ * Returns the default block size that is used for all outgoing in-band bytestreams for this
+ * connection.
+ *
+ * The recommended default block size is 4096 bytes. See XEP-0047 Section 5.
+ *
+ * @return the default block size
+ */
+ public int getDefaultBlockSize() {
+ return defaultBlockSize;
+ }
+
+ /**
+ * Sets the default block size that is used for all outgoing in-band bytestreams for this
+ * connection.
+ *
+ * The default block size must be between 1 and 65535 bytes. The recommended default block size
+ * is 4096 bytes. See XEP-0047
+ * Section 5.
+ *
+ * @param defaultBlockSize the default block size to set
+ */
+ public void setDefaultBlockSize(int defaultBlockSize) {
+ if (defaultBlockSize <= 0 || defaultBlockSize > MAXIMUM_BLOCK_SIZE) {
+ throw new IllegalArgumentException("Default block size must be between 1 and "
+ + MAXIMUM_BLOCK_SIZE);
+ }
+ this.defaultBlockSize = defaultBlockSize;
+ }
+
+ /**
+ * Returns the maximum block size that is allowed for In-Band Bytestreams for this connection.
+ *
+ * Incoming In-Band Bytestream open request will be rejected with an
+ * <resource-constraint/> error if the block size is greater then the maximum allowed
+ * block size.
+ *
+ * The default maximum block size is 65535 bytes.
+ *
+ * @return the maximum block size
+ */
+ public int getMaximumBlockSize() {
+ return maximumBlockSize;
+ }
+
+ /**
+ * Sets the maximum block size that is allowed for In-Band Bytestreams for this connection.
+ *
+ * The maximum block size must be between 1 and 65535 bytes.
+ *
+ * Incoming In-Band Bytestream open request will be rejected with an
+ * <resource-constraint/> error if the block size is greater then the maximum allowed
+ * block size.
+ *
+ * @param maximumBlockSize the maximum block size to set
+ */
+ public void setMaximumBlockSize(int maximumBlockSize) {
+ if (maximumBlockSize <= 0 || maximumBlockSize > MAXIMUM_BLOCK_SIZE) {
+ throw new IllegalArgumentException("Maximum block size must be between 1 and "
+ + MAXIMUM_BLOCK_SIZE);
+ }
+ this.maximumBlockSize = maximumBlockSize;
+ }
+
+ /**
+ * Returns the stanza used to send data packets.
+ *
+ * Default is {@link StanzaType#IQ}. See XEP-0047 Section 4.
+ *
+ * @return the stanza used to send data packets
+ */
+ public StanzaType getStanza() {
+ return stanza;
+ }
+
+ /**
+ * Sets the stanza used to send data packets.
+ *
+ * The use of {@link StanzaType#IQ} is recommended. See XEP-0047 Section 4.
+ *
+ * @param stanza the stanza to set
+ */
+ public void setStanza(StanzaType stanza) {
+ this.stanza = stanza;
+ }
+
+ /**
+ * Establishes an In-Band Bytestream with the given user and returns the session to send/receive
+ * data to/from the user.
+ *
+ * Use this method to establish In-Band Bytestreams to users accepting all incoming In-Band
+ * Bytestream requests since this method doesn't provide a way to tell the user something about
+ * the data to be sent.
+ *
+ * To establish an In-Band Bytestream after negotiation the kind of data to be sent (e.g. file
+ * transfer) use {@link #establishSession(String, String)}.
+ *
+ * @param targetJID the JID of the user an In-Band Bytestream should be established
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
+ * user prefers smaller block sizes
+ */
+ public InBandBytestreamSession establishSession(String targetJID) throws XMPPException {
+ String sessionID = getNextSessionID();
+ return establishSession(targetJID, sessionID);
+ }
+
+ /**
+ * Establishes an In-Band Bytestream with the given user using the given session ID and returns
+ * the session to send/receive data to/from the user.
+ *
+ * @param targetJID the JID of the user an In-Band Bytestream should be established
+ * @param sessionID the session ID for the In-Band Bytestream request
+ * @return the session to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept in-band bytestreams, or if the
+ * user prefers smaller block sizes
+ */
+ public InBandBytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException {
+ Open byteStreamRequest = new Open(sessionID, this.defaultBlockSize, this.stanza);
+ byteStreamRequest.setTo(targetJID);
+
+ // sending packet will throw exception on timeout or error reply
+ SyncPacketSend.getReply(this.connection, byteStreamRequest);
+
+ InBandBytestreamSession inBandBytestreamSession = new InBandBytestreamSession(
+ this.connection, byteStreamRequest, targetJID);
+ this.sessions.put(sessionID, inBandBytestreamSession);
+
+ return inBandBytestreamSession;
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream is
+ * not accepted.
+ *
+ * @param request IQ packet that should be answered with a not-acceptable error
+ */
+ protected void replyRejectPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream open
+ * request is rejected because its block size is greater than the maximum allowed block size.
+ *
+ * @param request IQ packet that should be answered with a resource-constraint error
+ */
+ protected void replyResourceConstraintPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.resource_constraint);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream
+ * session could not be found.
+ *
+ * @param request IQ packet that should be answered with a item-not-found error
+ */
+ protected void replyItemNotFoundPacket(IQ request) {
+ XMPPError xmppError = new XMPPError(XMPPError.Condition.item_not_found);
+ IQ error = IQ.createErrorResponse(request, xmppError);
+ this.connection.sendPacket(error);
+ }
+
+ /**
+ * Returns a new unique session ID.
+ *
+ * @return a new unique session ID
+ */
+ private String getNextSessionID() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(SESSION_ID_PREFIX);
+ buffer.append(Math.abs(randomGenerator.nextLong()));
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the XMPP connection.
+ *
+ * @return the XMPP connection
+ */
+ protected Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Returns the {@link InBandBytestreamListener} that should be informed if a In-Band Bytestream
+ * request from the given initiator JID is received.
+ *
+ * @param initiator the initiator's JID
+ * @return the listener
+ */
+ protected BytestreamListener getUserListener(String initiator) {
+ return this.userListeners.get(initiator);
+ }
+
+ /**
+ * Returns a list of {@link InBandBytestreamListener} that are informed if there are no
+ * listeners for a specific initiator.
+ *
+ * @return list of listeners
+ */
+ protected List
- * In-band bytestreams are bidirectional and this session encapsulates the streams for both
- * directions.
- *
- * Note that closing the In-Band Bytestream session will close both streams. If both streams are
- * closed individually the session will be closed automatically once the second stream is closed.
- * Use the {@link #setCloseBothStreamsEnabled(boolean)} method if both streams should be closed
- * automatically if one of them is closed.
- *
- * @author Henning Staib
- */
-public class InBandBytestreamSession implements BytestreamSession {
-
- /* XMPP connection */
- private final Connection connection;
-
- /* the In-Band Bytestream open request for this session */
- private final Open byteStreamRequest;
-
- /*
- * the input stream for this session (either IQIBBInputStream or MessageIBBInputStream)
- */
- private IBBInputStream inputStream;
-
- /*
- * the output stream for this session (either IQIBBOutputStream or MessageIBBOutputStream)
- */
- private IBBOutputStream outputStream;
-
- /* JID of the remote peer */
- private String remoteJID;
-
- /* flag to close both streams if one of them is closed */
- private boolean closeBothStreamsEnabled = false;
-
- /* flag to indicate if session is closed */
- private boolean isClosed = false;
-
- /**
- * Constructor.
- *
- * @param connection the XMPP connection
- * @param byteStreamRequest the In-Band Bytestream open request for this session
- * @param remoteJID JID of the remote peer
- */
- protected InBandBytestreamSession(Connection connection, Open byteStreamRequest,
- String remoteJID) {
- this.connection = connection;
- this.byteStreamRequest = byteStreamRequest;
- this.remoteJID = remoteJID;
-
- // initialize streams dependent to the uses stanza type
- switch (byteStreamRequest.getStanza()) {
- case IQ:
- this.inputStream = new IQIBBInputStream();
- this.outputStream = new IQIBBOutputStream();
- break;
- case MESSAGE:
- this.inputStream = new MessageIBBInputStream();
- this.outputStream = new MessageIBBOutputStream();
- break;
- }
-
- }
-
- public InputStream getInputStream() {
- return this.inputStream;
- }
-
- public OutputStream getOutputStream() {
- return this.outputStream;
- }
-
- public int getReadTimeout() {
- return this.inputStream.readTimeout;
- }
-
- public void setReadTimeout(int timeout) {
- if (timeout < 0) {
- throw new IllegalArgumentException("Timeout must be >= 0");
- }
- this.inputStream.readTimeout = timeout;
- }
-
- /**
- * Returns whether both streams should be closed automatically if one of the streams is closed.
- * Default is
+ * In-band bytestreams are bidirectional and this session encapsulates the streams for both
+ * directions.
+ *
+ * Note that closing the In-Band Bytestream session will close both streams. If both streams are
+ * closed individually the session will be closed automatically once the second stream is closed.
+ * Use the {@link #setCloseBothStreamsEnabled(boolean)} method if both streams should be closed
+ * automatically if one of them is closed.
+ *
+ * @author Henning Staib
+ */
+public class InBandBytestreamSession implements BytestreamSession {
+
+ /* XMPP connection */
+ private final Connection connection;
+
+ /* the In-Band Bytestream open request for this session */
+ private final Open byteStreamRequest;
+
+ /*
+ * the input stream for this session (either IQIBBInputStream or MessageIBBInputStream)
+ */
+ private IBBInputStream inputStream;
+
+ /*
+ * the output stream for this session (either IQIBBOutputStream or MessageIBBOutputStream)
+ */
+ private IBBOutputStream outputStream;
+
+ /* JID of the remote peer */
+ private String remoteJID;
+
+ /* flag to close both streams if one of them is closed */
+ private boolean closeBothStreamsEnabled = false;
+
+ /* flag to indicate if session is closed */
+ private boolean isClosed = false;
+
+ /**
+ * Constructor.
+ *
+ * @param connection the XMPP connection
+ * @param byteStreamRequest the In-Band Bytestream open request for this session
+ * @param remoteJID JID of the remote peer
+ */
+ protected InBandBytestreamSession(Connection connection, Open byteStreamRequest,
+ String remoteJID) {
+ this.connection = connection;
+ this.byteStreamRequest = byteStreamRequest;
+ this.remoteJID = remoteJID;
+
+ // initialize streams dependent to the uses stanza type
+ switch (byteStreamRequest.getStanza()) {
+ case IQ:
+ this.inputStream = new IQIBBInputStream();
+ this.outputStream = new IQIBBOutputStream();
+ break;
+ case MESSAGE:
+ this.inputStream = new MessageIBBInputStream();
+ this.outputStream = new MessageIBBOutputStream();
+ break;
+ }
+
+ }
+
+ public InputStream getInputStream() {
+ return this.inputStream;
+ }
+
+ public OutputStream getOutputStream() {
+ return this.outputStream;
+ }
+
+ public int getReadTimeout() {
+ return this.inputStream.readTimeout;
+ }
+
+ public void setReadTimeout(int timeout) {
+ if (timeout < 0) {
+ throw new IllegalArgumentException("Timeout must be >= 0");
+ }
+ this.inputStream.readTimeout = timeout;
+ }
+
+ /**
+ * Returns whether both streams should be closed automatically if one of the streams is closed.
+ * Default is
- * All In-Band Bytestream request having a block size greater than the maximum allowed block size
- * for this connection are rejected with an <resource-constraint/> error. The maximum block
- * size can be set by invoking {@link InBandBytestreamManager#setMaximumBlockSize(int)}.
- *
- * @author Henning Staib
- */
-class InitiationListener implements PacketListener {
-
- /* manager containing the listeners and the XMPP connection */
- private final InBandBytestreamManager manager;
-
- /* packet filter for all In-Band Bytestream requests */
- private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Open.class),
- new IQTypeFilter(IQ.Type.SET));
-
- /* executor service to process incoming requests concurrently */
- private final ExecutorService initiationListenerExecutor;
-
- /**
- * Constructor.
- *
- * @param manager the In-Band Bytestream manager
- */
- protected InitiationListener(InBandBytestreamManager manager) {
- this.manager = manager;
- initiationListenerExecutor = Executors.newCachedThreadPool();
- }
-
- public void processPacket(final Packet packet) {
- initiationListenerExecutor.execute(new Runnable() {
-
- public void run() {
- processRequest(packet);
- }
- });
- }
-
- private void processRequest(Packet packet) {
- Open ibbRequest = (Open) packet;
-
- // validate that block size is within allowed range
- if (ibbRequest.getBlockSize() > this.manager.getMaximumBlockSize()) {
- this.manager.replyResourceConstraintPacket(ibbRequest);
- return;
- }
-
- // ignore request if in ignore list
- if (this.manager.getIgnoredBytestreamRequests().remove(ibbRequest.getSessionID()))
- return;
-
- // build bytestream request from packet
- InBandBytestreamRequest request = new InBandBytestreamRequest(this.manager, ibbRequest);
-
- // notify listeners for bytestream initiation from a specific user
- BytestreamListener userListener = this.manager.getUserListener(ibbRequest.getFrom());
- if (userListener != null) {
- userListener.incomingBytestreamRequest(request);
-
- }
- else if (!this.manager.getAllRequestListeners().isEmpty()) {
- /*
- * if there is no user specific listener inform listeners for all initiation requests
- */
- for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
- listener.incomingBytestreamRequest(request);
- }
-
- }
- else {
- /*
- * if there is no listener for this initiation request, reply with reject message
- */
- this.manager.replyRejectPacket(ibbRequest);
- }
- }
-
- /**
- * Returns the packet filter for In-Band Bytestream open requests.
- *
- * @return the packet filter for In-Band Bytestream open requests
- */
- protected PacketFilter getFilter() {
- return this.initFilter;
- }
-
- /**
- * Shuts down the listeners executor service.
- */
- protected void shutdown() {
- this.initiationListenerExecutor.shutdownNow();
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.IQTypeFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+
+/**
+ * InitiationListener handles all incoming In-Band Bytestream open requests. If there are no
+ * listeners for a In-Band Bytestream request InitiationListener will always refuse the request and
+ * reply with a <not-acceptable/> error (XEP-0047 Section 2.1).
+ *
+ * All In-Band Bytestream request having a block size greater than the maximum allowed block size
+ * for this connection are rejected with an <resource-constraint/> error. The maximum block
+ * size can be set by invoking {@link InBandBytestreamManager#setMaximumBlockSize(int)}.
+ *
+ * @author Henning Staib
+ */
+class InitiationListener implements PacketListener {
+
+ /* manager containing the listeners and the XMPP connection */
+ private final InBandBytestreamManager manager;
+
+ /* packet filter for all In-Band Bytestream requests */
+ private final PacketFilter initFilter = new AndFilter(new PacketTypeFilter(Open.class),
+ new IQTypeFilter(IQ.Type.SET));
+
+ /* executor service to process incoming requests concurrently */
+ private final ExecutorService initiationListenerExecutor;
+
+ /**
+ * Constructor.
+ *
+ * @param manager the In-Band Bytestream manager
+ */
+ protected InitiationListener(InBandBytestreamManager manager) {
+ this.manager = manager;
+ initiationListenerExecutor = Executors.newCachedThreadPool();
+ }
+
+ public void processPacket(final Packet packet) {
+ initiationListenerExecutor.execute(new Runnable() {
+
+ public void run() {
+ processRequest(packet);
+ }
+ });
+ }
+
+ private void processRequest(Packet packet) {
+ Open ibbRequest = (Open) packet;
+
+ // validate that block size is within allowed range
+ if (ibbRequest.getBlockSize() > this.manager.getMaximumBlockSize()) {
+ this.manager.replyResourceConstraintPacket(ibbRequest);
+ return;
+ }
+
+ // ignore request if in ignore list
+ if (this.manager.getIgnoredBytestreamRequests().remove(ibbRequest.getSessionID()))
+ return;
+
+ // build bytestream request from packet
+ InBandBytestreamRequest request = new InBandBytestreamRequest(this.manager, ibbRequest);
+
+ // notify listeners for bytestream initiation from a specific user
+ BytestreamListener userListener = this.manager.getUserListener(ibbRequest.getFrom());
+ if (userListener != null) {
+ userListener.incomingBytestreamRequest(request);
+
+ }
+ else if (!this.manager.getAllRequestListeners().isEmpty()) {
+ /*
+ * if there is no user specific listener inform listeners for all initiation requests
+ */
+ for (BytestreamListener listener : this.manager.getAllRequestListeners()) {
+ listener.incomingBytestreamRequest(request);
+ }
+
+ }
+ else {
+ /*
+ * if there is no listener for this initiation request, reply with reject message
+ */
+ this.manager.replyRejectPacket(ibbRequest);
+ }
+ }
+
+ /**
+ * Returns the packet filter for In-Band Bytestream open requests.
+ *
+ * @return the packet filter for In-Band Bytestream open requests
+ */
+ protected PacketFilter getFilter() {
+ return this.initFilter;
+ }
+
+ /**
+ * Shuts down the listeners executor service.
+ */
+ protected void shutdown() {
+ this.initiationListenerExecutor.shutdownNow();
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
index f9a768524..fb0933695 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Close.java
@@ -1,68 +1,68 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-
-/**
- * Represents a request to close an In-Band Bytestream.
- *
- * @author Henning Staib
- */
-public class Close extends IQ {
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /**
- * Creates a new In-Band Bytestream close request packet.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- */
- public Close(String sessionID) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- this.sessionID = sessionID;
- setType(Type.SET);
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- @Override
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("
- * Convenience method for
+ * Convenience method for
- * The encoded data is invalid if it contains bad Base64 input characters or
- * if it contains the pad ('=') character on a position other than the last
- * character(s) of the data. See XEP-0047 Section
- * 6.
- *
- * @return the decoded data
- */
- public byte[] getDecodedData() {
- // return cached decoded data
- if (this.decodedData != null) {
- return this.decodedData;
- }
-
- // data must not contain the pad (=) other than end of data
- if (data.matches(".*={1,2}+.+")) {
- return null;
- }
-
- // decodeBase64 will return null if bad characters are included
- this.decodedData = StringUtils.decodeBase64(data);
- return this.decodedData;
- }
-
- public String getElementName() {
- return ELEMENT_NAME;
- }
-
- public String getNamespace() {
- return InBandBytestreamManager.NAMESPACE;
- }
-
- public String toXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("<");
- buf.append(getElementName());
- buf.append(" ");
- buf.append("xmlns=\"");
- buf.append(InBandBytestreamManager.NAMESPACE);
- buf.append("\" ");
- buf.append("seq=\"");
- buf.append(seq);
- buf.append("\" ");
- buf.append("sid=\"");
- buf.append(sessionID);
- buf.append("\">");
- buf.append(data);
- buf.append("");
- buf.append(getElementName());
- buf.append(">");
- return buf.toString();
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
+
+/**
+ * Represents a chunk of data of an In-Band Bytestream within an IQ stanza or a
+ * message stanza
+ *
+ * @author Henning Staib
+ */
+public class DataPacketExtension implements PacketExtension {
+
+ /**
+ * The element name of the data packet extension.
+ */
+ public final static String ELEMENT_NAME = "data";
+
+ /* unique session ID identifying this In-Band Bytestream */
+ private final String sessionID;
+
+ /* sequence of this packet in regard to the other data packets */
+ private final long seq;
+
+ /* the data contained in this packet */
+ private final String data;
+
+ private byte[] decodedData;
+
+ /**
+ * Creates a new In-Band Bytestream data packet.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param seq sequence of this packet in regard to the other data packets
+ * @param data the base64 encoded data contained in this packet
+ */
+ public DataPacketExtension(String sessionID, long seq, String data) {
+ if (sessionID == null || "".equals(sessionID)) {
+ throw new IllegalArgumentException("Session ID must not be null or empty");
+ }
+ if (seq < 0 || seq > 65535) {
+ throw new IllegalArgumentException("Sequence must not be between 0 and 65535");
+ }
+ if (data == null) {
+ throw new IllegalArgumentException("Data must not be null");
+ }
+ this.sessionID = sessionID;
+ this.seq = seq;
+ this.data = data;
+ }
+
+ /**
+ * Returns the unique session ID identifying this In-Band Bytestream.
+ *
+ * @return the unique session ID identifying this In-Band Bytestream
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the sequence of this packet in regard to the other data packets.
+ *
+ * @return the sequence of this packet in regard to the other data packets.
+ */
+ public long getSeq() {
+ return seq;
+ }
+
+ /**
+ * Returns the data contained in this packet.
+ *
+ * @return the data contained in this packet.
+ */
+ public String getData() {
+ return data;
+ }
+
+ /**
+ * Returns the decoded data or null if data could not be decoded.
+ *
+ * The encoded data is invalid if it contains bad Base64 input characters or
+ * if it contains the pad ('=') character on a position other than the last
+ * character(s) of the data. See XEP-0047 Section
+ * 6.
+ *
+ * @return the decoded data
+ */
+ public byte[] getDecodedData() {
+ // return cached decoded data
+ if (this.decodedData != null) {
+ return this.decodedData;
+ }
+
+ // data must not contain the pad (=) other than end of data
+ if (data.matches(".*={1,2}+.+")) {
+ return null;
+ }
+
+ // decodeBase64 will return null if bad characters are included
+ this.decodedData = StringUtils.decodeBase64(data);
+ return this.decodedData;
+ }
+
+ public String getElementName() {
+ return ELEMENT_NAME;
+ }
+
+ public String getNamespace() {
+ return InBandBytestreamManager.NAMESPACE;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<");
+ buf.append(getElementName());
+ buf.append(" ");
+ buf.append("xmlns=\"");
+ buf.append(InBandBytestreamManager.NAMESPACE);
+ buf.append("\" ");
+ buf.append("seq=\"");
+ buf.append(seq);
+ buf.append("\" ");
+ buf.append("sid=\"");
+ buf.append(sessionID);
+ buf.append("\">");
+ buf.append(data);
+ buf.append("");
+ buf.append(getElementName());
+ buf.append(">");
+ return buf.toString();
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
index b7303b75e..9f755a824 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/Open.java
@@ -1,129 +1,129 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager.StanzaType;
-
-/**
- * Represents a request to open an In-Band Bytestream.
- *
- * @author Henning Staib
- */
-public class Open extends IQ {
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /* block size in which the data will be fragmented */
- private final int blockSize;
-
- /* stanza type used to encapsulate the data */
- private final StanzaType stanza;
-
- /**
- * Creates a new In-Band Bytestream open request packet.
- *
- * The data sent over this In-Band Bytestream will be fragmented in blocks
- * with the given block size. The block size should not be greater than
- * 65535. A recommended default value is 4096.
- *
- * The data can be sent using IQ stanzas or message stanzas.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param blockSize block size in which the data will be fragmented
- * @param stanza stanza type used to encapsulate the data
- */
- public Open(String sessionID, int blockSize, StanzaType stanza) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- if (blockSize <= 0) {
- throw new IllegalArgumentException("Block size must be greater than zero");
- }
-
- this.sessionID = sessionID;
- this.blockSize = blockSize;
- this.stanza = stanza;
- setType(Type.SET);
- }
-
- /**
- * Creates a new In-Band Bytestream open request packet.
- *
- * The data sent over this In-Band Bytestream will be fragmented in blocks
- * with the given block size. The block size should not be greater than
- * 65535. A recommended default value is 4096.
- *
- * The data will be sent using IQ stanzas.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param blockSize block size in which the data will be fragmented
- */
- public Open(String sessionID, int blockSize) {
- this(sessionID, blockSize, StanzaType.IQ);
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the block size in which the data will be fragmented.
- *
- * @return the block size in which the data will be fragmented
- */
- public int getBlockSize() {
- return blockSize;
- }
-
- /**
- * Returns the stanza type used to encapsulate the data.
- *
- * @return the stanza type used to encapsulate the data
- */
- public StanzaType getStanza() {
- return stanza;
- }
-
- @Override
- public String getChildElementXML() {
- StringBuilder buf = new StringBuilder();
- buf.append("
+ * The data sent over this In-Band Bytestream will be fragmented in blocks
+ * with the given block size. The block size should not be greater than
+ * 65535. A recommended default value is 4096.
+ *
+ * The data can be sent using IQ stanzas or message stanzas.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param blockSize block size in which the data will be fragmented
+ * @param stanza stanza type used to encapsulate the data
+ */
+ public Open(String sessionID, int blockSize, StanzaType stanza) {
+ if (sessionID == null || "".equals(sessionID)) {
+ throw new IllegalArgumentException("Session ID must not be null or empty");
+ }
+ if (blockSize <= 0) {
+ throw new IllegalArgumentException("Block size must be greater than zero");
+ }
+
+ this.sessionID = sessionID;
+ this.blockSize = blockSize;
+ this.stanza = stanza;
+ setType(Type.SET);
+ }
+
+ /**
+ * Creates a new In-Band Bytestream open request packet.
+ *
+ * The data sent over this In-Band Bytestream will be fragmented in blocks
+ * with the given block size. The block size should not be greater than
+ * 65535. A recommended default value is 4096.
+ *
+ * The data will be sent using IQ stanzas.
+ *
+ * @param sessionID unique session ID identifying this In-Band Bytestream
+ * @param blockSize block size in which the data will be fragmented
+ */
+ public Open(String sessionID, int blockSize) {
+ this(sessionID, blockSize, StanzaType.IQ);
+ }
+
+ /**
+ * Returns the unique session ID identifying this In-Band Bytestream.
+ *
+ * @return the unique session ID identifying this In-Band Bytestream
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Returns the block size in which the data will be fragmented.
+ *
+ * @return the block size in which the data will be fragmented
+ */
+ public int getBlockSize() {
+ return blockSize;
+ }
+
+ /**
+ * Returns the stanza type used to encapsulate the data.
+ *
+ * @return the stanza type used to encapsulate the data
+ */
+ public StanzaType getStanza() {
+ return stanza;
+ }
+
+ @Override
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("
- * There are two ways to add this listener. See
- * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
- * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
- * further details.
- *
- * @author Henning Staib
- */
-public abstract class Socks5BytestreamListener implements BytestreamListener {
-
- public void incomingBytestreamRequest(BytestreamRequest request) {
- incomingBytestreamRequest((Socks5BytestreamRequest) request);
- }
-
- /**
- * This listener is notified if a SOCKS5 Bytestream request from another user has been received.
- *
- * @param request the incoming SOCKS5 Bytestream request
- */
- public abstract void incomingBytestreamRequest(Socks5BytestreamRequest request);
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.socks5;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamListener;
+import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
+
+/**
+ * Socks5BytestreamListener are informed if a remote user wants to initiate a SOCKS5 Bytestream.
+ * Implement this interface to handle incoming SOCKS5 Bytestream requests.
+ *
+ * There are two ways to add this listener. See
+ * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener)} and
+ * {@link Socks5BytestreamManager#addIncomingBytestreamListener(BytestreamListener, String)} for
+ * further details.
+ *
+ * @author Henning Staib
+ */
+public abstract class Socks5BytestreamListener implements BytestreamListener {
+
+ public void incomingBytestreamRequest(BytestreamRequest request) {
+ incomingBytestreamRequest((Socks5BytestreamRequest) request);
+ }
+
+ /**
+ * This listener is notified if a SOCKS5 Bytestream request from another user has been received.
+ *
+ * @param request the incoming SOCKS5 Bytestream request
+ */
+ public abstract void incomingBytestreamRequest(Socks5BytestreamRequest request);
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
index 190ec3d06..67210d6a1 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java
@@ -1,783 +1,783 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.AbstractConnectionListener;
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.ConnectionCreationListener;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smack.packet.XMPPError;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.BytestreamManager;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHostUsed;
-import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
-import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
-import org.jivesoftware.smackx.disco.packet.DiscoverItems;
-import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
-import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
-import org.jivesoftware.smackx.filetransfer.FileTransferManager;
-
-/**
- * The Socks5BytestreamManager class handles establishing SOCKS5 Bytestreams as specified in the XEP-0065.
- *
- * A SOCKS5 Bytestream is negotiated partly over the XMPP XML stream and partly over a separate
- * socket. The actual transfer though takes place over a separately created socket.
- *
- * A SOCKS5 Bytestream generally has three parties, the initiator, the target, and the stream host.
- * The stream host is a specialized SOCKS5 proxy setup on a server, or, the initiator can act as the
- * stream host.
- *
- * To establish a SOCKS5 Bytestream invoke the {@link #establishSession(String)} method. This will
- * negotiate a SOCKS5 Bytestream with the given target JID and return a socket.
- *
- * If a session ID for the SOCKS5 Bytestream was already negotiated (e.g. while negotiating a file
- * transfer) invoke {@link #establishSession(String, String)}.
- *
- * To handle incoming SOCKS5 Bytestream requests add an {@link Socks5BytestreamListener} to the
- * manager. There are two ways to add this listener. If you want to be informed about incoming
- * SOCKS5 Bytestreams from a specific user add the listener by invoking
- * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
- * respond to all SOCKS5 Bytestream requests invoke
- * {@link #addIncomingBytestreamListener(BytestreamListener)}.
- *
- * Note that the registered {@link Socks5BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * If no {@link Socks5BytestreamListener}s are registered, all incoming SOCKS5 Bytestream requests
- * will be rejected by returning a <not-acceptable/> error to the initiator.
- *
- * @author Henning Staib
- */
-public final class Socks5BytestreamManager implements BytestreamManager {
-
- /*
- * create a new Socks5BytestreamManager and register a shutdown listener on every established
- * connection
- */
- static {
- Connection.addConnectionCreationListener(new ConnectionCreationListener() {
-
- public void connectionCreated(final Connection connection) {
- // create the manager for this connection
- Socks5BytestreamManager.getBytestreamManager(connection);
-
- // register shutdown listener
- connection.addConnectionListener(new AbstractConnectionListener() {
-
- @Override
- public void connectionClosed() {
- Socks5BytestreamManager.getBytestreamManager(connection).disableService();
- }
-
- @Override
- public void connectionClosedOnError(Exception e) {
- Socks5BytestreamManager.getBytestreamManager(connection).disableService();
- }
-
- @Override
- public void reconnectionSuccessful() {
- // re-create the manager for this connection
- Socks5BytestreamManager.getBytestreamManager(connection);
- }
-
- });
- }
-
- });
- }
-
- /**
- * The XMPP namespace of the SOCKS5 Bytestream
- */
- public static final String NAMESPACE = "http://jabber.org/protocol/bytestreams";
-
- /* prefix used to generate session IDs */
- private static final String SESSION_ID_PREFIX = "js5_";
-
- /* random generator to create session IDs */
- private final static Random randomGenerator = new Random();
-
- /* stores one Socks5BytestreamManager for each XMPP connection */
- private final static Map
- * If no manager exists a new is created and initialized.
- *
- * @param connection the XMPP connection or
- * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
- * <not-acceptable/> error.
- *
- * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- */
- public void addIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.add(listener);
- }
-
- /**
- * Removes the given listener from the list of listeners for all incoming SOCKS5 Bytestream
- * requests.
- *
- * @param listener the listener to remove
- */
- public void removeIncomingBytestreamListener(BytestreamListener listener) {
- this.allRequestListeners.remove(listener);
- }
-
- /**
- * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request from the
- * given user.
- *
- * Use this method if you are awaiting an incoming SOCKS5 Bytestream request from a specific
- * user.
- *
- * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
- * <not-acceptable/> error.
- *
- * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
- * bytestream requests sent in the context of XEP-0096 file transfer. (See
- * {@link FileTransferManager})
- *
- * @param listener the listener to register
- * @param initiatorJID the JID of the user that wants to establish a SOCKS5 Bytestream
- */
- public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
- this.userListeners.put(initiatorJID, listener);
- }
-
- /**
- * Removes the listener for the given user.
- *
- * @param initiatorJID the JID of the user the listener should be removed
- */
- public void removeIncomingBytestreamListener(String initiatorJID) {
- this.userListeners.remove(initiatorJID);
- }
-
- /**
- * Use this method to ignore the next incoming SOCKS5 Bytestream request containing the given
- * session ID. No listeners will be notified for this request and and no error will be returned
- * to the initiator.
- *
- * This method should be used if you are awaiting a SOCKS5 Bytestream request as a reply to
- * another packet (e.g. file transfer).
- *
- * @param sessionID to be ignored
- */
- public void ignoreBytestreamRequestOnce(String sessionID) {
- this.ignoredBytestreamRequests.add(sessionID);
- }
-
- /**
- * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the
- * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and
- * resetting its internal state, which includes removing this instance from the managers map.
- *
- * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(Connection)}.
- * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
- */
- public synchronized void disableService() {
-
- // remove initiation packet listener
- this.connection.removePacketListener(this.initiationListener);
-
- // shutdown threads
- this.initiationListener.shutdown();
-
- // clear listeners
- this.allRequestListeners.clear();
- this.userListeners.clear();
-
- // reset internal state
- this.lastWorkingProxy = null;
- this.proxyBlacklist.clear();
- this.ignoredBytestreamRequests.clear();
-
- // remove manager from static managers map
- managers.remove(this.connection);
-
- // shutdown local SOCKS5 proxy if there are no more managers for other connections
- if (managers.size() == 0) {
- Socks5Proxy.getSocks5Proxy().stop();
- }
-
- // remove feature from service discovery
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
-
- // check if service discovery is not already disposed by connection shutdown
- if (serviceDiscoveryManager != null) {
- serviceDiscoveryManager.removeFeature(NAMESPACE);
- }
-
- }
-
- /**
- * Returns the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
- * Default is 10000ms.
- *
- * @return the timeout to wait for the response to the SOCKS5 Bytestream initialization request
- */
- public int getTargetResponseTimeout() {
- if (this.targetResponseTimeout <= 0) {
- this.targetResponseTimeout = 10000;
- }
- return targetResponseTimeout;
- }
-
- /**
- * Sets the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
- * Default is 10000ms.
- *
- * @param targetResponseTimeout the timeout to set
- */
- public void setTargetResponseTimeout(int targetResponseTimeout) {
- this.targetResponseTimeout = targetResponseTimeout;
- }
-
- /**
- * Returns the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
- * 10000ms.
- *
- * @return the timeout for connecting to the SOCKS5 proxy selected by the target
- */
- public int getProxyConnectionTimeout() {
- if (this.proxyConnectionTimeout <= 0) {
- this.proxyConnectionTimeout = 10000;
- }
- return proxyConnectionTimeout;
- }
-
- /**
- * Sets the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
- * 10000ms.
- *
- * @param proxyConnectionTimeout the timeout to set
- */
- public void setProxyConnectionTimeout(int proxyConnectionTimeout) {
- this.proxyConnectionTimeout = proxyConnectionTimeout;
- }
-
- /**
- * Returns if the prioritization of the last working SOCKS5 proxy on successive SOCKS5
- * Bytestream connections is enabled. Default is
- * Use this method to establish SOCKS5 Bytestreams to users accepting all incoming Socks5
- * bytestream requests since this method doesn't provide a way to tell the user something about
- * the data to be sent.
- *
- * To establish a SOCKS5 Bytestream after negotiation the kind of data to be sent (e.g. file
- * transfer) use {@link #establishSession(String, String)}.
- *
- * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
- * @return the Socket to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
- * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
- * @throws IOException if the bytestream could not be established
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession establishSession(String targetJID) throws XMPPException,
- IOException, InterruptedException {
- String sessionID = getNextSessionID();
- return establishSession(targetJID, sessionID);
- }
-
- /**
- * Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns
- * the Socket to send/receive data to/from the user.
- *
- * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
- * @param sessionID the session ID for the SOCKS5 Bytestream request
- * @return the Socket to send/receive data to/from the user
- * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
- * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
- * @throws IOException if the bytestream could not be established
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
- throws XMPPException, IOException, InterruptedException {
-
- XMPPException discoveryException = null;
- // check if target supports SOCKS5 Bytestream
- if (!supportsSocks5(targetJID)) {
- throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream");
- }
-
- List
+ * A SOCKS5 Bytestream is negotiated partly over the XMPP XML stream and partly over a separate
+ * socket. The actual transfer though takes place over a separately created socket.
+ *
+ * A SOCKS5 Bytestream generally has three parties, the initiator, the target, and the stream host.
+ * The stream host is a specialized SOCKS5 proxy setup on a server, or, the initiator can act as the
+ * stream host.
+ *
+ * To establish a SOCKS5 Bytestream invoke the {@link #establishSession(String)} method. This will
+ * negotiate a SOCKS5 Bytestream with the given target JID and return a socket.
+ *
+ * If a session ID for the SOCKS5 Bytestream was already negotiated (e.g. while negotiating a file
+ * transfer) invoke {@link #establishSession(String, String)}.
+ *
+ * To handle incoming SOCKS5 Bytestream requests add an {@link Socks5BytestreamListener} to the
+ * manager. There are two ways to add this listener. If you want to be informed about incoming
+ * SOCKS5 Bytestreams from a specific user add the listener by invoking
+ * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should
+ * respond to all SOCKS5 Bytestream requests invoke
+ * {@link #addIncomingBytestreamListener(BytestreamListener)}.
+ *
+ * Note that the registered {@link Socks5BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * If no {@link Socks5BytestreamListener}s are registered, all incoming SOCKS5 Bytestream requests
+ * will be rejected by returning a <not-acceptable/> error to the initiator.
+ *
+ * @author Henning Staib
+ */
+public final class Socks5BytestreamManager implements BytestreamManager {
+
+ /*
+ * create a new Socks5BytestreamManager and register a shutdown listener on every established
+ * connection
+ */
+ static {
+ Connection.addConnectionCreationListener(new ConnectionCreationListener() {
+
+ public void connectionCreated(final Connection connection) {
+ // create the manager for this connection
+ Socks5BytestreamManager.getBytestreamManager(connection);
+
+ // register shutdown listener
+ connection.addConnectionListener(new AbstractConnectionListener() {
+
+ @Override
+ public void connectionClosed() {
+ Socks5BytestreamManager.getBytestreamManager(connection).disableService();
+ }
+
+ @Override
+ public void connectionClosedOnError(Exception e) {
+ Socks5BytestreamManager.getBytestreamManager(connection).disableService();
+ }
+
+ @Override
+ public void reconnectionSuccessful() {
+ // re-create the manager for this connection
+ Socks5BytestreamManager.getBytestreamManager(connection);
+ }
+
+ });
+ }
+
+ });
+ }
+
+ /**
+ * The XMPP namespace of the SOCKS5 Bytestream
+ */
+ public static final String NAMESPACE = "http://jabber.org/protocol/bytestreams";
+
+ /* prefix used to generate session IDs */
+ private static final String SESSION_ID_PREFIX = "js5_";
+
+ /* random generator to create session IDs */
+ private final static Random randomGenerator = new Random();
+
+ /* stores one Socks5BytestreamManager for each XMPP connection */
+ private final static Map
+ * If no manager exists a new is created and initialized.
+ *
+ * @param connection the XMPP connection or
+ * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
+ * <not-acceptable/> error.
+ *
+ * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners for all incoming SOCKS5 Bytestream
+ * requests.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeIncomingBytestreamListener(BytestreamListener listener) {
+ this.allRequestListeners.remove(listener);
+ }
+
+ /**
+ * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request from the
+ * given user.
+ *
+ * Use this method if you are awaiting an incoming SOCKS5 Bytestream request from a specific
+ * user.
+ *
+ * If no listeners are registered all SOCKS5 Bytestream request are rejected with a
+ * <not-acceptable/> error.
+ *
+ * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5
+ * bytestream requests sent in the context of XEP-0096 file transfer. (See
+ * {@link FileTransferManager})
+ *
+ * @param listener the listener to register
+ * @param initiatorJID the JID of the user that wants to establish a SOCKS5 Bytestream
+ */
+ public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) {
+ this.userListeners.put(initiatorJID, listener);
+ }
+
+ /**
+ * Removes the listener for the given user.
+ *
+ * @param initiatorJID the JID of the user the listener should be removed
+ */
+ public void removeIncomingBytestreamListener(String initiatorJID) {
+ this.userListeners.remove(initiatorJID);
+ }
+
+ /**
+ * Use this method to ignore the next incoming SOCKS5 Bytestream request containing the given
+ * session ID. No listeners will be notified for this request and and no error will be returned
+ * to the initiator.
+ *
+ * This method should be used if you are awaiting a SOCKS5 Bytestream request as a reply to
+ * another packet (e.g. file transfer).
+ *
+ * @param sessionID to be ignored
+ */
+ public void ignoreBytestreamRequestOnce(String sessionID) {
+ this.ignoredBytestreamRequests.add(sessionID);
+ }
+
+ /**
+ * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the
+ * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and
+ * resetting its internal state, which includes removing this instance from the managers map.
+ *
+ * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(Connection)}.
+ * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
+ */
+ public synchronized void disableService() {
+
+ // remove initiation packet listener
+ this.connection.removePacketListener(this.initiationListener);
+
+ // shutdown threads
+ this.initiationListener.shutdown();
+
+ // clear listeners
+ this.allRequestListeners.clear();
+ this.userListeners.clear();
+
+ // reset internal state
+ this.lastWorkingProxy = null;
+ this.proxyBlacklist.clear();
+ this.ignoredBytestreamRequests.clear();
+
+ // remove manager from static managers map
+ managers.remove(this.connection);
+
+ // shutdown local SOCKS5 proxy if there are no more managers for other connections
+ if (managers.size() == 0) {
+ Socks5Proxy.getSocks5Proxy().stop();
+ }
+
+ // remove feature from service discovery
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+
+ // check if service discovery is not already disposed by connection shutdown
+ if (serviceDiscoveryManager != null) {
+ serviceDiscoveryManager.removeFeature(NAMESPACE);
+ }
+
+ }
+
+ /**
+ * Returns the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
+ * Default is 10000ms.
+ *
+ * @return the timeout to wait for the response to the SOCKS5 Bytestream initialization request
+ */
+ public int getTargetResponseTimeout() {
+ if (this.targetResponseTimeout <= 0) {
+ this.targetResponseTimeout = 10000;
+ }
+ return targetResponseTimeout;
+ }
+
+ /**
+ * Sets the timeout to wait for the response to the SOCKS5 Bytestream initialization request.
+ * Default is 10000ms.
+ *
+ * @param targetResponseTimeout the timeout to set
+ */
+ public void setTargetResponseTimeout(int targetResponseTimeout) {
+ this.targetResponseTimeout = targetResponseTimeout;
+ }
+
+ /**
+ * Returns the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
+ * 10000ms.
+ *
+ * @return the timeout for connecting to the SOCKS5 proxy selected by the target
+ */
+ public int getProxyConnectionTimeout() {
+ if (this.proxyConnectionTimeout <= 0) {
+ this.proxyConnectionTimeout = 10000;
+ }
+ return proxyConnectionTimeout;
+ }
+
+ /**
+ * Sets the timeout for connecting to the SOCKS5 proxy selected by the target. Default is
+ * 10000ms.
+ *
+ * @param proxyConnectionTimeout the timeout to set
+ */
+ public void setProxyConnectionTimeout(int proxyConnectionTimeout) {
+ this.proxyConnectionTimeout = proxyConnectionTimeout;
+ }
+
+ /**
+ * Returns if the prioritization of the last working SOCKS5 proxy on successive SOCKS5
+ * Bytestream connections is enabled. Default is
+ * Use this method to establish SOCKS5 Bytestreams to users accepting all incoming Socks5
+ * bytestream requests since this method doesn't provide a way to tell the user something about
+ * the data to be sent.
+ *
+ * To establish a SOCKS5 Bytestream after negotiation the kind of data to be sent (e.g. file
+ * transfer) use {@link #establishSession(String, String)}.
+ *
+ * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
+ * @return the Socket to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
+ * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
+ * @throws IOException if the bytestream could not be established
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession establishSession(String targetJID) throws XMPPException,
+ IOException, InterruptedException {
+ String sessionID = getNextSessionID();
+ return establishSession(targetJID, sessionID);
+ }
+
+ /**
+ * Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns
+ * the Socket to send/receive data to/from the user.
+ *
+ * @param targetJID the JID of the user a SOCKS5 Bytestream should be established
+ * @param sessionID the session ID for the SOCKS5 Bytestream request
+ * @return the Socket to send/receive data to/from the user
+ * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5
+ * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies
+ * @throws IOException if the bytestream could not be established
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
+ throws XMPPException, IOException, InterruptedException {
+
+ XMPPException discoveryException = null;
+ // check if target supports SOCKS5 Bytestream
+ if (!supportsSocks5(targetJID)) {
+ throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream");
+ }
+
+ List
- * Setting the connection failure threshold to zero disables the blacklisting.
- *
- * @param connectFailureThreshold the number of connection failures it takes for a particular
- * SOCKS5 proxy to be blacklisted
- */
- public static void setConnectFailureThreshold(int connectFailureThreshold) {
- CONNECTION_FAILURE_THRESHOLD = connectFailureThreshold;
- }
-
- /**
- * Creates a new Socks5BytestreamRequest.
- *
- * @param manager the SOCKS5 Bytestream manager
- * @param bytestreamRequest the SOCKS5 Bytestream initialization packet
- */
- protected Socks5BytestreamRequest(Socks5BytestreamManager manager, Bytestream bytestreamRequest) {
- this.manager = manager;
- this.bytestreamRequest = bytestreamRequest;
- }
-
- /**
- * Returns the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
- *
- * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
- * by the initiator until a connection is established. This timeout divided by the number of
- * SOCKS5 proxies determines the timeout for every connection attempt.
- *
- * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
- * {@link #setMinimumConnectTimeout(int)}.
- *
- * @return the maximum timeout to connect to SOCKS5 proxies
- */
- public int getTotalConnectTimeout() {
- if (this.totalConnectTimeout <= 0) {
- return 10000;
- }
- return this.totalConnectTimeout;
- }
-
- /**
- * Sets the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
- *
- * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
- * by the initiator until a connection is established. This timeout divided by the number of
- * SOCKS5 proxies determines the timeout for every connection attempt.
- *
- * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
- * {@link #setMinimumConnectTimeout(int)}.
- *
- * @param totalConnectTimeout the maximum timeout to connect to SOCKS5 proxies
- */
- public void setTotalConnectTimeout(int totalConnectTimeout) {
- this.totalConnectTimeout = totalConnectTimeout;
- }
-
- /**
- * Returns the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
- * request. Default is 2000ms.
- *
- * @return the timeout to connect to one SOCKS5 proxy
- */
- public int getMinimumConnectTimeout() {
- if (this.minimumConnectTimeout <= 0) {
- return 2000;
- }
- return this.minimumConnectTimeout;
- }
-
- /**
- * Sets the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
- * request. Default is 2000ms.
- *
- * @param minimumConnectTimeout the timeout to connect to one SOCKS5 proxy
- */
- public void setMinimumConnectTimeout(int minimumConnectTimeout) {
- this.minimumConnectTimeout = minimumConnectTimeout;
- }
-
- /**
- * Returns the sender of the SOCKS5 Bytestream initialization request.
- *
- * @return the sender of the SOCKS5 Bytestream initialization request.
- */
- public String getFrom() {
- return this.bytestreamRequest.getFrom();
- }
-
- /**
- * Returns the session ID of the SOCKS5 Bytestream initialization request.
- *
- * @return the session ID of the SOCKS5 Bytestream initialization request.
- */
- public String getSessionID() {
- return this.bytestreamRequest.getSessionID();
- }
-
- /**
- * Accepts the SOCKS5 Bytestream initialization request and returns the socket to send/receive
- * data.
- *
- * Before accepting the SOCKS5 Bytestream request you can set timeouts by invoking
- * {@link #setTotalConnectTimeout(int)} and {@link #setMinimumConnectTimeout(int)}.
- *
- * @return the socket to send/receive data
- * @throws XMPPException if connection to all SOCKS5 proxies failed or if stream is invalid.
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socks5BytestreamSession accept() throws XMPPException, InterruptedException {
- Collection
+ * Setting the connection failure threshold to zero disables the blacklisting.
+ *
+ * @param connectFailureThreshold the number of connection failures it takes for a particular
+ * SOCKS5 proxy to be blacklisted
+ */
+ public static void setConnectFailureThreshold(int connectFailureThreshold) {
+ CONNECTION_FAILURE_THRESHOLD = connectFailureThreshold;
+ }
+
+ /**
+ * Creates a new Socks5BytestreamRequest.
+ *
+ * @param manager the SOCKS5 Bytestream manager
+ * @param bytestreamRequest the SOCKS5 Bytestream initialization packet
+ */
+ protected Socks5BytestreamRequest(Socks5BytestreamManager manager, Bytestream bytestreamRequest) {
+ this.manager = manager;
+ this.bytestreamRequest = bytestreamRequest;
+ }
+
+ /**
+ * Returns the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
+ *
+ * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
+ * by the initiator until a connection is established. This timeout divided by the number of
+ * SOCKS5 proxies determines the timeout for every connection attempt.
+ *
+ * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
+ * {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @return the maximum timeout to connect to SOCKS5 proxies
+ */
+ public int getTotalConnectTimeout() {
+ if (this.totalConnectTimeout <= 0) {
+ return 10000;
+ }
+ return this.totalConnectTimeout;
+ }
+
+ /**
+ * Sets the maximum timeout to connect to SOCKS5 proxies. Default is 10000ms.
+ *
+ * When accepting a SOCKS5 Bytestream request Smack tries to connect to all SOCKS5 proxies given
+ * by the initiator until a connection is established. This timeout divided by the number of
+ * SOCKS5 proxies determines the timeout for every connection attempt.
+ *
+ * You can set the minimum timeout for establishing a connection to one SOCKS5 proxy by invoking
+ * {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @param totalConnectTimeout the maximum timeout to connect to SOCKS5 proxies
+ */
+ public void setTotalConnectTimeout(int totalConnectTimeout) {
+ this.totalConnectTimeout = totalConnectTimeout;
+ }
+
+ /**
+ * Returns the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
+ * request. Default is 2000ms.
+ *
+ * @return the timeout to connect to one SOCKS5 proxy
+ */
+ public int getMinimumConnectTimeout() {
+ if (this.minimumConnectTimeout <= 0) {
+ return 2000;
+ }
+ return this.minimumConnectTimeout;
+ }
+
+ /**
+ * Sets the timeout to connect to one SOCKS5 proxy while accepting the SOCKS5 Bytestream
+ * request. Default is 2000ms.
+ *
+ * @param minimumConnectTimeout the timeout to connect to one SOCKS5 proxy
+ */
+ public void setMinimumConnectTimeout(int minimumConnectTimeout) {
+ this.minimumConnectTimeout = minimumConnectTimeout;
+ }
+
+ /**
+ * Returns the sender of the SOCKS5 Bytestream initialization request.
+ *
+ * @return the sender of the SOCKS5 Bytestream initialization request.
+ */
+ public String getFrom() {
+ return this.bytestreamRequest.getFrom();
+ }
+
+ /**
+ * Returns the session ID of the SOCKS5 Bytestream initialization request.
+ *
+ * @return the session ID of the SOCKS5 Bytestream initialization request.
+ */
+ public String getSessionID() {
+ return this.bytestreamRequest.getSessionID();
+ }
+
+ /**
+ * Accepts the SOCKS5 Bytestream initialization request and returns the socket to send/receive
+ * data.
+ *
+ * Before accepting the SOCKS5 Bytestream request you can set timeouts by invoking
+ * {@link #setTotalConnectTimeout(int)} and {@link #setMinimumConnectTimeout(int)}.
+ *
+ * @return the socket to send/receive data
+ * @throws XMPPException if connection to all SOCKS5 proxies failed or if stream is invalid.
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socks5BytestreamSession accept() throws XMPPException, InterruptedException {
+ Collection
- * Returns
- * (see RFC1928)
- *
- * @return SOCKS5 connection request message
- */
- private byte[] createSocks5ConnectRequest() {
- byte addr[] = this.digest.getBytes();
-
- byte[] data = new byte[7 + addr.length];
- data[0] = (byte) 0x05; // version (SOCKS5)
- data[1] = (byte) 0x01; // command (1 - connect)
- data[2] = (byte) 0x00; // reserved byte (always 0)
- data[3] = (byte) 0x03; // address type (3 - domain name)
- data[4] = (byte) addr.length; // address length
- System.arraycopy(addr, 0, data, 5, addr.length); // address
- data[data.length - 2] = (byte) 0; // address port (2 bytes always 0)
- data[data.length - 1] = (byte) 0;
-
- return data;
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+
+/**
+ * The SOCKS5 client class handles establishing a connection to a SOCKS5 proxy. Connecting to a
+ * SOCKS5 proxy requires authentication. This implementation only supports the no-authentication
+ * authentication method.
+ *
+ * @author Henning Staib
+ */
+class Socks5Client {
+
+ /* stream host containing network settings and name of the SOCKS5 proxy */
+ protected StreamHost streamHost;
+
+ /* SHA-1 digest identifying the SOCKS5 stream */
+ protected String digest;
+
+ /**
+ * Constructor for a SOCKS5 client.
+ *
+ * @param streamHost containing network settings of the SOCKS5 proxy
+ * @param digest identifying the SOCKS5 Bytestream
+ */
+ public Socks5Client(StreamHost streamHost, String digest) {
+ this.streamHost = streamHost;
+ this.digest = digest;
+ }
+
+ /**
+ * Returns the initialized socket that can be used to transfer data between peers via the SOCKS5
+ * proxy.
+ *
+ * @param timeout timeout to connect to SOCKS5 proxy in milliseconds
+ * @return socket the initialized socket
+ * @throws IOException if initializing the socket failed due to a network error
+ * @throws XMPPException if establishing connection to SOCKS5 proxy failed
+ * @throws TimeoutException if connecting to SOCKS5 proxy timed out
+ * @throws InterruptedException if the current thread was interrupted while waiting
+ */
+ public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
+ TimeoutException {
+
+ // wrap connecting in future for timeout
+ FutureTask
+ * Returns
+ * (see RFC1928)
+ *
+ * @return SOCKS5 connection request message
+ */
+ private byte[] createSocks5ConnectRequest() {
+ byte addr[] = this.digest.getBytes();
+
+ byte[] data = new byte[7 + addr.length];
+ data[0] = (byte) 0x05; // version (SOCKS5)
+ data[1] = (byte) 0x01; // command (1 - connect)
+ data[2] = (byte) 0x00; // reserved byte (always 0)
+ data[3] = (byte) 0x03; // address type (3 - domain name)
+ data[4] = (byte) addr.length; // address length
+ System.arraycopy(addr, 0, data, 5, addr.length); // address
+ data[data.length - 2] = (byte) 0; // address port (2 bytes always 0)
+ data[data.length - 1] = (byte) 0;
+
+ return data;
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
index 385ae5d8e..1359bd4e1 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
@@ -1,120 +1,120 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.Connection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.util.SyncPacketSend;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-
-/**
- * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
- * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
- * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
- * the peers.
- *
- * @author Henning Staib
- */
-class Socks5ClientForInitiator extends Socks5Client {
-
- /* the XMPP connection used to communicate with the SOCKS5 proxy */
- private Connection connection;
-
- /* the session ID used to activate SOCKS5 stream */
- private String sessionID;
-
- /* the target JID used to activate SOCKS5 stream */
- private String target;
-
- /**
- * Creates a new SOCKS5 client for the initiators side.
- *
- * @param streamHost containing network settings of the SOCKS5 proxy
- * @param digest identifying the SOCKS5 Bytestream
- * @param connection the XMPP connection
- * @param sessionID the session ID of the SOCKS5 Bytestream
- * @param target the target JID of the SOCKS5 Bytestream
- */
- public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection,
- String sessionID, String target) {
- super(streamHost, digest);
- this.connection = connection;
- this.sessionID = sessionID;
- this.target = target;
- }
-
- public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
- TimeoutException {
- Socket socket = null;
-
- // check if stream host is the local SOCKS5 proxy
- if (this.streamHost.getJID().equals(this.connection.getUser())) {
- Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
- socket = socks5Server.getSocket(this.digest);
- if (socket == null) {
- throw new XMPPException("target is not connected to SOCKS5 proxy");
- }
- }
- else {
- socket = super.getSocket(timeout);
-
- try {
- activate();
- }
- catch (XMPPException e) {
- socket.close();
- throw new XMPPException("activating SOCKS5 Bytestream failed", e);
- }
-
- }
-
- return socket;
- }
-
- /**
- * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the
- * SOCKS5 proxy.
- */
- private void activate() throws XMPPException {
- Bytestream activate = createStreamHostActivation();
- // if activation fails #getReply throws an exception
- SyncPacketSend.getReply(this.connection, activate);
- }
-
- /**
- * Returns a SOCKS5 Bytestream activation packet.
- *
- * @return SOCKS5 Bytestream activation packet
- */
- private Bytestream createStreamHostActivation() {
- Bytestream activate = new Bytestream(this.sessionID);
- activate.setMode(null);
- activate.setType(IQ.Type.SET);
- activate.setTo(this.streamHost.getJID());
-
- activate.setToActivate(this.target);
-
- return activate;
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.socks5;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.concurrent.TimeoutException;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
+import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
+
+/**
+ * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
+ * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
+ * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
+ * the peers.
+ *
+ * @author Henning Staib
+ */
+class Socks5ClientForInitiator extends Socks5Client {
+
+ /* the XMPP connection used to communicate with the SOCKS5 proxy */
+ private Connection connection;
+
+ /* the session ID used to activate SOCKS5 stream */
+ private String sessionID;
+
+ /* the target JID used to activate SOCKS5 stream */
+ private String target;
+
+ /**
+ * Creates a new SOCKS5 client for the initiators side.
+ *
+ * @param streamHost containing network settings of the SOCKS5 proxy
+ * @param digest identifying the SOCKS5 Bytestream
+ * @param connection the XMPP connection
+ * @param sessionID the session ID of the SOCKS5 Bytestream
+ * @param target the target JID of the SOCKS5 Bytestream
+ */
+ public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection,
+ String sessionID, String target) {
+ super(streamHost, digest);
+ this.connection = connection;
+ this.sessionID = sessionID;
+ this.target = target;
+ }
+
+ public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
+ TimeoutException {
+ Socket socket = null;
+
+ // check if stream host is the local SOCKS5 proxy
+ if (this.streamHost.getJID().equals(this.connection.getUser())) {
+ Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
+ socket = socks5Server.getSocket(this.digest);
+ if (socket == null) {
+ throw new XMPPException("target is not connected to SOCKS5 proxy");
+ }
+ }
+ else {
+ socket = super.getSocket(timeout);
+
+ try {
+ activate();
+ }
+ catch (XMPPException e) {
+ socket.close();
+ throw new XMPPException("activating SOCKS5 Bytestream failed", e);
+ }
+
+ }
+
+ return socket;
+ }
+
+ /**
+ * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the
+ * SOCKS5 proxy.
+ */
+ private void activate() throws XMPPException {
+ Bytestream activate = createStreamHostActivation();
+ // if activation fails #getReply throws an exception
+ SyncPacketSend.getReply(this.connection, activate);
+ }
+
+ /**
+ * Returns a SOCKS5 Bytestream activation packet.
+ *
+ * @return SOCKS5 Bytestream activation packet
+ */
+ private Bytestream createStreamHostActivation() {
+ Bytestream activate = new Bytestream(this.sessionID);
+ activate.setMode(null);
+ activate.setType(IQ.Type.SET);
+ activate.setTo(this.streamHost.getJID());
+
+ activate.setToActivate(this.target);
+
+ return activate;
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
index bfc9d35ec..cbe4cc971 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java
@@ -1,428 +1,428 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-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;
-
-import org.jivesoftware.smack.SmackConfiguration;
-import org.jivesoftware.smack.XMPPException;
-
-/**
- * The Socks5Proxy class represents a local SOCKS5 proxy server. It can be enabled/disabled by
- * setting the
- * The port of the local SOCKS5 proxy can be configured by setting
- * If your application is running on a machine with multiple network interfaces or if you want to
- * provide your public address in case you are behind a NAT router, invoke
- * {@link #addLocalAddress(String)} or {@link #replaceLocalAddresses(List)} to modify the list of
- * local network addresses used for outgoing SOCKS5 Bytestream requests.
- *
- * The local SOCKS5 proxy server refuses all connections except the ones that are explicitly allowed
- * in the process of establishing a SOCKS5 Bytestream (
- * {@link Socks5BytestreamManager#establishSession(String)}).
- *
- * This Implementation has the following limitations:
- *
- * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request.
- * This may be necessary if your application is running on a machine with multiple network
- * interfaces or if you want to provide your public address in case you are behind a NAT router.
- *
- * The order of the addresses used is determined by the order you add addresses.
- *
- * Note that the list of addresses initially contains the address returned by
- *
- * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request and
- * want to define their order. This may be necessary if your application is running on a machine
- * with multiple network interfaces or if you want to provide your public address in case you
- * are behind a NAT router.
- *
- * @param addresses the new list of local network addresses
- */
- public void replaceLocalAddresses(List
- * The digest should be removed after establishing the SOCKS5 Bytestream is finished, an error
- * occurred while establishing the connection or if the connection is not allowed anymore.
- *
- * @param digest to be removed from the list of allowed transfers
- */
- protected void removeTransfer(String digest) {
- this.allowedConnections.remove(digest);
- this.connectionMap.remove(digest);
- }
-
- /**
- * Returns
+ * The port of the local SOCKS5 proxy can be configured by setting
+ * If your application is running on a machine with multiple network interfaces or if you want to
+ * provide your public address in case you are behind a NAT router, invoke
+ * {@link #addLocalAddress(String)} or {@link #replaceLocalAddresses(List)} to modify the list of
+ * local network addresses used for outgoing SOCKS5 Bytestream requests.
+ *
+ * The local SOCKS5 proxy server refuses all connections except the ones that are explicitly allowed
+ * in the process of establishing a SOCKS5 Bytestream (
+ * {@link Socks5BytestreamManager#establishSession(String)}).
+ *
+ * This Implementation has the following limitations:
+ *
+ * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request.
+ * This may be necessary if your application is running on a machine with multiple network
+ * interfaces or if you want to provide your public address in case you are behind a NAT router.
+ *
+ * The order of the addresses used is determined by the order you add addresses.
+ *
+ * Note that the list of addresses initially contains the address returned by
+ *
+ * Use this method if you want to provide multiple addresses in a SOCKS5 Bytestream request and
+ * want to define their order. This may be necessary if your application is running on a machine
+ * with multiple network interfaces or if you want to provide your public address in case you
+ * are behind a NAT router.
+ *
+ * @param addresses the new list of local network addresses
+ */
+ public void replaceLocalAddresses(List
+ * The digest should be removed after establishing the SOCKS5 Bytestream is finished, an error
+ * occurred while establishing the connection or if the connection is not allowed anymore.
+ *
+ * @param digest to be removed from the list of allowed transfers
+ */
+ protected void removeTransfer(String digest) {
+ this.allowedConnections.remove(digest);
+ this.connectionMap.remove(digest);
+ }
+
+ /**
+ * Returns
- * (see RFC1928)
- *
- * @param in the DataInputStream to read the message from
- * @return the SOCKS5 message
- * @throws IOException if a network error occurred
- * @throws XMPPException if the SOCKS5 message contains an unsupported address type
- */
- public static byte[] receiveSocks5Message(DataInputStream in) throws IOException, XMPPException {
- byte[] header = new byte[5];
- in.readFully(header, 0, 5);
-
- if (header[3] != (byte) 0x03) {
- throw new XMPPException("Unsupported SOCKS5 address type");
- }
-
- int addressLength = header[4];
-
- byte[] response = new byte[7 + addressLength];
- System.arraycopy(header, 0, response, 0, header.length);
-
- in.readFully(response, header.length, addressLength + 2);
-
- return response;
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * A collection of utility methods for SOcKS5 messages.
+ *
+ * @author Henning Staib
+ */
+class Socks5Utils {
+
+ /**
+ * Returns a SHA-1 digest of the given parameters as specified in XEP-0065.
+ *
+ * @param sessionID for the SOCKS5 Bytestream
+ * @param initiatorJID JID of the initiator of a SOCKS5 Bytestream
+ * @param targetJID JID of the target of a SOCKS5 Bytestream
+ * @return SHA-1 digest of the given parameters
+ */
+ public static String createDigest(String sessionID, String initiatorJID, String targetJID) {
+ StringBuilder b = new StringBuilder();
+ b.append(sessionID).append(initiatorJID).append(targetJID);
+ return StringUtils.hash(b.toString());
+ }
+
+ /**
+ * Reads a SOCKS5 message from the given InputStream. The message can either be a SOCKS5 request
+ * message or a SOCKS5 response message.
+ *
+ * (see RFC1928)
+ *
+ * @param in the DataInputStream to read the message from
+ * @return the SOCKS5 message
+ * @throws IOException if a network error occurred
+ * @throws XMPPException if the SOCKS5 message contains an unsupported address type
+ */
+ public static byte[] receiveSocks5Message(DataInputStream in) throws IOException, XMPPException {
+ byte[] header = new byte[5];
+ in.readFully(header, 0, 5);
+
+ if (header[3] != (byte) 0x03) {
+ throw new XMPPException("Unsupported SOCKS5 address type");
+ }
+
+ int addressLength = header[4];
+
+ byte[] response = new byte[7 + addressLength];
+ System.arraycopy(header, 0, response, 0, header.length);
+
+ in.readFully(response, header.length, addressLength + 2);
+
+ return response;
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
index 8efba8bee..fba74539f 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
@@ -1,477 +1,477 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5.packet;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-
-/**
- * A packet representing part of a SOCKS5 Bytestream negotiation.
- *
- * @author Alexander Wenckus
- */
-public class Bytestream extends IQ {
-
- private String sessionID;
-
- private Mode mode = Mode.tcp;
-
- private final List
- *
- *
- * @author Gaston Dombiak
- */
-public class StreamError {
-
- public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams";
-
- private String code;
- private String text;
-
- public StreamError(String code) {
- super();
- this.code = code;
- }
-
- public StreamError(String code, String text) {
- this(code);
- this.text = text;
- }
-
- /**
- * Returns the error code.
- *
- * @return the error code.
- */
- public String getCode() {
- return code;
- }
-
- /**
- * Returns the error text, which may be null.
- *
- * @return the error text.
- */
- public String getText() {
- return text;
- }
-
- public String toString() {
- StringBuilder txt = new StringBuilder();
- txt.append("stream:error (").append(code).append(")");
- if (text != null) txt.append(" text: ").append(text);
- return txt.toString();
- }
-}
+/**
+ *
+ * Copyright 2003-2005 Jive Software.
+ *
+ * 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.smack.packet;
+
+/**
+ * Represents a stream error packet. Stream errors are unrecoverable errors where the server
+ * will close the unrelying TCP connection after the stream error was sent to the client.
+ * These is the list of stream errors as defined in the XMPP spec:
- * Code Description
- * bad-format the entity has sent XML that cannot be processed
- * unsupported-encoding the entity has sent a namespace prefix that is
- * unsupported
- * bad-namespace-prefix Remote Server Timeout
- * conflict the server is closing the active stream for this entity
- * because a new stream has been initiated that conflicts with the existing
- * stream.
- * connection-timeout the entity has not generated any traffic over
- * the stream for some period of time.
- * host-gone the value of the 'to' attribute provided by the initiating
- * entity in the stream header corresponds to a hostname that is no longer hosted by
- * the server.
- * host-unknown the value of the 'to' attribute provided by the
- * initiating entity in the stream header does not correspond to a hostname that is
- * hosted by the server.
- * improper-addressing a stanza sent between two servers lacks a 'to'
- * or 'from' attribute
- * internal-server-error the server has experienced a
- * misconfiguration.
- * invalid-from the JID or hostname provided in a 'from' address does
- * not match an authorized JID.
- * invalid-namespace the streams namespace name is invalid.
- * invalid-xml the entity has sent invalid XML over the stream.
- * not-authorized the entity has attempted to send data before the
- * stream has been authenticated
- * policy-violation the entity has violated some local service
- * policy.
- * remote-connection-failed Rthe server is unable to properly connect
- * to a remote entity.
- * resource-constraint Rthe server lacks the system resources necessary
- * to service the stream.
- * restricted-xml the entity has attempted to send restricted XML
- * features.
- * see-other-host the server will not provide service to the initiating
- * entity but is redirecting traffic to another host.
- * system-shutdown the server is being shut down and all active streams
- * are being closed.
- * undefined-condition the error condition is not one of those defined
- * by the other conditions in this list.
- * unsupported-encoding the initiating entity has encoded the stream in
- * an encoding that is not supported.
- * unsupported-stanza-type the initiating entity has sent a first-level
- * child of the stream that is not supported.
- * unsupported-version the value of the 'version' attribute provided by
- * the initiating entity in the stream header specifies a version of XMPP that is not
- * supported.
- * not-well-formed the initiating entity has sent XML that is not
- * well-formed.
+ *
+ *
+ * @author Gaston Dombiak
+ */
+public class StreamError {
+
+ public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams";
+
+ private String code;
+ private String text;
+
+ public StreamError(String code) {
+ super();
+ this.code = code;
+ }
+
+ public StreamError(String code, String text) {
+ this(code);
+ this.text = text;
+ }
+
+ /**
+ * Returns the error code.
+ *
+ * @return the error code.
+ */
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * Returns the error text, which may be null.
+ *
+ * @return the error text.
+ */
+ public String getText() {
+ return text;
+ }
+
+ public String toString() {
+ StringBuilder txt = new StringBuilder();
+ txt.append("stream:error (").append(code).append(")");
+ if (text != null) txt.append(" text: ").append(text);
+ return txt.toString();
+ }
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/provider/AbstractProviderInfo.java b/core/src/main/java/org/jivesoftware/smack/provider/AbstractProviderInfo.java
index c783bb6ac..7aa26172f 100644
--- a/core/src/main/java/org/jivesoftware/smack/provider/AbstractProviderInfo.java
+++ b/core/src/main/java/org/jivesoftware/smack/provider/AbstractProviderInfo.java
@@ -1,41 +1,41 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.smack.provider;
-
-abstract class AbstractProviderInfo {
- private String element;
- private String ns;
- private Object provider;
-
- AbstractProviderInfo(String elementName, String namespace, Object iqOrExtProvider) {
- element = elementName;
- ns = namespace;
- provider = iqOrExtProvider;
- }
-
- public String getElementName() {
- return element;
- }
-
- public String getNamespace() {
- return ns;
- }
-
- Object getProvider() {
- return provider;
- }
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.smack.provider;
+
+abstract class AbstractProviderInfo {
+ private String element;
+ private String ns;
+ private Object provider;
+
+ AbstractProviderInfo(String elementName, String namespace, Object iqOrExtProvider) {
+ element = elementName;
+ ns = namespace;
+ provider = iqOrExtProvider;
+ }
+
+ public String getElementName() {
+ return element;
+ }
+
+ public String getNamespace() {
+ return ns;
+ }
+
+ Object getProvider() {
+ return provider;
+ }
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java b/core/src/main/java/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
index e8ee87476..7e7e63fcf 100644
--- a/core/src/main/java/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
+++ b/core/src/main/java/org/jivesoftware/smack/provider/EmbeddedExtensionProvider.java
@@ -1,109 +1,109 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.smack.provider;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.provider.PacketExtensionProvider;
-import org.jivesoftware.smack.util.PacketParserUtils;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- *
- * This class simplifies parsing of embedded elements by using the
- * Template Method Pattern.
- * After extracting the current element attributes and content of any child elements, the template method
- * ({@link #createReturnExtension(String, String, Map, List)} is called. Subclasses
- * then override this method to create the specific return type.
- *
- *
+ * Code Description
+ * bad-format the entity has sent XML that cannot be processed
+ * unsupported-encoding the entity has sent a namespace prefix that is
+ * unsupported
+ * bad-namespace-prefix Remote Server Timeout
+ * conflict the server is closing the active stream for this entity
+ * because a new stream has been initiated that conflicts with the existing
+ * stream.
+ * connection-timeout the entity has not generated any traffic over
+ * the stream for some period of time.
+ * host-gone the value of the 'to' attribute provided by the initiating
+ * entity in the stream header corresponds to a hostname that is no longer hosted by
+ * the server.
+ * host-unknown the value of the 'to' attribute provided by the
+ * initiating entity in the stream header does not correspond to a hostname that is
+ * hosted by the server.
+ * improper-addressing a stanza sent between two servers lacks a 'to'
+ * or 'from' attribute
+ * internal-server-error the server has experienced a
+ * misconfiguration.
+ * invalid-from the JID or hostname provided in a 'from' address does
+ * not match an authorized JID.
+ * invalid-namespace the streams namespace name is invalid.
+ * invalid-xml the entity has sent invalid XML over the stream.
+ * not-authorized the entity has attempted to send data before the
+ * stream has been authenticated
+ * policy-violation the entity has violated some local service
+ * policy.
+ * remote-connection-failed Rthe server is unable to properly connect
+ * to a remote entity.
+ * resource-constraint Rthe server lacks the system resources necessary
+ * to service the stream.
+ * restricted-xml the entity has attempted to send restricted XML
+ * features.
+ * see-other-host the server will not provide service to the initiating
+ * entity but is redirecting traffic to another host.
+ * system-shutdown the server is being shut down and all active streams
+ * are being closed.
+ * undefined-condition the error condition is not one of those defined
+ * by the other conditions in this list.
+ * unsupported-encoding the initiating entity has encoded the stream in
+ * an encoding that is not supported.
+ * unsupported-stanza-type the initiating entity has sent a first-level
+ * child of the stream that is not supported.
+ * unsupported-version the value of the 'version' attribute provided by
+ * the initiating entity in the stream header specifies a version of XMPP that is not
+ * supported.
+ * not-well-formed the initiating entity has sent XML that is not
+ * well-formed.
- * For example, given the following message
- *
- * <message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo>
- * <event xmlns='http://jabber.org/protocol/pubsub#event>
- * <items node='princely_musings'>
- * <item id='asdjkwei3i34234n356'>
- * <entry xmlns='http://www.w3.org/2005/Atom'>
- * <title>Soliloquy</title>
- * <link rel='alternative' type='text/html'/>
- * <id>tag:denmark.lit,2003:entry-32397</id>
- * </entry>
- * </item>
- * </items>
- * </event>
- * </message>
- *
- * I would have a classes
- * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
- * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
- * and
- * AtomProvider extends {@link PacketExtensionProvider}
- *
- * These classes are then registered in the meta-inf/smack.providers file
- * as follows.
- *
- * <extensionProvider>
- * <elementName>items</elementName>
- * <namespace>http://jabber.org/protocol/pubsub#event</namespace>
- * <className>org.jivesoftware.smackx.provider.ItemsEventProvider</className>
- * </extensionProvider>
- * <extensionProvider>
- * <elementName>item</elementName>
- * <namespace>http://jabber.org/protocol/pubsub#event</namespace>
- * <className>org.jivesoftware.smackx.provider.ItemProvider</className>
- * </extensionProvider>
- *
- *
- *
- * @author Robin Collier
- */
-abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
-{
-
- final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
- {
- String namespace = parser.getNamespace();
- String name = parser.getName();
- Map
+ * For example, given the following message
+ *
+ * <message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo>
+ * <event xmlns='http://jabber.org/protocol/pubsub#event>
+ * <items node='princely_musings'>
+ * <item id='asdjkwei3i34234n356'>
+ * <entry xmlns='http://www.w3.org/2005/Atom'>
+ * <title>Soliloquy</title>
+ * <link rel='alternative' type='text/html'/>
+ * <id>tag:denmark.lit,2003:entry-32397</id>
+ * </entry>
+ * </item>
+ * </items>
+ * </event>
+ * </message>
+ *
+ * I would have a classes
+ * {@link ItemsProvider} extends {@link EmbeddedExtensionProvider}
+ * {@link ItemProvider} extends {@link EmbeddedExtensionProvider}
+ * and
+ * AtomProvider extends {@link PacketExtensionProvider}
+ *
+ * These classes are then registered in the meta-inf/smack.providers file
+ * as follows.
+ *
+ * <extensionProvider>
+ * <elementName>items</elementName>
+ * <namespace>http://jabber.org/protocol/pubsub#event</namespace>
+ * <className>org.jivesoftware.smackx.provider.ItemsEventProvider</className>
+ * </extensionProvider>
+ * <extensionProvider>
+ * <elementName>item</elementName>
+ * <namespace>http://jabber.org/protocol/pubsub#event</namespace>
+ * <className>org.jivesoftware.smackx.provider.ItemProvider</className>
+ * </extensionProvider>
+ *
+ *
+ *
+ * @author Robin Collier
+ */
+abstract public class EmbeddedExtensionProvider implements PacketExtensionProvider
+{
+
+ final public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ String namespace = parser.getNamespace();
+ String name = parser.getName();
+ MapPacketExtensionProvider
interface.
- *
- * @param elementName Element that provider parses.
- * @param namespace Namespace that provider parses.
- * @param extProvider The provider implementation.
- */
- public ExtensionProviderInfo(String elementName, String namespace, PacketExtensionProvider extProvider) {
- super(elementName, namespace, extProvider);
- }
-
- /**
- * Defines an extension provider which is adheres to the JavaBean spec for parsing the extension.
- *
- * @param elementName Element that provider parses.
- * @param namespace Namespace that provider parses.
- * @param beanClass The provider bean class.
- */
- public ExtensionProviderInfo(String elementName, String namespace, Class> beanClass) {
- super(elementName, namespace, beanClass);
- }
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.smack.provider;
+
+/**
+ * Defines the information required to register a packet extension Provider with the {@link ProviderManager} when using the
+ * {@link ProviderLoader}.
+ *
+ * @author Robin Collier
+ *
+ */
+public final class ExtensionProviderInfo extends AbstractProviderInfo {
+
+ /**
+ * Defines an extension provider which implements the PacketExtensionProvider
interface.
+ *
+ * @param elementName Element that provider parses.
+ * @param namespace Namespace that provider parses.
+ * @param extProvider The provider implementation.
+ */
+ public ExtensionProviderInfo(String elementName, String namespace, PacketExtensionProvider extProvider) {
+ super(elementName, namespace, extProvider);
+ }
+
+ /**
+ * Defines an extension provider which is adheres to the JavaBean spec for parsing the extension.
+ *
+ * @param elementName Element that provider parses.
+ * @param namespace Namespace that provider parses.
+ * @param beanClass The provider bean class.
+ */
+ public ExtensionProviderInfo(String elementName, String namespace, Class> beanClass) {
+ super(elementName, namespace, beanClass);
+ }
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/provider/IQProvider.java b/core/src/main/java/org/jivesoftware/smack/provider/IQProvider.java
index f2ac95f41..aaa099b91 100644
--- a/core/src/main/java/org/jivesoftware/smack/provider/IQProvider.java
+++ b/core/src/main/java/org/jivesoftware/smack/provider/IQProvider.java
@@ -41,4 +41,4 @@ public interface IQProvider {
* @throws Exception if an error occurs parsing the XML.
*/
public IQ parseIQ(XmlPullParser parser) throws Exception;
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/provider/IQProviderInfo.java b/core/src/main/java/org/jivesoftware/smack/provider/IQProviderInfo.java
index 264618596..9265c32e2 100644
--- a/core/src/main/java/org/jivesoftware/smack/provider/IQProviderInfo.java
+++ b/core/src/main/java/org/jivesoftware/smack/provider/IQProviderInfo.java
@@ -1,51 +1,51 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.smack.provider;
-
-import org.jivesoftware.smack.packet.IQ;
-
-/**
- * Defines the information required to register an IQ Provider with the {@link ProviderManager} when using the
- * {@link ProviderLoader}.
- *
- * @author Robin Collier
- *
- */
-public final class IQProviderInfo extends AbstractProviderInfo {
-
- /**
- * Defines an IQ provider which implements the IQProvider
interface.
- *
- * @param elementName Element that provider parses.
- * @param namespace Namespace that provider parses.
- * @param iqProvider The provider implementation.
- */
- public IQProviderInfo(String elementName, String namespace, IQProvider iqProvider) {
- super(elementName, namespace, iqProvider);
- }
-
- /**
- * Defines an IQ class which can be used as a provider via introspection.
- *
- * @param elementName Element that provider parses.
- * @param namespace Namespace that provider parses.
- * @param iqProviderClass The IQ class being parsed.
- */
- public IQProviderInfo(String elementName, String namespace, Class extends IQ> iqProviderClass) {
- super(elementName, namespace, iqProviderClass);
- }
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.smack.provider;
+
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * Defines the information required to register an IQ Provider with the {@link ProviderManager} when using the
+ * {@link ProviderLoader}.
+ *
+ * @author Robin Collier
+ *
+ */
+public final class IQProviderInfo extends AbstractProviderInfo {
+
+ /**
+ * Defines an IQ provider which implements the IQProvider
interface.
+ *
+ * @param elementName Element that provider parses.
+ * @param namespace Namespace that provider parses.
+ * @param iqProvider The provider implementation.
+ */
+ public IQProviderInfo(String elementName, String namespace, IQProvider iqProvider) {
+ super(elementName, namespace, iqProvider);
+ }
+
+ /**
+ * Defines an IQ class which can be used as a provider via introspection.
+ *
+ * @param elementName Element that provider parses.
+ * @param namespace Namespace that provider parses.
+ * @param iqProviderClass The IQ class being parsed.
+ */
+ public IQProviderInfo(String elementName, String namespace, Class extends IQ> iqProviderClass) {
+ super(elementName, namespace, iqProviderClass);
+ }
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java b/core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java
index 8798948b8..d8b9e6109 100644
--- a/core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java
+++ b/core/src/main/java/org/jivesoftware/smack/provider/ProviderFileLoader.java
@@ -1,172 +1,172 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.smack.provider;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.xmlpull.mxp1.MXParser;
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Loads the {@link IQProvider} and {@link PacketExtensionProvider} information from a standard provider file in preparation
- * for loading into the {@link ProviderManager}.
- *
- * @author Robin Collier
- *
- */
-public class ProviderFileLoader implements ProviderLoader {
- private final static Logger log = Logger.getLogger(ProviderFileLoader.class.getName());
-
- private CollectionProviderManager
.
- * @return The IQ provider info to load.
- */
- CollectionProviderManager
.
- * @return The extension provider info to load.
- */
- CollectionProviderManager
.
+ * @return The IQ provider info to load.
+ */
+ CollectionProviderManager
.
+ * @return The extension provider info to load.
+ */
+ Collection
- *
- *
- * Then, when the server requests or requires the client certificate, java will
- * simply provide the one in the keyStore.
- *
- * Also worth noting is the EXTERNAL mechanism in Smack is not enabled by default.
- * To enable it, the implementer will need to call SASLAuthentication.supportSASLMechamism("EXTERNAL");
- *
- * @author Jay Kline
- */
-public class SASLExternalMechanism extends SASLMechanism {
-
- public SASLExternalMechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
- }
-
- protected String getName() {
- return "EXTERNAL";
- }
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.smack.sasl;
+
+import org.jivesoftware.smack.SASLAuthentication;
+
+/**
+ * Implementation of the SASL EXTERNAL mechanism.
+ *
+ * To effectively use this mechanism, Java must be configured to properly
+ * supply a client SSL certificate (of some sort) to the server. It is up
+ * to the implementer to determine how to do this. Here is one method:
+ *
+ * Create a java keystore with your SSL certificate in it:
+ * keytool -genkey -alias username -dname "cn=username,ou=organizationalUnit,o=organizationaName,l=locality,s=state,c=country"
+ *
+ * Next, set the System Properties:
+ *
+ *
+ *
+ * Then, when the server requests or requires the client certificate, java will
+ * simply provide the one in the keyStore.
+ *
+ * Also worth noting is the EXTERNAL mechanism in Smack is not enabled by default.
+ * To enable it, the implementer will need to call SASLAuthentication.supportSASLMechamism("EXTERNAL");
+ *
+ * @author Jay Kline
+ */
+public class SASLExternalMechanism extends SASLMechanism {
+
+ public SASLExternalMechanism(SASLAuthentication saslAuthentication) {
+ super(saslAuthentication);
+ }
+
+ protected String getName() {
+ return "EXTERNAL";
+ }
+}
diff --git a/core/src/main/java/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java b/core/src/main/java/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
index c92d95dbf..78f0fac10 100644
--- a/core/src/main/java/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
+++ b/core/src/main/java/org/jivesoftware/smack/sasl/SASLGSSAPIMechanism.java
@@ -1,86 +1,86 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.smack.sasl;
-
-import org.jivesoftware.smack.SASLAuthentication;
-import org.jivesoftware.smack.XMPPException;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-import javax.security.sasl.Sasl;
-import javax.security.auth.callback.CallbackHandler;
-
-/**
- * Implementation of the SASL GSSAPI mechanism
- *
- * @author Jay Kline
- */
-public class SASLGSSAPIMechanism extends SASLMechanism {
-
- public SASLGSSAPIMechanism(SASLAuthentication saslAuthentication) {
- super(saslAuthentication);
-
- System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
- System.setProperty("java.security.auth.login.config","gss.conf");
-
- }
-
- protected String getName() {
- return "GSSAPI";
- }
-
- /**
- * Builds and sends the auth stanza to the server.
- * This overrides from the abstract class because the initial token
- * needed for GSSAPI is binary, and not safe to put in a string, thus
- * getAuthenticationText() cannot be used.
- *
- * @param username the username of the user being authenticated.
- * @param host the hostname where the user account resides.
- * @param cbh the CallbackHandler (not used with GSSAPI)
- * @throws IOException If a network error occures while authenticating.
- */
- public void authenticate(String username, String host, CallbackHandler cbh) throws IOException, XMPPException {
- String[] mechanisms = { getName() };
- Map
- *
- * Subclasses will likely want to implement their own versions of these mthods:
- *
+ *
+ * Subclasses will likely want to implement their own versions of these mthods:
+ *
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * Note: Technically, this makes your encoding non-compliant.
- *
- * encodeObject( myObj, Base64.GZIP )
or
- * encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )
- *
- * @param serializableObject The object to encode
- * @param options Specified options
- * @return The Base64-encoded object
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeObject( java.io.Serializable serializableObject, int options )
- {
- // Streams
- java.io.ByteArrayOutputStream baos = null;
- java.io.OutputStream b64os = null;
- java.io.ObjectOutputStream oos = null;
- java.util.zip.GZIPOutputStream gzos = null;
-
- // Isolate options
- int gzip = (options & GZIP);
-
- try
- {
- // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
- baos = new java.io.ByteArrayOutputStream();
- b64os = new Base64.OutputStream( baos, ENCODE | options );
-
- // GZip?
- if( gzip == GZIP )
- {
- gzos = new java.util.zip.GZIPOutputStream( b64os );
- oos = new java.io.ObjectOutputStream( gzos );
- } // end if: gzip
- else
- oos = new java.io.ObjectOutputStream( b64os );
-
- oos.writeObject( serializableObject );
- } // end try
- catch( java.io.IOException e )
- {
- log.log(Level.SEVERE, "Error encoding object", e);
- return null;
- } // end catch
- finally
- {
- try{ oos.close(); } catch( Exception e ){}
- try{ gzos.close(); } catch( Exception e ){}
- try{ b64os.close(); } catch( Exception e ){}
- try{ baos.close(); } catch( Exception e ){}
- } // end finally
-
- // Return value according to relevant encoding.
- try
- {
- return new String( baos.toByteArray(), PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( baos.toByteArray() );
- } // end catch
-
- } // end encode
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * Does not GZip-compress data.
- *
- * @param source The data to convert
- * @since 1.4
- */
- public static String encodeBytes( byte[] source )
- {
- return encodeBytes( source, 0, source.length, NO_OPTIONS );
- } // end encodeBytes
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- *
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * Note: Technically, this makes your encoding non-compliant.
- *
- * encodeBytes( myData, Base64.GZIP )
or
- * encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
- *
- *
- * @param source The data to convert
- * @param options Specified options
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeBytes( byte[] source, int options )
- {
- return encodeBytes( source, 0, source.length, options );
- } // end encodeBytes
-
-
- /**
- * Encodes a byte array into Base64 notation.
- * Does not GZip-compress data.
- *
- * @param source The data to convert
- * @param off Offset in array where conversion should begin
- * @param len Length of data to convert
- * @since 1.4
- */
- public static String encodeBytes( byte[] source, int off, int len )
- {
- return encodeBytes( source, off, len, NO_OPTIONS );
- } // end encodeBytes
-
-
-
- /**
- * Encodes a byte array into Base64 notation.
- *
- * GZIP: gzip-compresses object before encoding it.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * Note: Technically, this makes your encoding non-compliant.
- *
- * encodeBytes( myData, Base64.GZIP )
or
- * encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
- *
- *
- * @param source The data to convert
- * @param off Offset in array where conversion should begin
- * @param len Length of data to convert
- * @param options Specified options; alphabet type is pulled from this (standard, url-safe, ordered)
- * @see Base64#GZIP
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public static String encodeBytes( byte[] source, int off, int len, int options )
- {
- // Isolate options
- int dontBreakLines = ( options & DONT_BREAK_LINES );
- int gzip = ( options & GZIP );
-
- // Compress?
- if( gzip == GZIP )
- {
- java.io.ByteArrayOutputStream baos = null;
- java.util.zip.GZIPOutputStream gzos = null;
- Base64.OutputStream b64os = null;
-
-
- try
- {
- // GZip -> Base64 -> ByteArray
- baos = new java.io.ByteArrayOutputStream();
- b64os = new Base64.OutputStream( baos, ENCODE | options );
- gzos = new java.util.zip.GZIPOutputStream( b64os );
-
- gzos.write( source, off, len );
- gzos.close();
- } // end try
- catch( java.io.IOException e )
- {
+/**
+ *
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * Note: Technically, this makes your encoding non-compliant.
+ *
+ * encodeObject( myObj, Base64.GZIP )
or
+ * encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ * @param serializableObject The object to encode
+ * @param options Specified options
+ * @return The Base64-encoded object
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeObject( java.io.Serializable serializableObject, int options )
+ {
+ // Streams
+ java.io.ByteArrayOutputStream baos = null;
+ java.io.OutputStream b64os = null;
+ java.io.ObjectOutputStream oos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+
+ // Isolate options
+ int gzip = (options & GZIP);
+
+ try
+ {
+ // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+
+ // GZip?
+ if( gzip == GZIP )
+ {
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+ oos = new java.io.ObjectOutputStream( gzos );
+ } // end if: gzip
+ else
+ oos = new java.io.ObjectOutputStream( b64os );
+
+ oos.writeObject( serializableObject );
+ } // end try
+ catch( java.io.IOException e )
+ {
+ log.log(Level.SEVERE, "Error encoding object", e);
+ return null;
+ } // end catch
+ finally
+ {
+ try{ oos.close(); } catch( Exception e ){}
+ try{ gzos.close(); } catch( Exception e ){}
+ try{ b64os.close(); } catch( Exception e ){}
+ try{ baos.close(); } catch( Exception e ){}
+ } // end finally
+
+ // Return value according to relevant encoding.
+ try
+ {
+ return new String( baos.toByteArray(), PREFERRED_ENCODING );
+ } // end try
+ catch (java.io.UnsupportedEncodingException uue)
+ {
+ return new String( baos.toByteArray() );
+ } // end catch
+
+ } // end encode
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source )
+ {
+ return encodeBytes( source, 0, source.length, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ *
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * Note: Technically, this makes your encoding non-compliant.
+ *
+ * encodeBytes( myData, Base64.GZIP )
or
+ * encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ *
+ * @param source The data to convert
+ * @param options Specified options
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int options )
+ {
+ return encodeBytes( source, 0, source.length, options );
+ } // end encodeBytes
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ * Does not GZip-compress data.
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @since 1.4
+ */
+ public static String encodeBytes( byte[] source, int off, int len )
+ {
+ return encodeBytes( source, off, len, NO_OPTIONS );
+ } // end encodeBytes
+
+
+
+ /**
+ * Encodes a byte array into Base64 notation.
+ *
+ * GZIP: gzip-compresses object before encoding it.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * Note: Technically, this makes your encoding non-compliant.
+ *
+ * encodeBytes( myData, Base64.GZIP )
or
+ * encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )
+ *
+ *
+ * @param source The data to convert
+ * @param off Offset in array where conversion should begin
+ * @param len Length of data to convert
+ * @param options Specified options; alphabet type is pulled from this (standard, url-safe, ordered)
+ * @see Base64#GZIP
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public static String encodeBytes( byte[] source, int off, int len, int options )
+ {
+ // Isolate options
+ int dontBreakLines = ( options & DONT_BREAK_LINES );
+ int gzip = ( options & GZIP );
+
+ // Compress?
+ if( gzip == GZIP )
+ {
+ java.io.ByteArrayOutputStream baos = null;
+ java.util.zip.GZIPOutputStream gzos = null;
+ Base64.OutputStream b64os = null;
+
+
+ try
+ {
+ // GZip -> Base64 -> ByteArray
+ baos = new java.io.ByteArrayOutputStream();
+ b64os = new Base64.OutputStream( baos, ENCODE | options );
+ gzos = new java.util.zip.GZIPOutputStream( b64os );
+
+ gzos.write( source, off, len );
+ gzos.close();
+ } // end try
+ catch( java.io.IOException e )
+ {
log.log(Level.SEVERE, "Error encoding bytes", e);
- return null;
- } // end catch
- finally
- {
- try{ gzos.close(); } catch( Exception e ){}
- try{ b64os.close(); } catch( Exception e ){}
- try{ baos.close(); } catch( Exception e ){}
- } // end finally
-
- // Return value according to relevant encoding.
- try
- {
- return new String( baos.toByteArray(), PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( baos.toByteArray() );
- } // end catch
- } // end if: compress
-
- // Else, don't compress. Better not to use streams at all then.
- else
- {
- // Convert option to boolean in way that code likes it.
- boolean breakLines = dontBreakLines == 0;
-
- int len43 = len * 4 / 3;
- byte[] outBuff = new byte[ ( len43 ) // Main 4:3
- + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
- + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
- int d = 0;
- int e = 0;
- int len2 = len - 2;
- int lineLength = 0;
- for( ; d < len2; d+=3, e+=4 )
- {
- encode3to4( source, d+off, 3, outBuff, e, options );
-
- lineLength += 4;
- if( breakLines && lineLength == MAX_LINE_LENGTH )
- {
- outBuff[e+4] = NEW_LINE;
- e++;
- lineLength = 0;
- } // end if: end of line
- } // en dfor: each piece of array
-
- if( d < len )
- {
- encode3to4( source, d+off, len - d, outBuff, e, options );
- e += 4;
- } // end if: some padding needed
-
-
- // Return value according to relevant encoding.
- try
- {
- return new String( outBuff, 0, e, PREFERRED_ENCODING );
- } // end try
- catch (java.io.UnsupportedEncodingException uue)
- {
- return new String( outBuff, 0, e );
- } // end catch
-
- } // end else: don't compress
-
- } // end encodeBytes
-
-
-
-
-
-/* ******** D E C O D I N G M E T H O D S ******** */
-
-
- /**
- * Decodes four bytes from array source
- * and writes the resulting bytes (up to three of them)
- * to destination.
- * The source and destination arrays can be manipulated
- * anywhere along their length by specifying
- * srcOffset and destOffset.
- * This method does not check to make sure your arrays
- * are large enough to accomodate srcOffset + 4 for
- * the source array or destOffset + 3 for
- * the destination array.
- * This method returns the actual number of bytes that
- * were converted from the Base64 encoding.
- *
- * ENCODE or DECODE: Encode or Decode as data is read.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * (only meaningful when encoding)
- * Note: Technically, this makes your encoding non-compliant.
- *
- * new Base64.InputStream( in, Base64.DECODE )
- *
- *
- * @param in the java.io.InputStream from which to read data.
- * @param options Specified options
- * @see Base64#ENCODE
- * @see Base64#DECODE
- * @see Base64#DONT_BREAK_LINES
- * @since 2.0
- */
- public InputStream( java.io.InputStream in, int options )
- {
- super( in );
- this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
- this.encode = (options & ENCODE) == ENCODE;
- this.bufferLength = encode ? 4 : 3;
- this.buffer = new byte[ bufferLength ];
- this.position = -1;
- this.lineLength = 0;
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in DECODE mode.
+ *
+ * @param in the java.io.InputStream from which to read data.
+ * @since 1.3
+ */
+ public InputStream( java.io.InputStream in )
+ {
+ this( in, DECODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.InputStream} in
+ * either ENCODE or DECODE mode.
+ *
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * (only meaningful when encoding)
+ * Note: Technically, this makes your encoding non-compliant.
+ *
+ * new Base64.InputStream( in, Base64.DECODE )
+ *
+ *
+ * @param in the java.io.InputStream from which to read data.
+ * @param options Specified options
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 2.0
+ */
+ public InputStream( java.io.InputStream in, int options )
+ {
+ super( in );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 4 : 3;
+ this.buffer = new byte[ bufferLength ];
+ this.position = -1;
+ this.lineLength = 0;
this.options = options; // Record for later, mostly to determine which alphabet to use
- this.decodabet = getDecodabet(options);
- } // end constructor
-
- /**
- * Reads enough of the input stream to convert
- * to/from Base64 and returns the next byte.
- *
- * @return next byte
- * @since 1.3
- */
- public int read() throws java.io.IOException
- {
- // Do we need to get data?
- if( position < 0 )
- {
- if( encode )
- {
- byte[] b3 = new byte[3];
- int numBinaryBytes = 0;
- for( int i = 0; i < 3; i++ )
- {
- try
- {
- int b = in.read();
-
- // If end of stream, b is -1.
- if( b >= 0 )
- {
- b3[i] = (byte)b;
- numBinaryBytes++;
- } // end if: not end of stream
-
- } // end try: read
- catch( java.io.IOException e )
- {
- // Only a problem if we got no data at all.
- if( i == 0 )
- throw e;
-
- } // end catch
- } // end for: each needed input byte
-
- if( numBinaryBytes > 0 )
- {
- encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
- position = 0;
- numSigBytes = 4;
- } // end if: got data
- else
- {
- return -1;
- } // end else
- } // end if: encoding
-
- // Else decoding
- else
- {
- byte[] b4 = new byte[4];
- int i = 0;
- for( i = 0; i < 4; i++ )
- {
- // Read four "meaningful" bytes:
- int b = 0;
- do{ b = in.read(); }
- while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
-
- if( b < 0 )
- break; // Reads a -1 if end of stream
-
- b4[i] = (byte)b;
- } // end for: each needed input byte
-
- if( i == 4 )
- {
- numSigBytes = decode4to3( b4, 0, buffer, 0, options );
- position = 0;
- } // end if: got four characters
- else if( i == 0 ){
- return -1;
- } // end else if: also padded correctly
- else
- {
- // Must have broken out from above.
- throw new java.io.IOException( "Improperly padded Base64 input." );
- } // end
-
- } // end else: decode
- } // end else: get data
-
- // Got data?
- if( position >= 0 )
- {
- // End of relevant data?
- if( /*!encode &&*/ position >= numSigBytes )
- return -1;
-
- if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
- {
- lineLength = 0;
- return '\n';
- } // end if
- else
- {
- lineLength++; // This isn't important when decoding
- // but throwing an extra "if" seems
- // just as wasteful.
-
- int b = buffer[ position++ ];
-
- if( position >= bufferLength )
- position = -1;
-
- return b & 0xFF; // This is how you "cast" a byte that's
- // intended to be unsigned.
- } // end else
- } // end if: position >= 0
-
- // Else error
- else
- {
- // When JDK1.4 is more accepted, use an assertion here.
- throw new java.io.IOException( "Error in Base64 code reading stream." );
- } // end else
- } // end read
-
-
- /**
- * Calls {@link #read()} repeatedly until the end of stream
- * is reached or len bytes are read.
- * Returns number of bytes read into array or -1 if
- * end of stream is encountered.
- *
- * @param dest array to hold values
- * @param off offset for array
- * @param len max number of bytes to read into array
- * @return bytes read into array or -1 if end of stream is encountered.
- * @since 1.3
- */
- public int read( byte[] dest, int off, int len ) throws java.io.IOException
- {
- int i;
- int b;
- for( i = 0; i < len; i++ )
- {
- b = read();
-
- //if( b < 0 && i == 0 )
- // return -1;
-
- if( b >= 0 )
- dest[off + i] = (byte)b;
- else if( i == 0 )
- return -1;
- else
- break; // Out of 'for' loop
- } // end for: each byte read
- return i;
- } // end read
-
- } // end inner class InputStream
-
-
-
-
-
-
- /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
-
-
-
- /**
- * A {@link Base64.OutputStream} will write data to another
- * java.io.OutputStream, given in the constructor,
- * and encode/decode to/from Base64 notation on the fly.
- *
- * @see Base64
- * @since 1.3
- */
- public static class OutputStream extends java.io.FilterOutputStream
- {
- private boolean encode;
- private int position;
- private byte[] buffer;
- private int bufferLength;
- private int lineLength;
- private boolean breakLines;
- private byte[] b4; // Scratch used in a few places
- private boolean suspendEncoding;
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+ /**
+ * Reads enough of the input stream to convert
+ * to/from Base64 and returns the next byte.
+ *
+ * @return next byte
+ * @since 1.3
+ */
+ public int read() throws java.io.IOException
+ {
+ // Do we need to get data?
+ if( position < 0 )
+ {
+ if( encode )
+ {
+ byte[] b3 = new byte[3];
+ int numBinaryBytes = 0;
+ for( int i = 0; i < 3; i++ )
+ {
+ try
+ {
+ int b = in.read();
+
+ // If end of stream, b is -1.
+ if( b >= 0 )
+ {
+ b3[i] = (byte)b;
+ numBinaryBytes++;
+ } // end if: not end of stream
+
+ } // end try: read
+ catch( java.io.IOException e )
+ {
+ // Only a problem if we got no data at all.
+ if( i == 0 )
+ throw e;
+
+ } // end catch
+ } // end for: each needed input byte
+
+ if( numBinaryBytes > 0 )
+ {
+ encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
+ position = 0;
+ numSigBytes = 4;
+ } // end if: got data
+ else
+ {
+ return -1;
+ } // end else
+ } // end if: encoding
+
+ // Else decoding
+ else
+ {
+ byte[] b4 = new byte[4];
+ int i = 0;
+ for( i = 0; i < 4; i++ )
+ {
+ // Read four "meaningful" bytes:
+ int b = 0;
+ do{ b = in.read(); }
+ while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
+
+ if( b < 0 )
+ break; // Reads a -1 if end of stream
+
+ b4[i] = (byte)b;
+ } // end for: each needed input byte
+
+ if( i == 4 )
+ {
+ numSigBytes = decode4to3( b4, 0, buffer, 0, options );
+ position = 0;
+ } // end if: got four characters
+ else if( i == 0 ){
+ return -1;
+ } // end else if: also padded correctly
+ else
+ {
+ // Must have broken out from above.
+ throw new java.io.IOException( "Improperly padded Base64 input." );
+ } // end
+
+ } // end else: decode
+ } // end else: get data
+
+ // Got data?
+ if( position >= 0 )
+ {
+ // End of relevant data?
+ if( /*!encode &&*/ position >= numSigBytes )
+ return -1;
+
+ if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ lineLength = 0;
+ return '\n';
+ } // end if
+ else
+ {
+ lineLength++; // This isn't important when decoding
+ // but throwing an extra "if" seems
+ // just as wasteful.
+
+ int b = buffer[ position++ ];
+
+ if( position >= bufferLength )
+ position = -1;
+
+ return b & 0xFF; // This is how you "cast" a byte that's
+ // intended to be unsigned.
+ } // end else
+ } // end if: position >= 0
+
+ // Else error
+ else
+ {
+ // When JDK1.4 is more accepted, use an assertion here.
+ throw new java.io.IOException( "Error in Base64 code reading stream." );
+ } // end else
+ } // end read
+
+
+ /**
+ * Calls {@link #read()} repeatedly until the end of stream
+ * is reached or len bytes are read.
+ * Returns number of bytes read into array or -1 if
+ * end of stream is encountered.
+ *
+ * @param dest array to hold values
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @return bytes read into array or -1 if end of stream is encountered.
+ * @since 1.3
+ */
+ public int read( byte[] dest, int off, int len ) throws java.io.IOException
+ {
+ int i;
+ int b;
+ for( i = 0; i < len; i++ )
+ {
+ b = read();
+
+ //if( b < 0 && i == 0 )
+ // return -1;
+
+ if( b >= 0 )
+ dest[off + i] = (byte)b;
+ else if( i == 0 )
+ return -1;
+ else
+ break; // Out of 'for' loop
+ } // end for: each byte read
+ return i;
+ } // end read
+
+ } // end inner class InputStream
+
+
+
+
+
+
+ /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
+
+
+
+ /**
+ * A {@link Base64.OutputStream} will write data to another
+ * java.io.OutputStream, given in the constructor,
+ * and encode/decode to/from Base64 notation on the fly.
+ *
+ * @see Base64
+ * @since 1.3
+ */
+ public static class OutputStream extends java.io.FilterOutputStream
+ {
+ private boolean encode;
+ private int position;
+ private byte[] buffer;
+ private int bufferLength;
+ private int lineLength;
+ private boolean breakLines;
+ private byte[] b4; // Scratch used in a few places
+ private boolean suspendEncoding;
private int options; // Record for later
- private byte[] decodabet; // Local copies to avoid extra method calls
-
- /**
- * Constructs a {@link Base64.OutputStream} in ENCODE mode.
- *
- * @param out the java.io.OutputStream to which data will be written.
- * @since 1.3
- */
- public OutputStream( java.io.OutputStream out )
- {
- this( out, ENCODE );
- } // end constructor
-
-
- /**
- * Constructs a {@link Base64.OutputStream} in
- * either ENCODE or DECODE mode.
- *
- * ENCODE or DECODE: Encode or Decode as data is read.
- * DONT_BREAK_LINES: don't break lines at 76 characters
- * (only meaningful when encoding)
- * Note: Technically, this makes your encoding non-compliant.
- *
- * new Base64.OutputStream( out, Base64.ENCODE )
- *
- * @param out the java.io.OutputStream to which data will be written.
- * @param options Specified options.
- * @see Base64#ENCODE
- * @see Base64#DECODE
- * @see Base64#DONT_BREAK_LINES
- * @since 1.3
- */
- public OutputStream( java.io.OutputStream out, int options )
- {
- super( out );
- this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
- this.encode = (options & ENCODE) == ENCODE;
- this.bufferLength = encode ? 3 : 4;
- this.buffer = new byte[ bufferLength ];
- this.position = 0;
- this.lineLength = 0;
- this.suspendEncoding = false;
- this.b4 = new byte[4];
+ private byte[] decodabet; // Local copies to avoid extra method calls
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out )
+ {
+ this( out, ENCODE );
+ } // end constructor
+
+
+ /**
+ * Constructs a {@link Base64.OutputStream} in
+ * either ENCODE or DECODE mode.
+ *
+ * ENCODE or DECODE: Encode or Decode as data is read.
+ * DONT_BREAK_LINES: don't break lines at 76 characters
+ * (only meaningful when encoding)
+ * Note: Technically, this makes your encoding non-compliant.
+ *
+ * new Base64.OutputStream( out, Base64.ENCODE )
+ *
+ * @param out the java.io.OutputStream to which data will be written.
+ * @param options Specified options.
+ * @see Base64#ENCODE
+ * @see Base64#DECODE
+ * @see Base64#DONT_BREAK_LINES
+ * @since 1.3
+ */
+ public OutputStream( java.io.OutputStream out, int options )
+ {
+ super( out );
+ this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+ this.encode = (options & ENCODE) == ENCODE;
+ this.bufferLength = encode ? 3 : 4;
+ this.buffer = new byte[ bufferLength ];
+ this.position = 0;
+ this.lineLength = 0;
+ this.suspendEncoding = false;
+ this.b4 = new byte[4];
this.options = options;
- this.decodabet = getDecodabet(options);
- } // end constructor
-
-
- /**
- * Writes the byte to the output stream after
- * converting to/from Base64 notation.
- * When encoding, bytes are buffered three
- * at a time before the output stream actually
- * gets a write() call.
- * When decoding, bytes are buffered four
- * at a time.
- *
- * @param theByte the byte to write
- * @since 1.3
- */
- public void write(int theByte) throws java.io.IOException
- {
- // Encoding suspended?
- if( suspendEncoding )
- {
- super.out.write( theByte );
- return;
- } // end if: supsended
-
- // Encode?
- if( encode )
- {
- buffer[ position++ ] = (byte)theByte;
- if( position >= bufferLength ) // Enough to encode.
- {
- out.write( encode3to4( b4, buffer, bufferLength, options ) );
-
- lineLength += 4;
- if( breakLines && lineLength >= MAX_LINE_LENGTH )
- {
- out.write( NEW_LINE );
- lineLength = 0;
- } // end if: end of line
-
- position = 0;
- } // end if: enough to output
- } // end if: encoding
-
- // Else, Decoding
- else
- {
- // Meaningful Base64 character?
- if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
- {
- buffer[ position++ ] = (byte)theByte;
- if( position >= bufferLength ) // Enough to output.
- {
- int len = Base64.decode4to3( buffer, 0, b4, 0, options );
- out.write( b4, 0, len );
- //out.write( Base64.decode4to3( buffer ) );
- position = 0;
- } // end if: enough to output
- } // end if: meaningful base64 character
- else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
- {
- throw new java.io.IOException( "Invalid character in Base64 data." );
- } // end else: not white space either
- } // end else: decoding
- } // end write
-
-
-
- /**
- * Calls {@link #write(int)} repeatedly until len
- * bytes are written.
- *
- * @param theBytes array from which to read bytes
- * @param off offset for array
- * @param len max number of bytes to read into array
- * @since 1.3
- */
- public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
- {
- // Encoding suspended?
- if( suspendEncoding )
- {
- super.out.write( theBytes, off, len );
- return;
- } // end if: supsended
-
- for( int i = 0; i < len; i++ )
- {
- write( theBytes[ off + i ] );
- } // end for: each byte written
-
- } // end write
-
-
-
- /**
- * Method added by PHIL. [Thanks, PHIL. -Rob]
- * This pads the buffer without closing the stream.
- */
- public void flushBase64() throws java.io.IOException
- {
- if( position > 0 )
- {
- if( encode )
- {
- out.write( encode3to4( b4, buffer, position, options ) );
- position = 0;
- } // end if: encoding
- else
- {
- throw new java.io.IOException( "Base64 input not properly padded." );
- } // end else: decoding
- } // end if: buffer partially full
-
- } // end flush
-
-
- /**
- * Flushes and closes (I think, in the superclass) the stream.
- *
- * @since 1.3
- */
- public void close() throws java.io.IOException
- {
- // 1. Ensure that pending characters are written
- flushBase64();
-
- // 2. Actually close the stream
- // Base class both flushes and closes.
- super.close();
-
- buffer = null;
- out = null;
- } // end close
-
-
-
- /**
- * Suspends encoding of the stream.
- * May be helpful if you need to embed a piece of
- * base640-encoded data in a stream.
- *
- * @since 1.5.1
- */
- public void suspendEncoding() throws java.io.IOException
- {
- flushBase64();
- this.suspendEncoding = true;
- } // end suspendEncoding
-
-
- /**
- * Resumes encoding of the stream.
- * May be helpful if you need to embed a piece of
- * base640-encoded data in a stream.
- *
- * @since 1.5.1
- */
- public void resumeEncoding()
- {
- this.suspendEncoding = false;
- } // end resumeEncoding
-
-
-
- } // end inner class OutputStream
-
-
-} // end class Base64
-
+ this.decodabet = getDecodabet(options);
+ } // end constructor
+
+
+ /**
+ * Writes the byte to the output stream after
+ * converting to/from Base64 notation.
+ * When encoding, bytes are buffered three
+ * at a time before the output stream actually
+ * gets a write() call.
+ * When decoding, bytes are buffered four
+ * at a time.
+ *
+ * @param theByte the byte to write
+ * @since 1.3
+ */
+ public void write(int theByte) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theByte );
+ return;
+ } // end if: supsended
+
+ // Encode?
+ if( encode )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to encode.
+ {
+ out.write( encode3to4( b4, buffer, bufferLength, options ) );
+
+ lineLength += 4;
+ if( breakLines && lineLength >= MAX_LINE_LENGTH )
+ {
+ out.write( NEW_LINE );
+ lineLength = 0;
+ } // end if: end of line
+
+ position = 0;
+ } // end if: enough to output
+ } // end if: encoding
+
+ // Else, Decoding
+ else
+ {
+ // Meaningful Base64 character?
+ if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
+ {
+ buffer[ position++ ] = (byte)theByte;
+ if( position >= bufferLength ) // Enough to output.
+ {
+ int len = Base64.decode4to3( buffer, 0, b4, 0, options );
+ out.write( b4, 0, len );
+ //out.write( Base64.decode4to3( buffer ) );
+ position = 0;
+ } // end if: enough to output
+ } // end if: meaningful base64 character
+ else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
+ {
+ throw new java.io.IOException( "Invalid character in Base64 data." );
+ } // end else: not white space either
+ } // end else: decoding
+ } // end write
+
+
+
+ /**
+ * Calls {@link #write(int)} repeatedly until len
+ * bytes are written.
+ *
+ * @param theBytes array from which to read bytes
+ * @param off offset for array
+ * @param len max number of bytes to read into array
+ * @since 1.3
+ */
+ public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
+ {
+ // Encoding suspended?
+ if( suspendEncoding )
+ {
+ super.out.write( theBytes, off, len );
+ return;
+ } // end if: supsended
+
+ for( int i = 0; i < len; i++ )
+ {
+ write( theBytes[ off + i ] );
+ } // end for: each byte written
+
+ } // end write
+
+
+
+ /**
+ * Method added by PHIL. [Thanks, PHIL. -Rob]
+ * This pads the buffer without closing the stream.
+ */
+ public void flushBase64() throws java.io.IOException
+ {
+ if( position > 0 )
+ {
+ if( encode )
+ {
+ out.write( encode3to4( b4, buffer, position, options ) );
+ position = 0;
+ } // end if: encoding
+ else
+ {
+ throw new java.io.IOException( "Base64 input not properly padded." );
+ } // end else: decoding
+ } // end if: buffer partially full
+
+ } // end flush
+
+
+ /**
+ * Flushes and closes (I think, in the superclass) the stream.
+ *
+ * @since 1.3
+ */
+ public void close() throws java.io.IOException
+ {
+ // 1. Ensure that pending characters are written
+ flushBase64();
+
+ // 2. Actually close the stream
+ // Base class both flushes and closes.
+ super.close();
+
+ buffer = null;
+ out = null;
+ } // end close
+
+
+
+ /**
+ * Suspends encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void suspendEncoding() throws java.io.IOException
+ {
+ flushBase64();
+ this.suspendEncoding = true;
+ } // end suspendEncoding
+
+
+ /**
+ * Resumes encoding of the stream.
+ * May be helpful if you need to embed a piece of
+ * base640-encoded data in a stream.
+ *
+ * @since 1.5.1
+ */
+ public void resumeEncoding()
+ {
+ this.suspendEncoding = false;
+ } // end resumeEncoding
+
+
+
+ } // end inner class OutputStream
+
+
+} // end class Base64
+
diff --git a/core/src/main/java/org/jivesoftware/smack/util/Cache.java b/core/src/main/java/org/jivesoftware/smack/util/Cache.java
index 0b992ab2b..98bdaad20 100644
--- a/core/src/main/java/org/jivesoftware/smack/util/Cache.java
+++ b/core/src/main/java/org/jivesoftware/smack/util/Cache.java
@@ -675,4 +675,4 @@ public class Cachefalse
.
- *
- * @return true
if both streams will be closed if one of the streams is closed,
- * false
if both streams can be closed independently.
- */
- public boolean isCloseBothStreamsEnabled() {
- return closeBothStreamsEnabled;
- }
-
- /**
- * Sets whether both streams should be closed automatically if one of the streams is closed.
- * Default is false
.
- *
- * @param closeBothStreamsEnabled true
if both streams should be closed if one of
- * the streams is closed, false
if both streams should be closed
- * independently
- */
- public void setCloseBothStreamsEnabled(boolean closeBothStreamsEnabled) {
- this.closeBothStreamsEnabled = closeBothStreamsEnabled;
- }
-
- public void close() throws IOException {
- closeByLocal(true); // close input stream
- closeByLocal(false); // close output stream
- }
-
- /**
- * This method is invoked if a request to close the In-Band Bytestream has been received.
- *
- * @param closeRequest the close request from the remote peer
- */
- protected void closeByPeer(Close closeRequest) {
-
- /*
- * close streams without flushing them, because stream is already considered closed on the
- * remote peers side
- */
- this.inputStream.closeInternal();
- this.inputStream.cleanup();
- this.outputStream.closeInternal(false);
-
- // acknowledge close request
- IQ confirmClose = IQ.createResultIQ(closeRequest);
- this.connection.sendPacket(confirmClose);
-
- }
-
- /**
- * This method is invoked if one of the streams has been closed locally, if an error occurred
- * locally or if the whole session should be closed.
- *
- * @throws IOException if an error occurs while sending the close request
- */
- protected synchronized void closeByLocal(boolean in) throws IOException {
- if (this.isClosed) {
- return;
- }
-
- if (this.closeBothStreamsEnabled) {
- this.inputStream.closeInternal();
- this.outputStream.closeInternal(true);
- }
- else {
- if (in) {
- this.inputStream.closeInternal();
- }
- else {
- // close stream but try to send any data left
- this.outputStream.closeInternal(true);
- }
- }
-
- if (this.inputStream.isClosed && this.outputStream.isClosed) {
- this.isClosed = true;
-
- // send close request
- Close close = new Close(this.byteStreamRequest.getSessionID());
- close.setTo(this.remoteJID);
- try {
- SyncPacketSend.getReply(this.connection, close);
- }
- catch (XMPPException e) {
- throw new IOException("Error while closing stream: " + e.getMessage());
- }
-
- this.inputStream.cleanup();
-
- // remove session from manager
- InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(this);
- }
-
- }
-
- /**
- * IBBInputStream class is the base implementation of an In-Band Bytestream input stream.
- * Subclasses of this input stream must provide a packet listener along with a packet filter to
- * collect the In-Band Bytestream data packets.
- */
- private abstract class IBBInputStream extends InputStream {
-
- /* the data packet listener to fill the data queue */
- private final PacketListener dataPacketListener;
-
- /* queue containing received In-Band Bytestream data packets */
- protected final BlockingQueuetrue
if data was received, otherwise false
- * @throws IOException if data packets are out of sequence
- */
- private synchronized boolean loadBuffer() throws IOException {
-
- // wait until data is available or stream is closed
- DataPacketExtension data = null;
- try {
- if (this.readTimeout == 0) {
- while (data == null) {
- if (isClosed && this.dataQueue.isEmpty()) {
- return false;
- }
- data = this.dataQueue.poll(1000, TimeUnit.MILLISECONDS);
- }
- }
- else {
- data = this.dataQueue.poll(this.readTimeout, TimeUnit.MILLISECONDS);
- if (data == null) {
- throw new SocketTimeoutException();
- }
- }
- }
- catch (InterruptedException e) {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
- return false;
- }
-
- // handle sequence overflow
- if (this.seq == 65535) {
- this.seq = -1;
- }
-
- // check if data packets sequence is successor of last seen sequence
- long seq = data.getSeq();
- if (seq - 1 != this.seq) {
- // packets out of order; close stream/session
- InBandBytestreamSession.this.close();
- throw new IOException("Packets out of sequence");
- }
- else {
- this.seq = seq;
- }
-
- // set buffer to decoded data
- buffer = data.getDecodedData();
- bufferPointer = 0;
- return true;
- }
-
- /**
- * Checks if this stream is closed and throws an IOException if necessary
- *
- * @throws IOException if stream is closed and no data should be read anymore
- */
- private void checkClosed() throws IOException {
- /* throw no exception if there is data available, but not if close method was invoked */
- if ((isClosed && this.dataQueue.isEmpty()) || closeInvoked) {
- // clear data queue in case additional data was received after stream was closed
- this.dataQueue.clear();
- throw new IOException("Stream is closed");
- }
- }
-
- public boolean markSupported() {
- return false;
- }
-
- public void close() throws IOException {
- if (isClosed) {
- return;
- }
-
- this.closeInvoked = true;
-
- InBandBytestreamSession.this.closeByLocal(true);
- }
-
- /**
- * This method sets the close flag and removes the data packet listener.
- */
- private void closeInternal() {
- if (isClosed) {
- return;
- }
- isClosed = true;
- }
-
- /**
- * Invoked if the session is closed.
- */
- private void cleanup() {
- connection.removePacketListener(this.dataPacketListener);
- }
-
- }
-
- /**
- * IQIBBInputStream class implements IBBInputStream to be used with IQ stanzas encapsulating the
- * data packets.
- */
- private class IQIBBInputStream extends IBBInputStream {
-
- protected PacketListener getDataPacketListener() {
- return new PacketListener() {
-
- private long lastSequence = -1;
-
- public void processPacket(Packet packet) {
- // get data packet extension
- DataPacketExtension data = (DataPacketExtension) packet.getExtension(
- DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
-
- /*
- * check if sequence was not used already (see XEP-0047 Section 2.2)
- */
- if (data.getSeq() <= this.lastSequence) {
- IQ unexpectedRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
- XMPPError.Condition.unexpected_request));
- connection.sendPacket(unexpectedRequest);
- return;
-
- }
-
- // check if encoded data is valid (see XEP-0047 Section 2.2)
- if (data.getDecodedData() == null) {
- // data is invalid; respond with bad-request error
- IQ badRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
- XMPPError.Condition.bad_request));
- connection.sendPacket(badRequest);
- return;
- }
-
- // data is valid; add to data queue
- dataQueue.offer(data);
-
- // confirm IQ
- IQ confirmData = IQ.createResultIQ((IQ) packet);
- connection.sendPacket(confirmData);
-
- // set last seen sequence
- this.lastSequence = data.getSeq();
- if (this.lastSequence == 65535) {
- this.lastSequence = -1;
- }
-
- }
-
- };
- }
-
- protected PacketFilter getDataPacketFilter() {
- /*
- * filter all IQ stanzas having type 'SET' (represented by Data class), containing a
- * data packet extension, matching session ID and recipient
- */
- return new AndFilter(new PacketTypeFilter(Data.class), new IBBDataPacketFilter());
- }
-
- }
-
- /**
- * MessageIBBInputStream class implements IBBInputStream to be used with message stanzas
- * encapsulating the data packets.
- */
- private class MessageIBBInputStream extends IBBInputStream {
-
- protected PacketListener getDataPacketListener() {
- return new PacketListener() {
-
- public void processPacket(Packet packet) {
- // get data packet extension
- DataPacketExtension data = (DataPacketExtension) packet.getExtension(
- DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
-
- // check if encoded data is valid
- if (data.getDecodedData() == null) {
- /*
- * TODO once a majority of XMPP server implementation support XEP-0079
- * Advanced Message Processing the invalid message could be answered with an
- * appropriate error. For now we just ignore the packet. Subsequent packets
- * with an increased sequence will cause the input stream to close the
- * stream/session.
- */
- return;
- }
-
- // data is valid; add to data queue
- dataQueue.offer(data);
-
- // TODO confirm packet once XMPP servers support XEP-0079
- }
-
- };
- }
-
- @Override
- protected PacketFilter getDataPacketFilter() {
- /*
- * filter all message stanzas containing a data packet extension, matching session ID
- * and recipient
- */
- return new AndFilter(new PacketTypeFilter(Message.class), new IBBDataPacketFilter());
- }
-
- }
-
- /**
- * IBBDataPacketFilter class filters all packets from the remote peer of this session,
- * containing an In-Band Bytestream data packet extension whose session ID matches this sessions
- * ID.
- */
- private class IBBDataPacketFilter implements PacketFilter {
-
- public boolean accept(Packet packet) {
- // sender equals remote peer
- if (!packet.getFrom().equalsIgnoreCase(remoteJID)) {
- return false;
- }
-
- // stanza contains data packet extension
- PacketExtension packetExtension = packet.getExtension(DataPacketExtension.ELEMENT_NAME,
- InBandBytestreamManager.NAMESPACE);
- if (packetExtension == null || !(packetExtension instanceof DataPacketExtension)) {
- return false;
- }
-
- // session ID equals this session ID
- DataPacketExtension data = (DataPacketExtension) packetExtension;
- if (!data.getSessionID().equals(byteStreamRequest.getSessionID())) {
- return false;
- }
-
- return true;
- }
-
- }
-
- /**
- * IBBOutputStream class is the base implementation of an In-Band Bytestream output stream.
- * Subclasses of this output stream must provide a method to send data over XMPP stream.
- */
- private abstract class IBBOutputStream extends OutputStream {
-
- /* buffer with the size of this sessions block size */
- protected final byte[] buffer;
-
- /* pointer to next byte to write to buffer */
- protected int bufferPointer = 0;
-
- /* data packet sequence (range from 0 to 65535) */
- protected long seq = 0;
-
- /* flag to indicate if output stream is closed */
- protected boolean isClosed = false;
-
- /**
- * Constructor.
- */
- public IBBOutputStream() {
- this.buffer = new byte[byteStreamRequest.getBlockSize()];
- }
-
- /**
- * Writes the given data packet to the XMPP stream.
- *
- * @param data the data packet
- * @throws IOException if an I/O error occurred while sending or if the stream is closed
- */
- protected abstract void writeToXML(DataPacketExtension data) throws IOException;
-
- public synchronized void write(int b) throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // if buffer is full flush buffer
- if (bufferPointer >= buffer.length) {
- flushBuffer();
- }
-
- buffer[bufferPointer++] = (byte) b;
- }
-
- public synchronized void write(byte b[], int off, int len) throws IOException {
- if (b == null) {
- throw new NullPointerException();
- }
- else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
- || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- }
- else if (len == 0) {
- return;
- }
-
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // is data to send greater than buffer size
- if (len >= buffer.length) {
-
- // "byte" off the first chunk to write out
- writeOut(b, off, buffer.length);
-
- // recursively call this method with the lesser amount
- write(b, off + buffer.length, len - buffer.length);
- }
- else {
- writeOut(b, off, len);
- }
- }
-
- public synchronized void write(byte[] b) throws IOException {
- write(b, 0, b.length);
- }
-
- /**
- * Fills the buffer with the given data and sends it over the XMPP stream if the buffers
- * capacity has been reached. This method is only called from this class so it is assured
- * that the amount of data to send is <= buffer capacity
- *
- * @param b the data
- * @param off the data
- * @param len the number of bytes to write
- * @throws IOException if an I/O error occurred while sending or if the stream is closed
- */
- private synchronized void writeOut(byte b[], int off, int len) throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
-
- // set to 0 in case the next 'if' block is not executed
- int available = 0;
-
- // is data to send greater that buffer space left
- if (len > buffer.length - bufferPointer) {
- // fill buffer to capacity and send it
- available = buffer.length - bufferPointer;
- System.arraycopy(b, off, buffer, bufferPointer, available);
- bufferPointer += available;
- flushBuffer();
- }
-
- // copy the data left to buffer
- System.arraycopy(b, off + available, buffer, bufferPointer, len - available);
- bufferPointer += len - available;
- }
-
- public synchronized void flush() throws IOException {
- if (this.isClosed) {
- throw new IOException("Stream is closed");
- }
- flushBuffer();
- }
-
- private synchronized void flushBuffer() throws IOException {
-
- // do nothing if no data to send available
- if (bufferPointer == 0) {
- return;
- }
-
- // create data packet
- String enc = StringUtils.encodeBase64(buffer, 0, bufferPointer, false);
- DataPacketExtension data = new DataPacketExtension(byteStreamRequest.getSessionID(),
- this.seq, enc);
-
- // write to XMPP stream
- writeToXML(data);
-
- // reset buffer pointer
- bufferPointer = 0;
-
- // increment sequence, considering sequence overflow
- this.seq = (this.seq + 1 == 65535 ? 0 : this.seq + 1);
-
- }
-
- public void close() throws IOException {
- if (isClosed) {
- return;
- }
- InBandBytestreamSession.this.closeByLocal(false);
- }
-
- /**
- * Sets the close flag and optionally flushes the stream.
- *
- * @param flush if true
flushes the stream
- */
- protected void closeInternal(boolean flush) {
- if (this.isClosed) {
- return;
- }
- this.isClosed = true;
-
- try {
- if (flush) {
- flushBuffer();
- }
- }
- catch (IOException e) {
- /*
- * ignore, because writeToXML() will not throw an exception if stream is already
- * closed
- */
- }
- }
-
- }
-
- /**
- * IQIBBOutputStream class implements IBBOutputStream to be used with IQ stanzas encapsulating
- * the data packets.
- */
- private class IQIBBOutputStream extends IBBOutputStream {
-
- @Override
- protected synchronized void writeToXML(DataPacketExtension data) throws IOException {
- // create IQ stanza containing data packet
- IQ iq = new Data(data);
- iq.setTo(remoteJID);
-
- try {
- SyncPacketSend.getReply(connection, iq);
- }
- catch (XMPPException e) {
- // close session unless it is already closed
- if (!this.isClosed) {
- InBandBytestreamSession.this.close();
- throw new IOException("Error while sending Data: " + e.getMessage());
- }
- }
-
- }
-
- }
-
- /**
- * MessageIBBOutputStream class implements IBBOutputStream to be used with message stanzas
- * encapsulating the data packets.
- */
- private class MessageIBBOutputStream extends IBBOutputStream {
-
- @Override
- protected synchronized void writeToXML(DataPacketExtension data) {
- // create message stanza containing data packet
- Message message = new Message(remoteJID);
- message.addExtension(data);
-
- connection.sendPacket(message);
-
- }
-
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.jivesoftware.smack.Connection;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.AndFilter;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.packet.XMPPError;
+import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smack.util.SyncPacketSend;
+import org.jivesoftware.smackx.bytestreams.BytestreamSession;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Close;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Data;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
+import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
+
+/**
+ * InBandBytestreamSession class represents an In-Band Bytestream session.
+ * false
.
+ *
+ * @return true
if both streams will be closed if one of the streams is closed,
+ * false
if both streams can be closed independently.
+ */
+ public boolean isCloseBothStreamsEnabled() {
+ return closeBothStreamsEnabled;
+ }
+
+ /**
+ * Sets whether both streams should be closed automatically if one of the streams is closed.
+ * Default is false
.
+ *
+ * @param closeBothStreamsEnabled true
if both streams should be closed if one of
+ * the streams is closed, false
if both streams should be closed
+ * independently
+ */
+ public void setCloseBothStreamsEnabled(boolean closeBothStreamsEnabled) {
+ this.closeBothStreamsEnabled = closeBothStreamsEnabled;
+ }
+
+ public void close() throws IOException {
+ closeByLocal(true); // close input stream
+ closeByLocal(false); // close output stream
+ }
+
+ /**
+ * This method is invoked if a request to close the In-Band Bytestream has been received.
+ *
+ * @param closeRequest the close request from the remote peer
+ */
+ protected void closeByPeer(Close closeRequest) {
+
+ /*
+ * close streams without flushing them, because stream is already considered closed on the
+ * remote peers side
+ */
+ this.inputStream.closeInternal();
+ this.inputStream.cleanup();
+ this.outputStream.closeInternal(false);
+
+ // acknowledge close request
+ IQ confirmClose = IQ.createResultIQ(closeRequest);
+ this.connection.sendPacket(confirmClose);
+
+ }
+
+ /**
+ * This method is invoked if one of the streams has been closed locally, if an error occurred
+ * locally or if the whole session should be closed.
+ *
+ * @throws IOException if an error occurs while sending the close request
+ */
+ protected synchronized void closeByLocal(boolean in) throws IOException {
+ if (this.isClosed) {
+ return;
+ }
+
+ if (this.closeBothStreamsEnabled) {
+ this.inputStream.closeInternal();
+ this.outputStream.closeInternal(true);
+ }
+ else {
+ if (in) {
+ this.inputStream.closeInternal();
+ }
+ else {
+ // close stream but try to send any data left
+ this.outputStream.closeInternal(true);
+ }
+ }
+
+ if (this.inputStream.isClosed && this.outputStream.isClosed) {
+ this.isClosed = true;
+
+ // send close request
+ Close close = new Close(this.byteStreamRequest.getSessionID());
+ close.setTo(this.remoteJID);
+ try {
+ SyncPacketSend.getReply(this.connection, close);
+ }
+ catch (XMPPException e) {
+ throw new IOException("Error while closing stream: " + e.getMessage());
+ }
+
+ this.inputStream.cleanup();
+
+ // remove session from manager
+ InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(this);
+ }
+
+ }
+
+ /**
+ * IBBInputStream class is the base implementation of an In-Band Bytestream input stream.
+ * Subclasses of this input stream must provide a packet listener along with a packet filter to
+ * collect the In-Band Bytestream data packets.
+ */
+ private abstract class IBBInputStream extends InputStream {
+
+ /* the data packet listener to fill the data queue */
+ private final PacketListener dataPacketListener;
+
+ /* queue containing received In-Band Bytestream data packets */
+ protected final BlockingQueuetrue
if data was received, otherwise false
+ * @throws IOException if data packets are out of sequence
+ */
+ private synchronized boolean loadBuffer() throws IOException {
+
+ // wait until data is available or stream is closed
+ DataPacketExtension data = null;
+ try {
+ if (this.readTimeout == 0) {
+ while (data == null) {
+ if (isClosed && this.dataQueue.isEmpty()) {
+ return false;
+ }
+ data = this.dataQueue.poll(1000, TimeUnit.MILLISECONDS);
+ }
+ }
+ else {
+ data = this.dataQueue.poll(this.readTimeout, TimeUnit.MILLISECONDS);
+ if (data == null) {
+ throw new SocketTimeoutException();
+ }
+ }
+ }
+ catch (InterruptedException e) {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+ return false;
+ }
+
+ // handle sequence overflow
+ if (this.seq == 65535) {
+ this.seq = -1;
+ }
+
+ // check if data packets sequence is successor of last seen sequence
+ long seq = data.getSeq();
+ if (seq - 1 != this.seq) {
+ // packets out of order; close stream/session
+ InBandBytestreamSession.this.close();
+ throw new IOException("Packets out of sequence");
+ }
+ else {
+ this.seq = seq;
+ }
+
+ // set buffer to decoded data
+ buffer = data.getDecodedData();
+ bufferPointer = 0;
+ return true;
+ }
+
+ /**
+ * Checks if this stream is closed and throws an IOException if necessary
+ *
+ * @throws IOException if stream is closed and no data should be read anymore
+ */
+ private void checkClosed() throws IOException {
+ /* throw no exception if there is data available, but not if close method was invoked */
+ if ((isClosed && this.dataQueue.isEmpty()) || closeInvoked) {
+ // clear data queue in case additional data was received after stream was closed
+ this.dataQueue.clear();
+ throw new IOException("Stream is closed");
+ }
+ }
+
+ public boolean markSupported() {
+ return false;
+ }
+
+ public void close() throws IOException {
+ if (isClosed) {
+ return;
+ }
+
+ this.closeInvoked = true;
+
+ InBandBytestreamSession.this.closeByLocal(true);
+ }
+
+ /**
+ * This method sets the close flag and removes the data packet listener.
+ */
+ private void closeInternal() {
+ if (isClosed) {
+ return;
+ }
+ isClosed = true;
+ }
+
+ /**
+ * Invoked if the session is closed.
+ */
+ private void cleanup() {
+ connection.removePacketListener(this.dataPacketListener);
+ }
+
+ }
+
+ /**
+ * IQIBBInputStream class implements IBBInputStream to be used with IQ stanzas encapsulating the
+ * data packets.
+ */
+ private class IQIBBInputStream extends IBBInputStream {
+
+ protected PacketListener getDataPacketListener() {
+ return new PacketListener() {
+
+ private long lastSequence = -1;
+
+ public void processPacket(Packet packet) {
+ // get data packet extension
+ DataPacketExtension data = (DataPacketExtension) packet.getExtension(
+ DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+
+ /*
+ * check if sequence was not used already (see XEP-0047 Section 2.2)
+ */
+ if (data.getSeq() <= this.lastSequence) {
+ IQ unexpectedRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
+ XMPPError.Condition.unexpected_request));
+ connection.sendPacket(unexpectedRequest);
+ return;
+
+ }
+
+ // check if encoded data is valid (see XEP-0047 Section 2.2)
+ if (data.getDecodedData() == null) {
+ // data is invalid; respond with bad-request error
+ IQ badRequest = IQ.createErrorResponse((IQ) packet, new XMPPError(
+ XMPPError.Condition.bad_request));
+ connection.sendPacket(badRequest);
+ return;
+ }
+
+ // data is valid; add to data queue
+ dataQueue.offer(data);
+
+ // confirm IQ
+ IQ confirmData = IQ.createResultIQ((IQ) packet);
+ connection.sendPacket(confirmData);
+
+ // set last seen sequence
+ this.lastSequence = data.getSeq();
+ if (this.lastSequence == 65535) {
+ this.lastSequence = -1;
+ }
+
+ }
+
+ };
+ }
+
+ protected PacketFilter getDataPacketFilter() {
+ /*
+ * filter all IQ stanzas having type 'SET' (represented by Data class), containing a
+ * data packet extension, matching session ID and recipient
+ */
+ return new AndFilter(new PacketTypeFilter(Data.class), new IBBDataPacketFilter());
+ }
+
+ }
+
+ /**
+ * MessageIBBInputStream class implements IBBInputStream to be used with message stanzas
+ * encapsulating the data packets.
+ */
+ private class MessageIBBInputStream extends IBBInputStream {
+
+ protected PacketListener getDataPacketListener() {
+ return new PacketListener() {
+
+ public void processPacket(Packet packet) {
+ // get data packet extension
+ DataPacketExtension data = (DataPacketExtension) packet.getExtension(
+ DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+
+ // check if encoded data is valid
+ if (data.getDecodedData() == null) {
+ /*
+ * TODO once a majority of XMPP server implementation support XEP-0079
+ * Advanced Message Processing the invalid message could be answered with an
+ * appropriate error. For now we just ignore the packet. Subsequent packets
+ * with an increased sequence will cause the input stream to close the
+ * stream/session.
+ */
+ return;
+ }
+
+ // data is valid; add to data queue
+ dataQueue.offer(data);
+
+ // TODO confirm packet once XMPP servers support XEP-0079
+ }
+
+ };
+ }
+
+ @Override
+ protected PacketFilter getDataPacketFilter() {
+ /*
+ * filter all message stanzas containing a data packet extension, matching session ID
+ * and recipient
+ */
+ return new AndFilter(new PacketTypeFilter(Message.class), new IBBDataPacketFilter());
+ }
+
+ }
+
+ /**
+ * IBBDataPacketFilter class filters all packets from the remote peer of this session,
+ * containing an In-Band Bytestream data packet extension whose session ID matches this sessions
+ * ID.
+ */
+ private class IBBDataPacketFilter implements PacketFilter {
+
+ public boolean accept(Packet packet) {
+ // sender equals remote peer
+ if (!packet.getFrom().equalsIgnoreCase(remoteJID)) {
+ return false;
+ }
+
+ // stanza contains data packet extension
+ PacketExtension packetExtension = packet.getExtension(DataPacketExtension.ELEMENT_NAME,
+ InBandBytestreamManager.NAMESPACE);
+ if (packetExtension == null || !(packetExtension instanceof DataPacketExtension)) {
+ return false;
+ }
+
+ // session ID equals this session ID
+ DataPacketExtension data = (DataPacketExtension) packetExtension;
+ if (!data.getSessionID().equals(byteStreamRequest.getSessionID())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+
+ /**
+ * IBBOutputStream class is the base implementation of an In-Band Bytestream output stream.
+ * Subclasses of this output stream must provide a method to send data over XMPP stream.
+ */
+ private abstract class IBBOutputStream extends OutputStream {
+
+ /* buffer with the size of this sessions block size */
+ protected final byte[] buffer;
+
+ /* pointer to next byte to write to buffer */
+ protected int bufferPointer = 0;
+
+ /* data packet sequence (range from 0 to 65535) */
+ protected long seq = 0;
+
+ /* flag to indicate if output stream is closed */
+ protected boolean isClosed = false;
+
+ /**
+ * Constructor.
+ */
+ public IBBOutputStream() {
+ this.buffer = new byte[byteStreamRequest.getBlockSize()];
+ }
+
+ /**
+ * Writes the given data packet to the XMPP stream.
+ *
+ * @param data the data packet
+ * @throws IOException if an I/O error occurred while sending or if the stream is closed
+ */
+ protected abstract void writeToXML(DataPacketExtension data) throws IOException;
+
+ public synchronized void write(int b) throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // if buffer is full flush buffer
+ if (bufferPointer >= buffer.length) {
+ flushBuffer();
+ }
+
+ buffer[bufferPointer++] = (byte) b;
+ }
+
+ public synchronized void write(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length)
+ || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0) {
+ return;
+ }
+
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // is data to send greater than buffer size
+ if (len >= buffer.length) {
+
+ // "byte" off the first chunk to write out
+ writeOut(b, off, buffer.length);
+
+ // recursively call this method with the lesser amount
+ write(b, off + buffer.length, len - buffer.length);
+ }
+ else {
+ writeOut(b, off, len);
+ }
+ }
+
+ public synchronized void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Fills the buffer with the given data and sends it over the XMPP stream if the buffers
+ * capacity has been reached. This method is only called from this class so it is assured
+ * that the amount of data to send is <= buffer capacity
+ *
+ * @param b the data
+ * @param off the data
+ * @param len the number of bytes to write
+ * @throws IOException if an I/O error occurred while sending or if the stream is closed
+ */
+ private synchronized void writeOut(byte b[], int off, int len) throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+
+ // set to 0 in case the next 'if' block is not executed
+ int available = 0;
+
+ // is data to send greater that buffer space left
+ if (len > buffer.length - bufferPointer) {
+ // fill buffer to capacity and send it
+ available = buffer.length - bufferPointer;
+ System.arraycopy(b, off, buffer, bufferPointer, available);
+ bufferPointer += available;
+ flushBuffer();
+ }
+
+ // copy the data left to buffer
+ System.arraycopy(b, off + available, buffer, bufferPointer, len - available);
+ bufferPointer += len - available;
+ }
+
+ public synchronized void flush() throws IOException {
+ if (this.isClosed) {
+ throw new IOException("Stream is closed");
+ }
+ flushBuffer();
+ }
+
+ private synchronized void flushBuffer() throws IOException {
+
+ // do nothing if no data to send available
+ if (bufferPointer == 0) {
+ return;
+ }
+
+ // create data packet
+ String enc = StringUtils.encodeBase64(buffer, 0, bufferPointer, false);
+ DataPacketExtension data = new DataPacketExtension(byteStreamRequest.getSessionID(),
+ this.seq, enc);
+
+ // write to XMPP stream
+ writeToXML(data);
+
+ // reset buffer pointer
+ bufferPointer = 0;
+
+ // increment sequence, considering sequence overflow
+ this.seq = (this.seq + 1 == 65535 ? 0 : this.seq + 1);
+
+ }
+
+ public void close() throws IOException {
+ if (isClosed) {
+ return;
+ }
+ InBandBytestreamSession.this.closeByLocal(false);
+ }
+
+ /**
+ * Sets the close flag and optionally flushes the stream.
+ *
+ * @param flush if true
flushes the stream
+ */
+ protected void closeInternal(boolean flush) {
+ if (this.isClosed) {
+ return;
+ }
+ this.isClosed = true;
+
+ try {
+ if (flush) {
+ flushBuffer();
+ }
+ }
+ catch (IOException e) {
+ /*
+ * ignore, because writeToXML() will not throw an exception if stream is already
+ * closed
+ */
+ }
+ }
+
+ }
+
+ /**
+ * IQIBBOutputStream class implements IBBOutputStream to be used with IQ stanzas encapsulating
+ * the data packets.
+ */
+ private class IQIBBOutputStream extends IBBOutputStream {
+
+ @Override
+ protected synchronized void writeToXML(DataPacketExtension data) throws IOException {
+ // create IQ stanza containing data packet
+ IQ iq = new Data(data);
+ iq.setTo(remoteJID);
+
+ try {
+ SyncPacketSend.getReply(connection, iq);
+ }
+ catch (XMPPException e) {
+ // close session unless it is already closed
+ if (!this.isClosed) {
+ InBandBytestreamSession.this.close();
+ throw new IOException("Error while sending Data: " + e.getMessage());
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * MessageIBBOutputStream class implements IBBOutputStream to be used with message stanzas
+ * encapsulating the data packets.
+ */
+ private class MessageIBBOutputStream extends IBBOutputStream {
+
+ @Override
+ protected synchronized void writeToXML(DataPacketExtension data) {
+ // create message stanza containing data packet
+ Message message = new Message(remoteJID);
+ message.addExtension(data);
+
+ connection.sendPacket(message);
+
+ }
+
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
index 44464d688..82a63404f 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/InitiationListener.java
@@ -1,130 +1,130 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.jivesoftware.smack.PacketListener;
-import org.jivesoftware.smack.filter.AndFilter;
-import org.jivesoftware.smack.filter.IQTypeFilter;
-import org.jivesoftware.smack.filter.PacketFilter;
-import org.jivesoftware.smack.filter.PacketTypeFilter;
-import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.Packet;
-import org.jivesoftware.smackx.bytestreams.BytestreamListener;
-import org.jivesoftware.smackx.bytestreams.ibb.packet.Open;
-
-/**
- * InitiationListener handles all incoming In-Band Bytestream open requests. If there are no
- * listeners for a In-Band Bytestream request InitiationListener will always refuse the request and
- * reply with a <not-acceptable/> error (XEP-0047 Section 2.1).
- * packet.getExtension("data",
- * "http://jabber.org/protocol/ibb")
.
- *
- * @return the data packet extension
- */
- public DataPacketExtension getDataPacketExtension() {
- return this.dataPacketExtension;
- }
-
- public String getChildElementXML() {
- return this.dataPacketExtension.toXML();
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.ibb.packet;
+
+import org.jivesoftware.smack.packet.IQ;
+
+/**
+ * Represents a chunk of data sent over an In-Band Bytestream encapsulated in an
+ * IQ stanza.
+ *
+ * @author Henning Staib
+ */
+public class Data extends IQ {
+
+ /* the data packet extension */
+ private final DataPacketExtension dataPacketExtension;
+
+ /**
+ * Constructor.
+ *
+ * @param data data packet extension containing the encoded data
+ */
+ public Data(DataPacketExtension data) {
+ if (data == null) {
+ throw new IllegalArgumentException("Data must not be null");
+ }
+ this.dataPacketExtension = data;
+
+ /*
+ * also set as packet extension so that data packet extension can be
+ * retrieved from IQ stanza and message stanza in the same way
+ */
+ addExtension(data);
+ setType(IQ.Type.SET);
+ }
+
+ /**
+ * Returns the data packet extension.
+ * packet.getExtension("data",
+ * "http://jabber.org/protocol/ibb")
.
+ *
+ * @return the data packet extension
+ */
+ public DataPacketExtension getDataPacketExtension() {
+ return this.dataPacketExtension;
+ }
+
+ public String getChildElementXML() {
+ return this.dataPacketExtension.toXML();
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
index 0d63512fd..ee3c4e49b 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/ibb/packet/DataPacketExtension.java
@@ -1,152 +1,152 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.ibb.packet;
-
-import org.jivesoftware.smack.packet.PacketExtension;
-import org.jivesoftware.smack.util.StringUtils;
-import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
-
-/**
- * Represents a chunk of data of an In-Band Bytestream within an IQ stanza or a
- * message stanza
- *
- * @author Henning Staib
- */
-public class DataPacketExtension implements PacketExtension {
-
- /**
- * The element name of the data packet extension.
- */
- public final static String ELEMENT_NAME = "data";
-
- /* unique session ID identifying this In-Band Bytestream */
- private final String sessionID;
-
- /* sequence of this packet in regard to the other data packets */
- private final long seq;
-
- /* the data contained in this packet */
- private final String data;
-
- private byte[] decodedData;
-
- /**
- * Creates a new In-Band Bytestream data packet.
- *
- * @param sessionID unique session ID identifying this In-Band Bytestream
- * @param seq sequence of this packet in regard to the other data packets
- * @param data the base64 encoded data contained in this packet
- */
- public DataPacketExtension(String sessionID, long seq, String data) {
- if (sessionID == null || "".equals(sessionID)) {
- throw new IllegalArgumentException("Session ID must not be null or empty");
- }
- if (seq < 0 || seq > 65535) {
- throw new IllegalArgumentException("Sequence must not be between 0 and 65535");
- }
- if (data == null) {
- throw new IllegalArgumentException("Data must not be null");
- }
- this.sessionID = sessionID;
- this.seq = seq;
- this.data = data;
- }
-
- /**
- * Returns the unique session ID identifying this In-Band Bytestream.
- *
- * @return the unique session ID identifying this In-Band Bytestream
- */
- public String getSessionID() {
- return sessionID;
- }
-
- /**
- * Returns the sequence of this packet in regard to the other data packets.
- *
- * @return the sequence of this packet in regard to the other data packets.
- */
- public long getSeq() {
- return seq;
- }
-
- /**
- * Returns the data contained in this packet.
- *
- * @return the data contained in this packet.
- */
- public String getData() {
- return data;
- }
-
- /**
- * Returns the decoded data or null if data could not be decoded.
- * null
if given connection is
- * null
- * @return the Socks5BytestreamManager for the given XMPP connection
- */
- public static synchronized Socks5BytestreamManager getBytestreamManager(Connection connection) {
- if (connection == null) {
- return null;
- }
- Socks5BytestreamManager manager = managers.get(connection);
- if (manager == null) {
- manager = new Socks5BytestreamManager(connection);
- managers.put(connection, manager);
- manager.activate();
- }
- return manager;
- }
-
- /**
- * Private constructor.
- *
- * @param connection the XMPP connection
- */
- private Socks5BytestreamManager(Connection connection) {
- this.connection = connection;
- this.initiationListener = new InitiationListener(this);
- }
-
- /**
- * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request unless
- * there is a user specific BytestreamListener registered.
- * true
.
- *
- * @return true
if prioritization is enabled, false
otherwise
- */
- public boolean isProxyPrioritizationEnabled() {
- return proxyPrioritizationEnabled;
- }
-
- /**
- * Enable/disable the prioritization of the last working SOCKS5 proxy on successive SOCKS5
- * Bytestream connections.
- *
- * @param proxyPrioritizationEnabled enable/disable the prioritization of the last working
- * SOCKS5 proxy
- */
- public void setProxyPrioritizationEnabled(boolean proxyPrioritizationEnabled) {
- this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
- }
-
- /**
- * Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
- * data to/from the user.
- * true
if the given target JID supports feature SOCKS5 Bytestream.
- *
- * @param targetJID the target JID
- * @return true
if the given target JID supports feature SOCKS5 Bytestream
- * otherwise false
- * @throws XMPPException if there was an error querying target for supported features
- */
- private boolean supportsSocks5(String targetJID) throws XMPPException {
- ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
- DiscoverInfo discoverInfo = serviceDiscoveryManager.discoverInfo(targetJID);
- return discoverInfo.containsFeature(NAMESPACE);
- }
-
- /**
- * Returns a list of JIDs of SOCKS5 proxies by querying the XMPP server. The SOCKS5 proxies are
- * in the same order as returned by the XMPP server.
- *
- * @return list of JIDs of SOCKS5 proxies
- * @throws XMPPException if there was an error querying the XMPP server for SOCKS5 proxies
- */
- private Listnull
if given connection is
+ * null
+ * @return the Socks5BytestreamManager for the given XMPP connection
+ */
+ public static synchronized Socks5BytestreamManager getBytestreamManager(Connection connection) {
+ if (connection == null) {
+ return null;
+ }
+ Socks5BytestreamManager manager = managers.get(connection);
+ if (manager == null) {
+ manager = new Socks5BytestreamManager(connection);
+ managers.put(connection, manager);
+ manager.activate();
+ }
+ return manager;
+ }
+
+ /**
+ * Private constructor.
+ *
+ * @param connection the XMPP connection
+ */
+ private Socks5BytestreamManager(Connection connection) {
+ this.connection = connection;
+ this.initiationListener = new InitiationListener(this);
+ }
+
+ /**
+ * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request unless
+ * there is a user specific BytestreamListener registered.
+ * true
.
+ *
+ * @return true
if prioritization is enabled, false
otherwise
+ */
+ public boolean isProxyPrioritizationEnabled() {
+ return proxyPrioritizationEnabled;
+ }
+
+ /**
+ * Enable/disable the prioritization of the last working SOCKS5 proxy on successive SOCKS5
+ * Bytestream connections.
+ *
+ * @param proxyPrioritizationEnabled enable/disable the prioritization of the last working
+ * SOCKS5 proxy
+ */
+ public void setProxyPrioritizationEnabled(boolean proxyPrioritizationEnabled) {
+ this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
+ }
+
+ /**
+ * Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
+ * data to/from the user.
+ * true
if the given target JID supports feature SOCKS5 Bytestream.
+ *
+ * @param targetJID the target JID
+ * @return true
if the given target JID supports feature SOCKS5 Bytestream
+ * otherwise false
+ * @throws XMPPException if there was an error querying target for supported features
+ */
+ private boolean supportsSocks5(String targetJID) throws XMPPException {
+ ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection);
+ DiscoverInfo discoverInfo = serviceDiscoveryManager.discoverInfo(targetJID);
+ return discoverInfo.containsFeature(NAMESPACE);
+ }
+
+ /**
+ * Returns a list of JIDs of SOCKS5 proxies by querying the XMPP server. The SOCKS5 proxies are
+ * in the same order as returned by the XMPP server.
+ *
+ * @return list of JIDs of SOCKS5 proxies
+ * @throws XMPPException if there was an error querying the XMPP server for SOCKS5 proxies
+ */
+ private Listtrue
if the session is established through a direct connection between
- * the initiator and target, false
if the session is mediated over a SOCKS proxy.
- *
- * @return true
if session is a direct connection, false
if session is
- * mediated over a SOCKS5 proxy
- */
- public boolean isDirect() {
- return this.isDirect;
- }
-
- /**
- * Returns true
if the session is mediated over a SOCKS proxy, false
- * if this session is established through a direct connection between the initiator and target.
- *
- * @return true
if session is mediated over a SOCKS5 proxy, false
if
- * session is a direct connection
- */
- public boolean isMediated() {
- return !this.isDirect;
- }
-
- public InputStream getInputStream() throws IOException {
- return this.socket.getInputStream();
- }
-
- public OutputStream getOutputStream() throws IOException {
- return this.socket.getOutputStream();
- }
-
- public int getReadTimeout() throws IOException {
- try {
- return this.socket.getSoTimeout();
- }
- catch (SocketException e) {
- throw new IOException("Error on underlying Socket");
- }
- }
-
- public void setReadTimeout(int timeout) throws IOException {
- try {
- this.socket.setSoTimeout(timeout);
- }
- catch (SocketException e) {
- throw new IOException("Error on underlying Socket");
- }
- }
-
- public void close() throws IOException {
- this.socket.close();
- }
-
-}
+package org.jivesoftware.smackx.bytestreams.socks5;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.jivesoftware.smackx.bytestreams.BytestreamSession;
+
+/**
+ * Socks5BytestreamSession class represents a SOCKS5 Bytestream session.
+ *
+ * @author Henning Staib
+ */
+public class Socks5BytestreamSession implements BytestreamSession {
+
+ /* the underlying socket of the SOCKS5 Bytestream */
+ private final Socket socket;
+
+ /* flag to indicate if this session is a direct or mediated connection */
+ private final boolean isDirect;
+
+ protected Socks5BytestreamSession(Socket socket, boolean isDirect) {
+ this.socket = socket;
+ this.isDirect = isDirect;
+ }
+
+ /**
+ * Returns true
if the session is established through a direct connection between
+ * the initiator and target, false
if the session is mediated over a SOCKS proxy.
+ *
+ * @return true
if session is a direct connection, false
if session is
+ * mediated over a SOCKS5 proxy
+ */
+ public boolean isDirect() {
+ return this.isDirect;
+ }
+
+ /**
+ * Returns true
if the session is mediated over a SOCKS proxy, false
+ * if this session is established through a direct connection between the initiator and target.
+ *
+ * @return true
if session is mediated over a SOCKS5 proxy, false
if
+ * session is a direct connection
+ */
+ public boolean isMediated() {
+ return !this.isDirect;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return this.socket.getInputStream();
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return this.socket.getOutputStream();
+ }
+
+ public int getReadTimeout() throws IOException {
+ try {
+ return this.socket.getSoTimeout();
+ }
+ catch (SocketException e) {
+ throw new IOException("Error on underlying Socket");
+ }
+ }
+
+ public void setReadTimeout(int timeout) throws IOException {
+ try {
+ this.socket.setSoTimeout(timeout);
+ }
+ catch (SocketException e) {
+ throw new IOException("Error on underlying Socket");
+ }
+ }
+
+ public void close() throws IOException {
+ this.socket.close();
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
index b805f89ba..5e538b68a 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java
@@ -1,207 +1,207 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
-
-/**
- * The SOCKS5 client class handles establishing a connection to a SOCKS5 proxy. Connecting to a
- * SOCKS5 proxy requires authentication. This implementation only supports the no-authentication
- * authentication method.
- *
- * @author Henning Staib
- */
-class Socks5Client {
-
- /* stream host containing network settings and name of the SOCKS5 proxy */
- protected StreamHost streamHost;
-
- /* SHA-1 digest identifying the SOCKS5 stream */
- protected String digest;
-
- /**
- * Constructor for a SOCKS5 client.
- *
- * @param streamHost containing network settings of the SOCKS5 proxy
- * @param digest identifying the SOCKS5 Bytestream
- */
- public Socks5Client(StreamHost streamHost, String digest) {
- this.streamHost = streamHost;
- this.digest = digest;
- }
-
- /**
- * Returns the initialized socket that can be used to transfer data between peers via the SOCKS5
- * proxy.
- *
- * @param timeout timeout to connect to SOCKS5 proxy in milliseconds
- * @return socket the initialized socket
- * @throws IOException if initializing the socket failed due to a network error
- * @throws XMPPException if establishing connection to SOCKS5 proxy failed
- * @throws TimeoutException if connecting to SOCKS5 proxy timed out
- * @throws InterruptedException if the current thread was interrupted while waiting
- */
- public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
- TimeoutException {
-
- // wrap connecting in future for timeout
- FutureTasktrue
if a stream could be established, otherwise false
. If
- * false
is returned the given Socket should be closed.
- *
- * @param socket connected to a SOCKS5 proxy
- * @return true
if if a stream could be established, otherwise false
.
- * If false
is returned the given Socket should be closed.
- * @throws IOException if a network error occurred
- */
- protected boolean establish(Socket socket) throws IOException {
-
- /*
- * use DataInputStream/DataOutpuStream to assure read and write is completed in a single
- * statement
- */
- DataInputStream in = new DataInputStream(socket.getInputStream());
- DataOutputStream out = new DataOutputStream(socket.getOutputStream());
-
- // authentication negotiation
- byte[] cmd = new byte[3];
-
- cmd[0] = (byte) 0x05; // protocol version 5
- cmd[1] = (byte) 0x01; // number of authentication methods supported
- cmd[2] = (byte) 0x00; // authentication method: no-authentication required
-
- out.write(cmd);
- out.flush();
-
- byte[] response = new byte[2];
- in.readFully(response);
-
- // check if server responded with correct version and no-authentication method
- if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
- return false;
- }
-
- // request SOCKS5 connection with given address/digest
- byte[] connectionRequest = createSocks5ConnectRequest();
- out.write(connectionRequest);
- out.flush();
-
- // receive response
- byte[] connectionResponse;
- try {
- connectionResponse = Socks5Utils.receiveSocks5Message(in);
- }
- catch (XMPPException e) {
- return false; // server answered in an unsupported way
- }
-
- // verify response
- connectionRequest[1] = (byte) 0x00; // set expected return status to 0
- return Arrays.equals(connectionRequest, connectionResponse);
- }
-
- /**
- * Returns a SOCKS5 connection request message. It contains the command "connect", the address
- * type "domain" and the digest as address.
- * true
if a stream could be established, otherwise false
. If
+ * false
is returned the given Socket should be closed.
+ *
+ * @param socket connected to a SOCKS5 proxy
+ * @return true
if if a stream could be established, otherwise false
.
+ * If false
is returned the given Socket should be closed.
+ * @throws IOException if a network error occurred
+ */
+ protected boolean establish(Socket socket) throws IOException {
+
+ /*
+ * use DataInputStream/DataOutpuStream to assure read and write is completed in a single
+ * statement
+ */
+ DataInputStream in = new DataInputStream(socket.getInputStream());
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+
+ // authentication negotiation
+ byte[] cmd = new byte[3];
+
+ cmd[0] = (byte) 0x05; // protocol version 5
+ cmd[1] = (byte) 0x01; // number of authentication methods supported
+ cmd[2] = (byte) 0x00; // authentication method: no-authentication required
+
+ out.write(cmd);
+ out.flush();
+
+ byte[] response = new byte[2];
+ in.readFully(response);
+
+ // check if server responded with correct version and no-authentication method
+ if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
+ return false;
+ }
+
+ // request SOCKS5 connection with given address/digest
+ byte[] connectionRequest = createSocks5ConnectRequest();
+ out.write(connectionRequest);
+ out.flush();
+
+ // receive response
+ byte[] connectionResponse;
+ try {
+ connectionResponse = Socks5Utils.receiveSocks5Message(in);
+ }
+ catch (XMPPException e) {
+ return false; // server answered in an unsupported way
+ }
+
+ // verify response
+ connectionRequest[1] = (byte) 0x00; // set expected return status to 0
+ return Arrays.equals(connectionRequest, connectionResponse);
+ }
+
+ /**
+ * Returns a SOCKS5 connection request message. It contains the command "connect", the address
+ * type "domain" and the digest as address.
+ * localSocks5ProxyEnabled
flag in the smack-config.xml
or by
- * invoking {@link SmackConfiguration#setLocalSocks5ProxyEnabled(boolean)}. The proxy is enabled by
- * default.
- * localSocks5ProxyPort
- * in the smack-config.xml
or by invoking
- * {@link SmackConfiguration#setLocalSocks5ProxyPort(int)}. Default port is 7777. If you set the
- * port to a negative value Smack tries to the absolute value and all following until it finds an
- * open port.
- *
- *
- * (see RFC 1928)
- *
- * @author Henning Staib
- */
-public class Socks5Proxy {
- private static Logger log = Logger.getLogger(Socks5Proxy.class.getName());
-
- /* SOCKS5 proxy singleton */
- private static Socks5Proxy socks5Server;
-
- /* reusable implementation of a SOCKS5 proxy server process */
- private Socks5ServerProcess serverProcess;
-
- /* thread running the SOCKS5 server process */
- private Thread serverThread;
-
- /* server socket to accept SOCKS5 connections */
- private ServerSocket serverSocket;
-
- /* assigns a connection to a digest */
- private final Mapconnect
command and will not answer correctly to other
- * commandsInetAddress.getLocalHost().getHostAddress()
. You can replace the list of
- * addresses by invoking {@link #replaceLocalAddresses(List)}.
- *
- * @param address the local network address to add
- */
- public void addLocalAddress(String address) {
- if (address == null) {
- throw new IllegalArgumentException("address may not be null");
- }
- this.localAddresses.add(address);
- }
-
- /**
- * Removes the given address from the list of local network addresses. This address will then no
- * longer be used of outgoing SOCKS5 Bytestream requests.
- *
- * @param address the local network address to remove
- */
- public void removeLocalAddress(String address) {
- this.localAddresses.remove(address);
- }
-
- /**
- * Returns an unmodifiable list of the local network addresses that will be used for streamhost
- * candidates of outgoing SOCKS5 Bytestream requests.
- *
- * @return unmodifiable list of the local network addresses
- */
- public Listtrue
if the local SOCKS5 proxy server is running, otherwise
- * false
.
- *
- * @return true
if the local SOCKS5 proxy server is running, otherwise
- * false
- */
- public boolean isRunning() {
- return this.serverSocket != null;
- }
-
- /**
- * Implementation of a simplified SOCKS5 proxy server.
- */
- private class Socks5ServerProcess implements Runnable {
-
- public void run() {
- while (true) {
- Socket socket = null;
-
- try {
-
- if (Socks5Proxy.this.serverSocket.isClosed()
- || Thread.currentThread().isInterrupted()) {
- return;
- }
-
- // accept connection
- socket = Socks5Proxy.this.serverSocket.accept();
-
- // initialize connection
- establishConnection(socket);
-
- }
- catch (SocketException e) {
- /*
- * do nothing, if caused by closing the server socket, thread will terminate in
- * next loop
- */
- }
- catch (Exception e) {
- try {
- if (socket != null) {
- socket.close();
- }
- }
- catch (IOException e1) {
- /* do nothing */
- }
- }
- }
-
- }
-
- /**
- * Negotiates a SOCKS5 connection and stores it on success.
- *
- * @param socket connection to the client
- * @throws XMPPException if client requests a connection in an unsupported way
- * @throws IOException if a network error occurred
- */
- private void establishConnection(Socket socket) throws XMPPException, IOException {
- DataOutputStream out = new DataOutputStream(socket.getOutputStream());
- DataInputStream in = new DataInputStream(socket.getInputStream());
-
- // first byte is version should be 5
- int b = in.read();
- if (b != 5) {
- throw new XMPPException("Only SOCKS5 supported");
- }
-
- // second byte number of authentication methods supported
- b = in.read();
-
- // read list of supported authentication methods
- byte[] auth = new byte[b];
- in.readFully(auth);
-
- byte[] authMethodSelectionResponse = new byte[2];
- authMethodSelectionResponse[0] = (byte) 0x05; // protocol version
-
- // only authentication method 0, no authentication, supported
- boolean noAuthMethodFound = false;
- for (int i = 0; i < auth.length; i++) {
- if (auth[i] == (byte) 0x00) {
- noAuthMethodFound = true;
- break;
- }
- }
-
- if (!noAuthMethodFound) {
- authMethodSelectionResponse[1] = (byte) 0xFF; // no acceptable methods
- out.write(authMethodSelectionResponse);
- out.flush();
- throw new XMPPException("Authentication method not supported");
- }
-
- authMethodSelectionResponse[1] = (byte) 0x00; // no-authentication method
- out.write(authMethodSelectionResponse);
- out.flush();
-
- // receive connection request
- byte[] connectionRequest = Socks5Utils.receiveSocks5Message(in);
-
- // extract digest
- String responseDigest = new String(connectionRequest, 5, connectionRequest[4]);
-
- // return error if digest is not allowed
- if (!Socks5Proxy.this.allowedConnections.contains(responseDigest)) {
- connectionRequest[1] = (byte) 0x05; // set return status to 5 (connection refused)
- out.write(connectionRequest);
- out.flush();
-
- throw new XMPPException("Connection is not allowed");
- }
-
- connectionRequest[1] = (byte) 0x00; // set return status to 0 (success)
- out.write(connectionRequest);
- out.flush();
-
- // store connection
- Socks5Proxy.this.connectionMap.put(responseDigest, socket);
- }
-
- }
-
-}
+/**
+ *
+ * Copyright the original author or authors
+ *
+ * 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.bytestreams.socks5;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+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;
+
+import org.jivesoftware.smack.SmackConfiguration;
+import org.jivesoftware.smack.XMPPException;
+
+/**
+ * The Socks5Proxy class represents a local SOCKS5 proxy server. It can be enabled/disabled by
+ * setting the localSocks5ProxyEnabled
flag in the smack-config.xml
or by
+ * invoking {@link SmackConfiguration#setLocalSocks5ProxyEnabled(boolean)}. The proxy is enabled by
+ * default.
+ * localSocks5ProxyPort
+ * in the smack-config.xml
or by invoking
+ * {@link SmackConfiguration#setLocalSocks5ProxyPort(int)}. Default port is 7777. If you set the
+ * port to a negative value Smack tries to the absolute value and all following until it finds an
+ * open port.
+ *
+ *
+ * (see RFC 1928)
+ *
+ * @author Henning Staib
+ */
+public class Socks5Proxy {
+ private static Logger log = Logger.getLogger(Socks5Proxy.class.getName());
+
+ /* SOCKS5 proxy singleton */
+ private static Socks5Proxy socks5Server;
+
+ /* reusable implementation of a SOCKS5 proxy server process */
+ private Socks5ServerProcess serverProcess;
+
+ /* thread running the SOCKS5 server process */
+ private Thread serverThread;
+
+ /* server socket to accept SOCKS5 connections */
+ private ServerSocket serverSocket;
+
+ /* assigns a connection to a digest */
+ private final Mapconnect
command and will not answer correctly to other
+ * commandsInetAddress.getLocalHost().getHostAddress()
. You can replace the list of
+ * addresses by invoking {@link #replaceLocalAddresses(List)}.
+ *
+ * @param address the local network address to add
+ */
+ public void addLocalAddress(String address) {
+ if (address == null) {
+ throw new IllegalArgumentException("address may not be null");
+ }
+ this.localAddresses.add(address);
+ }
+
+ /**
+ * Removes the given address from the list of local network addresses. This address will then no
+ * longer be used of outgoing SOCKS5 Bytestream requests.
+ *
+ * @param address the local network address to remove
+ */
+ public void removeLocalAddress(String address) {
+ this.localAddresses.remove(address);
+ }
+
+ /**
+ * Returns an unmodifiable list of the local network addresses that will be used for streamhost
+ * candidates of outgoing SOCKS5 Bytestream requests.
+ *
+ * @return unmodifiable list of the local network addresses
+ */
+ public Listtrue
if the local SOCKS5 proxy server is running, otherwise
+ * false
.
+ *
+ * @return true
if the local SOCKS5 proxy server is running, otherwise
+ * false
+ */
+ public boolean isRunning() {
+ return this.serverSocket != null;
+ }
+
+ /**
+ * Implementation of a simplified SOCKS5 proxy server.
+ */
+ private class Socks5ServerProcess implements Runnable {
+
+ public void run() {
+ while (true) {
+ Socket socket = null;
+
+ try {
+
+ if (Socks5Proxy.this.serverSocket.isClosed()
+ || Thread.currentThread().isInterrupted()) {
+ return;
+ }
+
+ // accept connection
+ socket = Socks5Proxy.this.serverSocket.accept();
+
+ // initialize connection
+ establishConnection(socket);
+
+ }
+ catch (SocketException e) {
+ /*
+ * do nothing, if caused by closing the server socket, thread will terminate in
+ * next loop
+ */
+ }
+ catch (Exception e) {
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ catch (IOException e1) {
+ /* do nothing */
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Negotiates a SOCKS5 connection and stores it on success.
+ *
+ * @param socket connection to the client
+ * @throws XMPPException if client requests a connection in an unsupported way
+ * @throws IOException if a network error occurred
+ */
+ private void establishConnection(Socket socket) throws XMPPException, IOException {
+ DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+ DataInputStream in = new DataInputStream(socket.getInputStream());
+
+ // first byte is version should be 5
+ int b = in.read();
+ if (b != 5) {
+ throw new XMPPException("Only SOCKS5 supported");
+ }
+
+ // second byte number of authentication methods supported
+ b = in.read();
+
+ // read list of supported authentication methods
+ byte[] auth = new byte[b];
+ in.readFully(auth);
+
+ byte[] authMethodSelectionResponse = new byte[2];
+ authMethodSelectionResponse[0] = (byte) 0x05; // protocol version
+
+ // only authentication method 0, no authentication, supported
+ boolean noAuthMethodFound = false;
+ for (int i = 0; i < auth.length; i++) {
+ if (auth[i] == (byte) 0x00) {
+ noAuthMethodFound = true;
+ break;
+ }
+ }
+
+ if (!noAuthMethodFound) {
+ authMethodSelectionResponse[1] = (byte) 0xFF; // no acceptable methods
+ out.write(authMethodSelectionResponse);
+ out.flush();
+ throw new XMPPException("Authentication method not supported");
+ }
+
+ authMethodSelectionResponse[1] = (byte) 0x00; // no-authentication method
+ out.write(authMethodSelectionResponse);
+ out.flush();
+
+ // receive connection request
+ byte[] connectionRequest = Socks5Utils.receiveSocks5Message(in);
+
+ // extract digest
+ String responseDigest = new String(connectionRequest, 5, connectionRequest[4]);
+
+ // return error if digest is not allowed
+ if (!Socks5Proxy.this.allowedConnections.contains(responseDigest)) {
+ connectionRequest[1] = (byte) 0x05; // set return status to 5 (connection refused)
+ out.write(connectionRequest);
+ out.flush();
+
+ throw new XMPPException("Connection is not allowed");
+ }
+
+ connectionRequest[1] = (byte) 0x00; // set return status to 0 (success)
+ out.write(connectionRequest);
+ out.flush();
+
+ // store connection
+ Socks5Proxy.this.connectionMap.put(responseDigest, socket);
+ }
+
+ }
+
+}
diff --git a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
index 819ce124e..9c7cc490c 100644
--- a/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
+++ b/extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Utils.java
@@ -1,76 +1,76 @@
-/**
- *
- * Copyright the original author or authors
- *
- * 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.bytestreams.socks5;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.util.StringUtils;
-
-/**
- * A collection of utility methods for SOcKS5 messages.
- *
- * @author Henning Staib
- */
-class Socks5Utils {
-
- /**
- * Returns a SHA-1 digest of the given parameters as specified in XEP-0065.
- *
- * @param sessionID for the SOCKS5 Bytestream
- * @param initiatorJID JID of the initiator of a SOCKS5 Bytestream
- * @param targetJID JID of the target of a SOCKS5 Bytestream
- * @return SHA-1 digest of the given parameters
- */
- public static String createDigest(String sessionID, String initiatorJID, String targetJID) {
- StringBuilder b = new StringBuilder();
- b.append(sessionID).append(initiatorJID).append(targetJID);
- return StringUtils.hash(b.toString());
- }
-
- /**
- * Reads a SOCKS5 message from the given InputStream. The message can either be a SOCKS5 request
- * message or a SOCKS5 response message.
- *