mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-22 12:02:05 +01:00
Rework XMPP Error class design
Introduce AbstractError, change 'Conditions' to enums. Because of AbstractError, it was necessary that PlainStreamElement and TopLevelStreamElement becomes an interface. Thus the implementation of TopLevelStreamElement.toString() had to be removed. This adds - policy-violation - unexpected-request to XMPPError.Condition, and removes the - payment-required - remote-server-error - unexpected-condition - request-timeout Conditions The file transfer code does now no longer throw XMPPErrorExceptions, but SmackExceptions. Fixes SMACK-608. Makes it possible to resolves SMACK-386.
This commit is contained in:
parent
cc09192095
commit
9286a1decb
31 changed files with 582 additions and 548 deletions
|
@ -277,9 +277,8 @@ public class ReconnectionManager {
|
||||||
if (e instanceof StreamErrorException) {
|
if (e instanceof StreamErrorException) {
|
||||||
StreamErrorException xmppEx = (StreamErrorException) e;
|
StreamErrorException xmppEx = (StreamErrorException) e;
|
||||||
StreamError error = xmppEx.getStreamError();
|
StreamError error = xmppEx.getStreamError();
|
||||||
String reason = error.getCode();
|
|
||||||
|
|
||||||
if ("conflict".equals(reason)) {
|
if (StreamError.Condition.conflict == error.getCondition()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2014 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.PacketUtil;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class AbstractError {
|
||||||
|
|
||||||
|
private final String textNamespace;
|
||||||
|
protected final Map<String, String> descriptiveTexts;
|
||||||
|
private final List<PacketExtension> extensions;
|
||||||
|
|
||||||
|
|
||||||
|
protected AbstractError(Map<String, String> descriptiveTexts) {
|
||||||
|
this(descriptiveTexts, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractError(Map<String, String> descriptiveTexts, List<PacketExtension> extensions) {
|
||||||
|
this(descriptiveTexts, null, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractError(Map<String, String> descriptiveTexts, String textNamespace, List<PacketExtension> extensions) {
|
||||||
|
if (descriptiveTexts != null) {
|
||||||
|
this.descriptiveTexts = descriptiveTexts;
|
||||||
|
} else {
|
||||||
|
this.descriptiveTexts = Collections.emptyMap();
|
||||||
|
}
|
||||||
|
this.textNamespace = textNamespace;
|
||||||
|
if (extensions != null) {
|
||||||
|
this.extensions = extensions;
|
||||||
|
} else {
|
||||||
|
this.extensions = Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the descriptive text of this SASLFailure.
|
||||||
|
* <p>
|
||||||
|
* Returns the descriptive text of this SASLFailure in the system default language if possible. May return null.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the descriptive text or null.
|
||||||
|
*/
|
||||||
|
public String getDescriptiveText() {
|
||||||
|
String defaultLocale = Locale.getDefault().getLanguage();
|
||||||
|
String descriptiveText = getDescriptiveText(defaultLocale);
|
||||||
|
if (descriptiveText == null) {
|
||||||
|
descriptiveText = getDescriptiveText("");
|
||||||
|
}
|
||||||
|
return descriptiveText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the descriptive test of this SASLFailure.
|
||||||
|
* <p>
|
||||||
|
* Returns the descriptive text of this SASLFailure in the given language. May return null if not available.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param xmllang the language.
|
||||||
|
* @return the descriptive text or null.
|
||||||
|
*/
|
||||||
|
public String getDescriptiveText(String xmllang) {
|
||||||
|
return descriptiveTexts.get(xmllang);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first packet extension that matches the specified element name and
|
||||||
|
* namespace, or <tt>null</tt> if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @param elementName the XML element name of the packet extension.
|
||||||
|
* @param namespace the XML element namespace of the packet extension.
|
||||||
|
* @return the extension, or <tt>null</tt> if it doesn't exist.
|
||||||
|
*/
|
||||||
|
public <PE extends PacketExtension> PE getExtension(String elementName, String namespace) {
|
||||||
|
return PacketUtil.packetExtensionfromCollection(extensions, elementName, namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addDescriptiveTextsAndExtensions(XmlStringBuilder xml) {
|
||||||
|
for (Map.Entry<String, String> entry : descriptiveTexts.entrySet()) {
|
||||||
|
String xmllang = entry.getKey();
|
||||||
|
String text = entry.getValue();
|
||||||
|
xml.halfOpenElement("text").xmlnsAttribute(textNamespace)
|
||||||
|
.xmllangAttribute(xmllang).rightAngleBracket();
|
||||||
|
xml.escape(text);
|
||||||
|
xml.closeElement("text");
|
||||||
|
}
|
||||||
|
for (PacketExtension packetExtension : extensions) {
|
||||||
|
xml.append(packetExtension.toXML());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,6 @@ package org.jivesoftware.smack.packet;
|
||||||
*
|
*
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
*/
|
*/
|
||||||
public abstract class FullStreamElement extends PlainStreamElement implements PacketExtension {
|
public abstract class FullStreamElement implements PlainStreamElement, PacketExtension {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public abstract class Packet extends TopLevelStreamElement {
|
public abstract class Packet implements TopLevelStreamElement {
|
||||||
|
|
||||||
public static final String TEXT = "text";
|
public static final String TEXT = "text";
|
||||||
public static final String ITEM = "item";
|
public static final String ITEM = "item";
|
||||||
|
|
|
@ -29,6 +29,6 @@ package org.jivesoftware.smack.packet;
|
||||||
*
|
*
|
||||||
* @author Florian Schmaus
|
* @author Florian Schmaus
|
||||||
*/
|
*/
|
||||||
public abstract class PlainStreamElement extends TopLevelStreamElement {
|
public interface PlainStreamElement extends TopLevelStreamElement {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
package org.jivesoftware.smack.packet;
|
package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a stream error packet. Stream errors are unrecoverable errors where the server
|
* 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.
|
* will close the unrelying TCP connection after the stream error was sent to the client.
|
||||||
|
@ -73,48 +78,114 @@ package org.jivesoftware.smack.packet;
|
||||||
* <tr><td> not-well-formed </td><td> the initiating entity has sent XML that is not
|
* <tr><td> not-well-formed </td><td> the initiating entity has sent XML that is not
|
||||||
* well-formed. </td></tr>
|
* well-formed. </td></tr>
|
||||||
* </table>
|
* </table>
|
||||||
|
* <p>
|
||||||
|
* Stream error syntax:
|
||||||
|
* <pre>
|
||||||
|
* {@code
|
||||||
|
* <stream:error>
|
||||||
|
* <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
|
||||||
|
* [<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'
|
||||||
|
* xml:lang='langcode'>
|
||||||
|
* OPTIONAL descriptive text
|
||||||
|
* </text>]
|
||||||
|
* [OPTIONAL application-specific condition element]
|
||||||
|
* </stream:error>
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Gaston Dombiak
|
* @author Gaston Dombiak
|
||||||
*/
|
*/
|
||||||
public class StreamError {
|
public class StreamError extends AbstractError implements PlainStreamElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "stream:error";
|
||||||
public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams";
|
public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams";
|
||||||
|
|
||||||
private String code;
|
private final Condition condition;
|
||||||
private String text;
|
private final String conditionText;
|
||||||
|
|
||||||
public StreamError(String code) {
|
public StreamError(Condition condition, String conditionText, Map<String, String> descriptiveTexts, List<PacketExtension> extensions) {
|
||||||
super();
|
super(descriptiveTexts, extensions);
|
||||||
this.code = code;
|
if (conditionText != null) {
|
||||||
|
switch (condition) {
|
||||||
|
case see_other_host:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("The given condition '" + condition
|
||||||
|
+ "' can not contain a conditionText");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.condition = condition;
|
||||||
|
this.conditionText = conditionText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamError(String code, String text) {
|
public Condition getCondition() {
|
||||||
this(code);
|
return condition;
|
||||||
this.text = text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String getConditionText() {
|
||||||
* Returns the error code.
|
return conditionText;
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder txt = new StringBuilder();
|
return toXML().toString();
|
||||||
txt.append("stream:error (").append(code).append(")");
|
}
|
||||||
if (text != null) txt.append(" text: ").append(text);
|
|
||||||
return txt.toString();
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.openElement(ELEMENT);
|
||||||
|
xml.rightAngleBracket().append(condition.toString()).xmlnsAttribute(NAMESPACE).closeEmptyElement();
|
||||||
|
addDescriptiveTextsAndExtensions(xml);
|
||||||
|
xml.closeElement(ELEMENT);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The defined stream error condtions, see RFC 6120 § 4.9.3
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Condition {
|
||||||
|
bad_format,
|
||||||
|
bad_namespace_prefix,
|
||||||
|
conflict,
|
||||||
|
connection_timeout,
|
||||||
|
host_gone,
|
||||||
|
host_unkown,
|
||||||
|
improper_addressing,
|
||||||
|
internal_server_error,
|
||||||
|
invalid_from,
|
||||||
|
invalid_namespace,
|
||||||
|
invalid_xml,
|
||||||
|
not_authorized,
|
||||||
|
not_well_formed,
|
||||||
|
policy_violation,
|
||||||
|
remote_connection_failed,
|
||||||
|
reset,
|
||||||
|
resource_constraint,
|
||||||
|
restricted_xml,
|
||||||
|
see_other_host,
|
||||||
|
system_shutdown,
|
||||||
|
undeficed_condition,
|
||||||
|
unsupported_encoding,
|
||||||
|
unsupported_feature,
|
||||||
|
unsupported_stanza_type,
|
||||||
|
unsupported_version;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name().replace('_', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Condition fromString(String string) {
|
||||||
|
string = string.replace('-', '_');
|
||||||
|
Condition condition = null;
|
||||||
|
try {
|
||||||
|
condition = Condition.valueOf(string);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Could not transform string '" + string + "' to XMPPErrorConditoin", e);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,6 @@ package org.jivesoftware.smack.packet;
|
||||||
* A XMPP top level stream element. This is either a stanza ({@link Packet}) or
|
* A XMPP top level stream element. This is either a stanza ({@link Packet}) or
|
||||||
* just a plain stream element ({@link PlainStreamElement}).
|
* just a plain stream element ({@link PlainStreamElement}).
|
||||||
*/
|
*/
|
||||||
public abstract class TopLevelStreamElement implements Element {
|
public interface TopLevelStreamElement extends Element {
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return toXML().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.packet;
|
package org.jivesoftware.smack.packet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,85 +30,76 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
* error condition as well as as an optional text explanation. Typical errors are:<p>
|
* error condition as well as as an optional text explanation. Typical errors are:<p>
|
||||||
*
|
*
|
||||||
* <table border=1>
|
* <table border=1>
|
||||||
* <hr><td><b>XMPP Error</b></td><td><b>Type</b></td></hr>
|
* <hr><td><b>XMPP Error Condition</b></td><td><b>Type</b></td><td><b>RFC 6120 Section</b></td></hr>
|
||||||
* <tr><td>internal-server-error</td><td>WAIT</td></tr>
|
* <tr><td>bad-request</td><td>MODIFY</td><td>8.3.3.1</td></tr>
|
||||||
* <tr><td>forbidden</td><td>AUTH</td></tr>
|
* <tr><td>conflict</td><td>CANCEL</td><td>8.3.3.2</td></tr>
|
||||||
* <tr><td>bad-request</td><td>MODIFY</td></tr>
|
* <tr><td>feature-not-implemented</td><td>CANCEL</td><td>8.3.3.3</td></tr>
|
||||||
* <tr><td>item-not-found</td><td>CANCEL</td></tr>
|
* <tr><td>forbidden</td><td>AUTH</td><td>8.3.3.4</td></tr>
|
||||||
* <tr><td>conflict</td><td>CANCEL</td></tr>
|
* <tr><td>gone</td><td>MODIFY</td><td>8.3.3.5</td></tr>
|
||||||
* <tr><td>feature-not-implemented</td><td>CANCEL</td></tr>
|
* <tr><td>internal-server-error</td><td>WAIT</td><td>8.3.3.6</td></tr>
|
||||||
* <tr><td>gone</td><td>MODIFY</td></tr>
|
* <tr><td>item-not-found</td><td>CANCEL</td><td>8.3.3.7</td></tr>
|
||||||
* <tr><td>jid-malformed</td><td>MODIFY</td></tr>
|
* <tr><td>jid-malformed</td><td>MODIFY</td><td>8.3.3.8</td></tr>
|
||||||
* <tr><td>not-acceptable</td><td> MODIFY</td></tr>
|
* <tr><td>not-acceptable</td><td> MODIFY</td><td>8.3.3.9</td></tr>
|
||||||
* <tr><td>not-allowed</td><td>CANCEL</td></tr>
|
* <tr><td>not-allowed</td><td>CANCEL</td><td>8.3.3.10</td></tr>
|
||||||
* <tr><td>not-authorized</td><td>AUTH</td></tr>
|
* <tr><td>not-authorized</td><td>AUTH</td><td>8.3.3.11</td></tr>
|
||||||
* <tr><td>payment-required</td><td>AUTH</td></tr>
|
* <tr><td>policy-violation</td><td>AUTH</td><td>8.3.3.12</td></tr>
|
||||||
* <tr><td>recipient-unavailable</td><td>WAIT</td></tr>
|
* <tr><td>recipient-unavailable</td><td>WAIT</td><td>8.3.3.13</td></tr>
|
||||||
* <tr><td>redirect</td><td>MODIFY</td></tr>
|
* <tr><td>redirect</td><td>MODIFY</td><td>8.3.3.14</td></tr>
|
||||||
* <tr><td>registration-required</td><td>AUTH</td></tr>
|
* <tr><td>registration-required</td><td>AUTH</td><td>8.3.3.15</td></tr>
|
||||||
* <tr><td>remote-server-not-found</td><td>CANCEL</td></tr>
|
* <tr><td>remote-server-not-found</td><td>CANCEL</td><td>8.3.3.16</td></tr>
|
||||||
* <tr><td>remote-server-timeout</td><td>WAIT</td></tr>
|
* <tr><td>remote-server-timeout</td><td>WAIT</td><td>8.3.3.17</td></tr>
|
||||||
* <tr><td>remote-server-error</td><td>CANCEL</td></tr>
|
* <tr><td>resource-constraint</td><td>WAIT</td><td>8.3.3.18</td></tr>
|
||||||
* <tr><td>resource-constraint</td><td>WAIT</td></tr>
|
* <tr><td>service-unavailable</td><td>CANCEL</td><td>8.3.3.19</td></tr>
|
||||||
* <tr><td>service-unavailable</td><td>CANCEL</td></tr>
|
* <tr><td>subscription-required</td><td>AUTH</td><td>8.3.3.20</td></tr>
|
||||||
* <tr><td>subscription-required</td><td>AUTH</td></tr>
|
* <tr><td>undefined-condition</td><td>WAIT</td><td>8.3.3.21</td></tr>
|
||||||
* <tr><td>undefined-condition</td><td>WAIT</td></tr>
|
* <tr><td>unexpected-request</td><td>WAIT</td><td>8.3.3.22</td></tr>
|
||||||
* <tr><td>unexpected-condition</td><td>WAIT</td></tr>
|
|
||||||
* <tr><td>request-timeout</td><td>CANCEL</td></tr>
|
|
||||||
* </table>
|
* </table>
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#stanzas-error-syntax">RFC 6120 - 8.3.2 Syntax: The Syntax of XMPP error stanzas</a>
|
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#stanzas-error-syntax">RFC 6120 - 8.3.2 Syntax: The Syntax of XMPP error stanzas</a>
|
||||||
*/
|
*/
|
||||||
public class XMPPError {
|
public class XMPPError extends AbstractError {
|
||||||
|
|
||||||
public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas";
|
public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas";
|
||||||
public static final String ERROR = "error";
|
public static final String ERROR = "error";
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(XMPPError.class.getName());
|
||||||
|
private static final Map<Condition, Type> CONDITION_TO_TYPE = new HashMap<Condition, Type>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
CONDITION_TO_TYPE.put(Condition.bad_request, Type.MODIFY);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.conflict, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.feature_not_implemented, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.forbidden, Type.AUTH);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.gone, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.internal_server_error, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.item_not_found, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.jid_malformed, Type.MODIFY);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.not_acceptable, Type.MODIFY);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.not_allowed, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.not_authorized, Type.AUTH);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.policy_violation, Type.MODIFY);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.recipient_unavailable, Type.WAIT);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.redirect, Type.MODIFY);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.registration_required, Type.AUTH);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.remote_server_not_found, Type.CANCEL);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.remote_server_timeout, Type.WAIT);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.resource_constraint, Type.WAIT);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.service_unavailable, Type.WAIT);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.subscription_required, Type.WAIT);
|
||||||
|
CONDITION_TO_TYPE.put(Condition.unexpected_request, Type.MODIFY);
|
||||||
|
}
|
||||||
|
private final Condition condition;
|
||||||
|
private final String conditionText;
|
||||||
|
private final String errorGenerator;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final String condition;
|
|
||||||
private String message;
|
|
||||||
private List<PacketExtension> applicationExtensions = null;
|
|
||||||
|
|
||||||
public XMPPError(String condition) {
|
|
||||||
this(new Condition(condition));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new error with the specified condition inferring the type.
|
|
||||||
* If the Condition is predefined, client code should be like:
|
|
||||||
* new XMPPError(XMPPError.Condition.remote_server_timeout);
|
|
||||||
* If the Condition is not predefined, invocations should be like
|
|
||||||
* new XMPPError(new XMPPError.Condition("my_own_error"));
|
|
||||||
*
|
|
||||||
* @param condition the error condition.
|
|
||||||
*/
|
|
||||||
public XMPPError(Condition condition) {
|
public XMPPError(Condition condition) {
|
||||||
// Look for the condition and its default type
|
this(condition, null, null, null, null, null);
|
||||||
ErrorSpecification defaultErrorSpecification = ErrorSpecification.specFor(condition);
|
|
||||||
this.condition = condition.value;
|
|
||||||
if (defaultErrorSpecification != null) {
|
|
||||||
// If there is a default error specification for the received condition,
|
|
||||||
// it get configured with the inferred type.
|
|
||||||
type = defaultErrorSpecification.getType();
|
|
||||||
} else {
|
|
||||||
type = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public XMPPError(Condition condition, PacketExtension applicationSpecificCondition) {
|
||||||
* Creates a new error with the specified condition and message infering the type.
|
this(condition, null, null, null, null, Arrays.asList(applicationSpecificCondition));
|
||||||
* If the Condition is predefined, client code should be like:
|
|
||||||
* new XMPPError(XMPPError.Condition.remote_server_timeout, "Error Explanation");
|
|
||||||
* If the Condition is not predefined, invocations should be like
|
|
||||||
* new XMPPError(new XMPPError.Condition("my_own_error"), "Error Explanation");
|
|
||||||
*
|
|
||||||
* @param condition the error condition.
|
|
||||||
* @param messageText a message describing the error.
|
|
||||||
*/
|
|
||||||
public XMPPError(Condition condition, String messageText) {
|
|
||||||
this(condition);
|
|
||||||
this.message = messageText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,15 +110,36 @@ public class XMPPError {
|
||||||
*
|
*
|
||||||
* @param type the error type.
|
* @param type the error type.
|
||||||
* @param condition the error condition.
|
* @param condition the error condition.
|
||||||
* @param message a message describing the error.
|
* @param descriptiveTexts
|
||||||
* @param extension list of packet extensions
|
* @param extensions list of packet extensions
|
||||||
*/
|
*/
|
||||||
public XMPPError(Type type, String condition, String message,
|
public XMPPError(Condition condition, String conditionText, String errorGenerator, Type type, Map<String, String> descriptiveTexts,
|
||||||
List<PacketExtension> extension) {
|
List<PacketExtension> extensions) {
|
||||||
this.type = type;
|
super(descriptiveTexts, NAMESPACE, extensions);
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.message = message;
|
if (conditionText != null) {
|
||||||
this.applicationExtensions = extension;
|
switch (condition) {
|
||||||
|
case gone:
|
||||||
|
case redirect:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Condition text can only be set with condtion types 'gone' and 'redirect', not "
|
||||||
|
+ condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.conditionText = conditionText;
|
||||||
|
this.errorGenerator = errorGenerator;
|
||||||
|
if (type == null) {
|
||||||
|
Type determinedType = CONDITION_TO_TYPE.get(condition);
|
||||||
|
if (determinedType == null) {
|
||||||
|
LOGGER.warning("Could not determine type for condition: " + condition);
|
||||||
|
determinedType = Type.CANCEL;
|
||||||
|
}
|
||||||
|
this.type = determinedType;
|
||||||
|
} else {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,7 +147,7 @@ public class XMPPError {
|
||||||
*
|
*
|
||||||
* @return the error condition.
|
* @return the error condition.
|
||||||
*/
|
*/
|
||||||
public String getCondition() {
|
public Condition getCondition() {
|
||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,13 +160,12 @@ public class XMPPError {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String getErrorGenerator() {
|
||||||
* Returns the message describing the error, or null if there is no message.
|
return errorGenerator;
|
||||||
*
|
}
|
||||||
* @return the message describing the error, or null if there is no message.
|
|
||||||
*/
|
public String getConditionText() {
|
||||||
public String getMessage() {
|
return conditionText;
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,93 +176,24 @@ public class XMPPError {
|
||||||
public XmlStringBuilder toXML() {
|
public XmlStringBuilder toXML() {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder();
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
xml.halfOpenElement(ERROR);
|
xml.halfOpenElement(ERROR);
|
||||||
xml.optAttribute("type", type.name().toLowerCase(Locale.US));
|
xml.attribute("type", type.toString());
|
||||||
|
xml.optAttribute("by", errorGenerator);
|
||||||
xml.rightAngleBracket();
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
if (condition != null) {
|
xml.halfOpenElement(condition.toString());
|
||||||
xml.halfOpenElement(condition);
|
|
||||||
xml.xmlnsAttribute(NAMESPACE);
|
xml.xmlnsAttribute(NAMESPACE);
|
||||||
xml.closeEmptyElement();
|
xml.closeEmptyElement();
|
||||||
}
|
|
||||||
if (message != null) {
|
addDescriptiveTextsAndExtensions(xml);
|
||||||
xml.halfOpenElement(Packet.TEXT);
|
|
||||||
xml.xmllangAttribute("en");
|
|
||||||
xml.xmlnsAttribute(NAMESPACE);
|
|
||||||
xml.rightAngleBracket();
|
|
||||||
xml.escape(message);
|
|
||||||
xml.closeElement(Packet.TEXT);
|
|
||||||
}
|
|
||||||
for (PacketExtension element : this.getExtensions()) {
|
|
||||||
xml.append(element.toXML());
|
|
||||||
}
|
|
||||||
xml.closeElement(ERROR);
|
xml.closeElement(ERROR);
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public static XMPPError from(Condition condition, String descriptiveText) {
|
||||||
StringBuilder txt = new StringBuilder();
|
Map<String, String> descriptiveTexts = new HashMap<String, String>();
|
||||||
if (condition != null) {
|
descriptiveTexts.put("en", descriptiveText);
|
||||||
txt.append(condition);
|
return new XMPPError(condition, null, null, null, descriptiveTexts, null);
|
||||||
}
|
|
||||||
if (message != null) {
|
|
||||||
txt.append(" ").append(message);
|
|
||||||
}
|
|
||||||
return txt.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a List of the error extensions attached to the xmppError.
|
|
||||||
* An application MAY provide application-specific error information by including a
|
|
||||||
* properly-namespaced child in the error element.
|
|
||||||
*
|
|
||||||
* @return a List of the error extensions.
|
|
||||||
*/
|
|
||||||
public synchronized List<PacketExtension> getExtensions() {
|
|
||||||
if (applicationExtensions == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(applicationExtensions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first packet extension that matches the specified element name and
|
|
||||||
* namespace, or <tt>null</tt> if it doesn't exist.
|
|
||||||
*
|
|
||||||
* @param elementName the XML element name of the packet extension.
|
|
||||||
* @param namespace the XML element namespace of the packet extension.
|
|
||||||
* @return the extension, or <tt>null</tt> if it doesn't exist.
|
|
||||||
*/
|
|
||||||
public synchronized PacketExtension getExtension(String elementName, String namespace) {
|
|
||||||
if (applicationExtensions == null || elementName == null || namespace == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (PacketExtension ext : applicationExtensions) {
|
|
||||||
if (elementName.equals(ext.getElementName()) && namespace.equals(ext.getNamespace())) {
|
|
||||||
return ext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a packet extension to the error.
|
|
||||||
*
|
|
||||||
* @param extension a packet extension.
|
|
||||||
*/
|
|
||||||
public synchronized void addExtension(PacketExtension extension) {
|
|
||||||
if (applicationExtensions == null) {
|
|
||||||
applicationExtensions = new ArrayList<PacketExtension>();
|
|
||||||
}
|
|
||||||
applicationExtensions.add(extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the packet extension to the error.
|
|
||||||
*
|
|
||||||
* @param extension a packet extension.
|
|
||||||
*/
|
|
||||||
public synchronized void setExtension(List<PacketExtension> extension) {
|
|
||||||
applicationExtensions = extension;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -272,161 +212,60 @@ public class XMPPError {
|
||||||
CANCEL,
|
CANCEL,
|
||||||
MODIFY,
|
MODIFY,
|
||||||
AUTH,
|
AUTH,
|
||||||
CONTINUE
|
CONTINUE;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class to represent predefined error conditions.
|
|
||||||
*/
|
|
||||||
public static class Condition implements CharSequence {
|
|
||||||
|
|
||||||
public static final Condition internal_server_error = new Condition("internal-server-error");
|
|
||||||
public static final Condition forbidden = new Condition("forbidden");
|
|
||||||
public static final Condition bad_request = new Condition("bad-request");
|
|
||||||
public static final Condition conflict = new Condition("conflict");
|
|
||||||
public static final Condition feature_not_implemented = new Condition("feature-not-implemented");
|
|
||||||
public static final Condition gone = new Condition("gone");
|
|
||||||
public static final Condition item_not_found = new Condition("item-not-found");
|
|
||||||
public static final Condition jid_malformed = new Condition("jid-malformed");
|
|
||||||
public static final Condition not_acceptable = new Condition("not-acceptable");
|
|
||||||
public static final Condition not_allowed = new Condition("not-allowed");
|
|
||||||
public static final Condition not_authorized = new Condition("not-authorized");
|
|
||||||
public static final Condition payment_required = new Condition("payment-required");
|
|
||||||
public static final Condition recipient_unavailable = new Condition("recipient-unavailable");
|
|
||||||
public static final Condition redirect = new Condition("redirect");
|
|
||||||
public static final Condition registration_required = new Condition("registration-required");
|
|
||||||
public static final Condition remote_server_error = new Condition("remote-server-error");
|
|
||||||
public static final Condition remote_server_not_found = new Condition("remote-server-not-found");
|
|
||||||
public static final Condition remote_server_timeout = new Condition("remote-server-timeout");
|
|
||||||
public static final Condition resource_constraint = new Condition("resource-constraint");
|
|
||||||
public static final Condition service_unavailable = new Condition("service-unavailable");
|
|
||||||
public static final Condition subscription_required = new Condition("subscription-required");
|
|
||||||
public static final Condition undefined_condition = new Condition("undefined-condition");
|
|
||||||
public static final Condition unexpected_request = new Condition("unexpected-request");
|
|
||||||
public static final Condition request_timeout = new Condition("request-timeout");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
public Condition(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return value;
|
// Locale.US not required, since Type consists only of ASCII chars
|
||||||
|
return name().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Type fromString(String string) {
|
||||||
|
// Locale.US not required, since Type consists only of ASCII chars
|
||||||
|
string = string.toUpperCase();
|
||||||
|
return Type.valueOf(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Condition {
|
||||||
|
bad_request,
|
||||||
|
conflict,
|
||||||
|
feature_not_implemented,
|
||||||
|
forbidden,
|
||||||
|
gone,
|
||||||
|
internal_server_error,
|
||||||
|
item_not_found,
|
||||||
|
jid_malformed,
|
||||||
|
not_acceptable,
|
||||||
|
not_allowed,
|
||||||
|
not_authorized,
|
||||||
|
policy_violation,
|
||||||
|
recipient_unavailable,
|
||||||
|
redirect,
|
||||||
|
registration_required,
|
||||||
|
remote_server_not_found,
|
||||||
|
remote_server_timeout,
|
||||||
|
resource_constraint,
|
||||||
|
service_unavailable,
|
||||||
|
subscription_required,
|
||||||
|
undefined_condition,
|
||||||
|
unexpected_request;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public String toString() {
|
||||||
if (other == null) {
|
return this.name().replace('_', '-');
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return toString().equals(other.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(CharSequence other) {
|
public static Condition fromString(String string) {
|
||||||
return StringUtils.nullSafeCharSequenceEquals(this, other);
|
string = string.replace('-', '_');
|
||||||
|
Condition condition = null;
|
||||||
|
try {
|
||||||
|
condition = Condition.valueOf(string);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Could not transform string '" + string + "' to XMPPErrorConditoin", e);
|
||||||
}
|
}
|
||||||
|
return condition;
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return value.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int length() {
|
|
||||||
return value.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char charAt(int index) {
|
|
||||||
return value.charAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence subSequence(int start, int end) {
|
|
||||||
return value.subSequence(start, end);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class to represent the error specification used to infer common usage.
|
|
||||||
*/
|
|
||||||
private static class ErrorSpecification {
|
|
||||||
private static Map<Condition, ErrorSpecification> instances = new HashMap<Condition, ErrorSpecification>();
|
|
||||||
|
|
||||||
private final Type type;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Condition condition;
|
|
||||||
|
|
||||||
private ErrorSpecification(Condition condition, Type type) {
|
|
||||||
this.type = type;
|
|
||||||
this.condition = condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
instances.put(Condition.internal_server_error, new ErrorSpecification(
|
|
||||||
Condition.internal_server_error, Type.WAIT));
|
|
||||||
instances.put(Condition.forbidden, new ErrorSpecification(Condition.forbidden,
|
|
||||||
Type.AUTH));
|
|
||||||
instances.put(Condition.bad_request, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.bad_request, Type.MODIFY));
|
|
||||||
instances.put(Condition.item_not_found, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.item_not_found, Type.CANCEL));
|
|
||||||
instances.put(Condition.conflict, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.conflict, Type.CANCEL));
|
|
||||||
instances.put(Condition.feature_not_implemented, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.feature_not_implemented, Type.CANCEL));
|
|
||||||
instances.put(Condition.gone, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.gone, Type.MODIFY));
|
|
||||||
instances.put(Condition.jid_malformed, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.jid_malformed, Type.MODIFY));
|
|
||||||
instances.put(Condition.not_acceptable, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.not_acceptable, Type.MODIFY));
|
|
||||||
instances.put(Condition.not_allowed, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.not_allowed, Type.CANCEL));
|
|
||||||
instances.put(Condition.not_authorized, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.not_authorized, Type.AUTH));
|
|
||||||
instances.put(Condition.payment_required, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.payment_required, Type.AUTH));
|
|
||||||
instances.put(Condition.recipient_unavailable, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.recipient_unavailable, Type.WAIT));
|
|
||||||
instances.put(Condition.redirect, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.redirect, Type.MODIFY));
|
|
||||||
instances.put(Condition.registration_required, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.registration_required, Type.AUTH));
|
|
||||||
instances.put(Condition.remote_server_not_found, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.remote_server_not_found, Type.CANCEL));
|
|
||||||
instances.put(Condition.remote_server_timeout, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.remote_server_timeout, Type.WAIT));
|
|
||||||
instances.put(Condition.remote_server_error, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.remote_server_error, Type.CANCEL));
|
|
||||||
instances.put(Condition.resource_constraint, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.resource_constraint, Type.WAIT));
|
|
||||||
instances.put(Condition.service_unavailable, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.service_unavailable, Type.CANCEL));
|
|
||||||
instances.put(Condition.subscription_required, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.subscription_required, Type.AUTH));
|
|
||||||
instances.put(Condition.undefined_condition, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.undefined_condition, Type.WAIT));
|
|
||||||
instances.put(Condition.unexpected_request, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.unexpected_request, Type.WAIT));
|
|
||||||
instances.put(Condition.request_timeout, new XMPPError.ErrorSpecification(
|
|
||||||
Condition.request_timeout, Type.CANCEL));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static ErrorSpecification specFor(Condition condition) {
|
|
||||||
return instances.get(condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the error type.
|
|
||||||
*
|
|
||||||
* @return the error type.
|
|
||||||
*/
|
|
||||||
protected Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.sasl.packet;
|
package org.jivesoftware.smack.sasl.packet;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.AbstractError;
|
||||||
import org.jivesoftware.smack.packet.PlainStreamElement;
|
import org.jivesoftware.smack.packet.PlainStreamElement;
|
||||||
import org.jivesoftware.smack.sasl.SASLError;
|
import org.jivesoftware.smack.sasl.SASLError;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
@ -31,7 +30,7 @@ public class SaslStreamElements {
|
||||||
/**
|
/**
|
||||||
* Initiating SASL authentication by select a mechanism.
|
* Initiating SASL authentication by select a mechanism.
|
||||||
*/
|
*/
|
||||||
public static class AuthMechanism extends PlainStreamElement {
|
public static class AuthMechanism implements PlainStreamElement {
|
||||||
public static final String ELEMENT = "auth";
|
public static final String ELEMENT = "auth";
|
||||||
|
|
||||||
private final String mechanism;
|
private final String mechanism;
|
||||||
|
@ -69,7 +68,7 @@ public class SaslStreamElements {
|
||||||
/**
|
/**
|
||||||
* A SASL challenge stream element.
|
* A SASL challenge stream element.
|
||||||
*/
|
*/
|
||||||
public static class Challenge extends PlainStreamElement {
|
public static class Challenge implements PlainStreamElement {
|
||||||
public static final String ELEMENT = "challenge";
|
public static final String ELEMENT = "challenge";
|
||||||
|
|
||||||
private final String data;
|
private final String data;
|
||||||
|
@ -91,7 +90,7 @@ public class SaslStreamElements {
|
||||||
/**
|
/**
|
||||||
* A SASL response stream element.
|
* A SASL response stream element.
|
||||||
*/
|
*/
|
||||||
public static class Response extends PlainStreamElement {
|
public static class Response implements PlainStreamElement {
|
||||||
public static final String ELEMENT = "response";
|
public static final String ELEMENT = "response";
|
||||||
|
|
||||||
private final String authenticationText;
|
private final String authenticationText;
|
||||||
|
@ -121,7 +120,7 @@ public class SaslStreamElements {
|
||||||
/**
|
/**
|
||||||
* A SASL success stream element.
|
* A SASL success stream element.
|
||||||
*/
|
*/
|
||||||
public static class Success extends PlainStreamElement {
|
public static class Success implements PlainStreamElement {
|
||||||
public static final String ELEMENT = "success";
|
public static final String ELEMENT = "success";
|
||||||
|
|
||||||
final private String data;
|
final private String data;
|
||||||
|
@ -156,25 +155,21 @@ public class SaslStreamElements {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A SASL failure stream element.
|
* A SASL failure stream element, also called "SASL Error"
|
||||||
|
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#sasl-errors">RFC 6120 6.5 SASL Errors</a>
|
||||||
*/
|
*/
|
||||||
public static class SASLFailure extends PlainStreamElement {
|
public static class SASLFailure extends AbstractError implements PlainStreamElement {
|
||||||
public static final String ELEMENT = "failure";
|
public static final String ELEMENT = "failure";
|
||||||
|
|
||||||
private final SASLError saslError;
|
private final SASLError saslError;
|
||||||
private final String saslErrorString;
|
private final String saslErrorString;
|
||||||
private final Map<String, String> descriptiveTexts;
|
|
||||||
|
|
||||||
public SASLFailure(String saslError) {
|
public SASLFailure(String saslError) {
|
||||||
this(saslError, null);
|
this(saslError, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SASLFailure(String saslError, Map<String, String> descriptiveTexts) {
|
public SASLFailure(String saslError, Map<String, String> descriptiveTexts) {
|
||||||
if (descriptiveTexts != null) {
|
super(descriptiveTexts);
|
||||||
this.descriptiveTexts = descriptiveTexts;
|
|
||||||
} else {
|
|
||||||
this.descriptiveTexts = Collections.emptyMap();
|
|
||||||
}
|
|
||||||
SASLError error = SASLError.fromString(saslError);
|
SASLError error = SASLError.fromString(saslError);
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
// RFC6120 6.5 states that unknown condition must be treat as generic authentication
|
// RFC6120 6.5 states that unknown condition must be treat as generic authentication
|
||||||
|
@ -203,50 +198,19 @@ public class SaslStreamElements {
|
||||||
return saslErrorString;
|
return saslErrorString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the descriptive text of this SASLFailure.
|
|
||||||
* <p>
|
|
||||||
* Returns the descriptive text of this SASLFailure in the system default language if possible. May return null.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return the descriptive text or null.
|
|
||||||
*/
|
|
||||||
public String getDescriptiveText() {
|
|
||||||
String defaultLocale = Locale.getDefault().getLanguage();
|
|
||||||
String descriptiveText = getDescriptiveText(defaultLocale);
|
|
||||||
if (descriptiveText == null) {
|
|
||||||
descriptiveText = getDescriptiveText(null);
|
|
||||||
}
|
|
||||||
return descriptiveText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the descriptive test of this SASLFailure.
|
|
||||||
* <p>
|
|
||||||
* Returns the descriptive text of this SASLFailure in the given language. May return null if not available.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param xmllang the language.
|
|
||||||
* @return the descriptive text or null.
|
|
||||||
*/
|
|
||||||
public String getDescriptiveText(String xmllang) {
|
|
||||||
return descriptiveTexts.get(xmllang);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XmlStringBuilder toXML() {
|
public XmlStringBuilder toXML() {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder();
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket();
|
xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket();
|
||||||
xml.emptyElement(saslErrorString);
|
xml.emptyElement(saslErrorString);
|
||||||
for (Map.Entry<String, String> entry : descriptiveTexts.entrySet()) {
|
addDescriptiveTextsAndExtensions(xml);
|
||||||
String xmllang = entry.getKey();
|
|
||||||
String text = entry.getValue();
|
|
||||||
xml.halfOpenElement("text").xmllangAttribute(xmllang).rightAngleBracket();
|
|
||||||
xml.escape(text);
|
|
||||||
xml.closeElement("text");
|
|
||||||
}
|
|
||||||
xml.closeElement(ELEMENT);
|
xml.closeElement(ELEMENT);
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toXML().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -762,6 +761,18 @@ public class PacketParserUtils {
|
||||||
return new Compress.Feature(methods);
|
return new Compress.Feature(methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> parseDescriptiveTexts(XmlPullParser parser, Map<String, String> descriptiveTexts)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
if (descriptiveTexts == null) {
|
||||||
|
descriptiveTexts = new HashMap<String, String>();
|
||||||
|
}
|
||||||
|
String xmllang = getLanguageAttribute(parser);
|
||||||
|
String text = parser.nextText();
|
||||||
|
String previousValue = descriptiveTexts.put(xmllang, text);
|
||||||
|
assert (previousValue == null);
|
||||||
|
return descriptiveTexts;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses SASL authentication error packets.
|
* Parses SASL authentication error packets.
|
||||||
*
|
*
|
||||||
|
@ -773,17 +784,14 @@ public class PacketParserUtils {
|
||||||
public static SASLFailure parseSASLFailure(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static SASLFailure parseSASLFailure(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
final int initialDepth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
String condition = null;
|
String condition = null;
|
||||||
Map<String, String> descriptiveTexts = new HashMap<String, String>();
|
Map<String, String> descriptiveTexts = null;
|
||||||
outerloop: while (true) {
|
outerloop: while (true) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case XmlPullParser.START_TAG:
|
case XmlPullParser.START_TAG:
|
||||||
String name = parser.getName();
|
String name = parser.getName();
|
||||||
if (name.equals("text")) {
|
if (name.equals("text")) {
|
||||||
String xmllang = getLanguageAttribute(parser);
|
descriptiveTexts = parseDescriptiveTexts(parser, descriptiveTexts);
|
||||||
String text = parser.nextText();
|
|
||||||
String previousValue = descriptiveTexts.put(xmllang, text);
|
|
||||||
assert(previousValue == null);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(condition == null);
|
assert(condition == null);
|
||||||
|
@ -806,36 +814,50 @@ public class PacketParserUtils {
|
||||||
* @param parser the XML parser.
|
* @param parser the XML parser.
|
||||||
* @return an stream error packet.
|
* @return an stream error packet.
|
||||||
* @throws XmlPullParserException if an exception occurs while parsing the packet.
|
* @throws XmlPullParserException if an exception occurs while parsing the packet.
|
||||||
|
* @throws SmackException
|
||||||
*/
|
*/
|
||||||
public static StreamError parseStreamError(XmlPullParser parser) throws IOException,
|
public static StreamError parseStreamError(XmlPullParser parser) throws IOException, XmlPullParserException,
|
||||||
XmlPullParserException {
|
SmackException {
|
||||||
final int depth = parser.getDepth();
|
final int initialDepth = parser.getDepth();
|
||||||
boolean done = false;
|
List<PacketExtension> extensions = new ArrayList<PacketExtension>();
|
||||||
String code = null;
|
Map<String, String> descriptiveTexts = null;
|
||||||
String text = null;
|
StreamError.Condition condition = null;
|
||||||
while (!done) {
|
String conditionText = null;
|
||||||
|
outerloop: while (true) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
|
switch (eventType) {
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
case XmlPullParser.START_TAG:
|
||||||
String namespace = parser.getNamespace();
|
|
||||||
if (StreamError.NAMESPACE.equals(namespace)) {
|
|
||||||
String name = parser.getName();
|
String name = parser.getName();
|
||||||
if (name.equals(Packet.TEXT) && !parser.isEmptyElementTag()) {
|
String namespace = parser.getNamespace();
|
||||||
parser.next();
|
switch (namespace) {
|
||||||
text = parser.getText();
|
case StreamError.NAMESPACE:
|
||||||
}
|
switch (name) {
|
||||||
else {
|
case "text":
|
||||||
|
descriptiveTexts = parseDescriptiveTexts(parser, descriptiveTexts);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
// If it's not a text element, that is qualified by the StreamError.NAMESPACE,
|
// If it's not a text element, that is qualified by the StreamError.NAMESPACE,
|
||||||
// then it has to be the stream error code
|
// then it has to be the stream error code
|
||||||
code = name;
|
condition = StreamError.Condition.fromString(name);
|
||||||
|
if (!parser.isEmptyElementTag()) {
|
||||||
|
conditionText = parser.nextText();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PacketParserUtils.addPacketExtension(extensions, parser, name, namespace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return new StreamError(condition, conditionText, descriptiveTexts, extensions);
|
||||||
else if (eventType == XmlPullParser.END_TAG && depth == parser.getDepth()) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new StreamError(code, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -849,50 +871,47 @@ public class PacketParserUtils {
|
||||||
*/
|
*/
|
||||||
public static XMPPError parseError(XmlPullParser parser)
|
public static XMPPError parseError(XmlPullParser parser)
|
||||||
throws XmlPullParserException, IOException, SmackException {
|
throws XmlPullParserException, IOException, SmackException {
|
||||||
String type = null;
|
final int initialDepth = parser.getDepth();
|
||||||
String message = null;
|
Map<String, String> descriptiveTexts = null;
|
||||||
String condition = null;
|
XMPPError.Condition condition = null;
|
||||||
|
String conditionText = null;
|
||||||
List<PacketExtension> extensions = new ArrayList<PacketExtension>();
|
List<PacketExtension> extensions = new ArrayList<PacketExtension>();
|
||||||
|
|
||||||
// Parse the error header
|
// Parse the error header
|
||||||
type = parser.getAttributeValue("", "type");
|
XMPPError.Type errorType = XMPPError.Type.fromString(parser.getAttributeValue("", "type"));
|
||||||
// Parse the text and condition tags
|
String errorGenerator = parser.getAttributeValue("", "by");
|
||||||
outerloop:
|
|
||||||
while (true) {
|
outerloop: while (true) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
switch (eventType) {
|
||||||
if (parser.getName().equals(Packet.TEXT)) {
|
case XmlPullParser.START_TAG:
|
||||||
message = parser.nextText();
|
String name = parser.getName();
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Condition tag, it can be xmpp error or an application defined error.
|
|
||||||
String elementName = parser.getName();
|
|
||||||
String namespace = parser.getNamespace();
|
String namespace = parser.getNamespace();
|
||||||
if (namespace.equals(XMPPError.NAMESPACE)) {
|
switch (namespace) {
|
||||||
condition = elementName;
|
case XMPPError.NAMESPACE:
|
||||||
|
switch (name) {
|
||||||
|
case Packet.TEXT:
|
||||||
|
descriptiveTexts = parseDescriptiveTexts(parser, descriptiveTexts);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
condition = XMPPError.Condition.fromString(name);
|
||||||
|
if (!parser.isEmptyElementTag()) {
|
||||||
|
conditionText = parser.nextText();
|
||||||
}
|
}
|
||||||
else {
|
break;
|
||||||
PacketParserUtils.addPacketExtension(extensions, parser, elementName, namespace);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PacketParserUtils.addPacketExtension(extensions, parser, name, namespace);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else if (eventType == XmlPullParser.END_TAG) {
|
case XmlPullParser.END_TAG:
|
||||||
if (parser.getName().equals("error")) {
|
if (parser.getDepth() == initialDepth) {
|
||||||
break outerloop;
|
break outerloop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Parse the error type.
|
return new XMPPError(condition, conditionText, errorGenerator, errorType, descriptiveTexts, extensions);
|
||||||
XMPPError.Type errorType = XMPPError.Type.CANCEL;
|
|
||||||
try {
|
|
||||||
if (type != null) {
|
|
||||||
errorType = XMPPError.Type.valueOf(type.toUpperCase(Locale.US));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException iae) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Could not find error type for " + type.toUpperCase(Locale.US), iae);
|
|
||||||
}
|
|
||||||
return new XMPPError(errorType, condition, message, extensions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.StreamError.Condition;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
@ -44,7 +45,7 @@ public class StreamErrorTest {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
assertNotNull(error);
|
assertNotNull(error);
|
||||||
assertEquals("conflict", error.getCode());
|
assertEquals(Condition.conflict, error.getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -68,8 +69,8 @@ public class StreamErrorTest {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
assertNotNull(error);
|
assertNotNull(error);
|
||||||
assertEquals("conflict", error.getCode());
|
assertEquals(Condition.conflict, error.getCondition());
|
||||||
assertEquals("Replaced by new connection", error.getText());
|
assertEquals("Replaced by new connection", error.getDescriptiveText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,7 +85,7 @@ public class StreamErrorTest {
|
||||||
"<text xml:lang='' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>" +
|
"<text xml:lang='' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>" +
|
||||||
"Replaced by new connection" +
|
"Replaced by new connection" +
|
||||||
"</text>" +
|
"</text>" +
|
||||||
"<appSpecificElement>" +
|
"<appSpecificElement xmlns='myns'>" +
|
||||||
"Text contents of application-specific condition element: Foo Bar" +
|
"Text contents of application-specific condition element: Foo Bar" +
|
||||||
"</appSpecificElement>" +
|
"</appSpecificElement>" +
|
||||||
"</stream:error>" +
|
"</stream:error>" +
|
||||||
|
@ -96,10 +97,10 @@ public class StreamErrorTest {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
assertNotNull(error);
|
assertNotNull(error);
|
||||||
assertEquals("conflict", error.getCode());
|
assertEquals(Condition.conflict, error.getCondition());
|
||||||
assertEquals("Replaced by new connection", error.getText());
|
assertEquals("Replaced by new connection", error.getDescriptiveText());
|
||||||
// As of now, Smack ignores application-specific condition elements, so we don't
|
PacketExtension appSpecificElement = error.getExtension("appSpecificElement", "myns");
|
||||||
// test them.
|
assertNotNull(appSpecificElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,7 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
*/
|
*/
|
||||||
private void cancelRequest() throws XMPPErrorException, NotConnectedException {
|
private void cancelRequest() throws XMPPErrorException, NotConnectedException {
|
||||||
String errorMessage = "Could not establish socket with any provided host";
|
String errorMessage = "Could not establish socket with any provided host";
|
||||||
XMPPError error = new XMPPError(XMPPError.Condition.item_not_found, errorMessage);
|
XMPPError error = XMPPError.from(XMPPError.Condition.item_not_found, errorMessage);
|
||||||
IQ errorIQ = IQ.createErrorResponse(this.bytestreamRequest, error);
|
IQ errorIQ = IQ.createErrorResponse(this.bytestreamRequest, error);
|
||||||
this.manager.getConnection().sendPacket(errorIQ);
|
this.manager.getConnection().sendPacket(errorIQ);
|
||||||
throw new XMPPErrorException(errorMessage, error);
|
throw new XMPPErrorException(errorMessage, error);
|
||||||
|
|
|
@ -593,8 +593,7 @@ public class AdHocCommandManager extends Manager {
|
||||||
private void respondError(AdHocCommandData response, XMPPError.Condition condition,
|
private void respondError(AdHocCommandData response, XMPPError.Condition condition,
|
||||||
AdHocCommand.SpecificErrorCondition specificCondition) throws NotConnectedException
|
AdHocCommand.SpecificErrorCondition specificCondition) throws NotConnectedException
|
||||||
{
|
{
|
||||||
XMPPError error = new XMPPError(condition);
|
XMPPError error = new XMPPError(condition, new AdHocCommandData.SpecificError(specificCondition));
|
||||||
error.addExtension(new AdHocCommandData.SpecificError(specificCondition));
|
|
||||||
respondError(response, error);
|
respondError(response, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2014 Florian Schmaus
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.filetransfer;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
|
||||||
|
public abstract class FileTransferException extends SmackException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public static class NoStreamMethodsOfferedException extends FileTransferException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoAcceptableTransferMechanisms extends FileTransferException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,8 @@ import org.jivesoftware.smack.packet.XMPPError;
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
|
import org.jivesoftware.smackx.bytestreams.ibb.packet.DataPacketExtension;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.filetransfer.FileTransferException.NoAcceptableTransferMechanisms;
|
||||||
|
import org.jivesoftware.smackx.filetransfer.FileTransferException.NoStreamMethodsOfferedException;
|
||||||
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
import org.jivesoftware.smackx.si.packet.StreamInitiation;
|
||||||
import org.jivesoftware.smackx.xdata.Form;
|
import org.jivesoftware.smackx.xdata.Form;
|
||||||
import org.jivesoftware.smackx.xdata.FormField;
|
import org.jivesoftware.smackx.xdata.FormField;
|
||||||
|
@ -176,32 +178,32 @@ public class FileTransferNegotiator extends Manager {
|
||||||
*
|
*
|
||||||
* @param request The related file transfer request.
|
* @param request The related file transfer request.
|
||||||
* @return The file transfer object that handles the transfer
|
* @return The file transfer object that handles the transfer
|
||||||
* @throws XMPPErrorException If there are either no stream methods contained in the packet, or
|
* @throws NoStreamMethodsOfferedException If there are either no stream methods contained in the packet, or
|
||||||
* there is not an appropriate stream method.
|
* there is not an appropriate stream method.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
|
* @throws NoAcceptableTransferMechanisms
|
||||||
*/
|
*/
|
||||||
public StreamNegotiator selectStreamNegotiator(
|
public StreamNegotiator selectStreamNegotiator(
|
||||||
FileTransferRequest request) throws XMPPErrorException, NotConnectedException {
|
FileTransferRequest request) throws NotConnectedException, NoStreamMethodsOfferedException, NoAcceptableTransferMechanisms {
|
||||||
StreamInitiation si = request.getStreamInitiation();
|
StreamInitiation si = request.getStreamInitiation();
|
||||||
FormField streamMethodField = getStreamMethodField(si
|
FormField streamMethodField = getStreamMethodField(si
|
||||||
.getFeatureNegotiationForm());
|
.getFeatureNegotiationForm());
|
||||||
|
|
||||||
if (streamMethodField == null) {
|
if (streamMethodField == null) {
|
||||||
String errorMessage = "No stream methods contained in packet.";
|
String errorMessage = "No stream methods contained in stanza.";
|
||||||
XMPPError error = new XMPPError(XMPPError.Condition.bad_request, errorMessage);
|
XMPPError error = XMPPError.from(XMPPError.Condition.bad_request, errorMessage);
|
||||||
IQ iqPacket = IQ.createErrorResponse(si, error);
|
IQ iqPacket = IQ.createErrorResponse(si, error);
|
||||||
connection().sendPacket(iqPacket);
|
connection().sendPacket(iqPacket);
|
||||||
throw new XMPPErrorException(errorMessage, error);
|
throw new FileTransferException.NoStreamMethodsOfferedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// select the appropriate protocol
|
// select the appropriate protocol
|
||||||
|
|
||||||
StreamNegotiator selectedStreamNegotiator;
|
StreamNegotiator selectedStreamNegotiator;
|
||||||
try {
|
try {
|
||||||
selectedStreamNegotiator = getNegotiator(streamMethodField);
|
selectedStreamNegotiator = getNegotiator(streamMethodField);
|
||||||
}
|
}
|
||||||
catch (XMPPErrorException e) {
|
catch (NoAcceptableTransferMechanisms e) {
|
||||||
IQ iqPacket = IQ.createErrorResponse(si, e.getXMPPError());
|
IQ iqPacket = IQ.createErrorResponse(si, XMPPError.from(XMPPError.Condition.bad_request, "No acceptable transfer mechanism"));
|
||||||
connection().sendPacket(iqPacket);
|
connection().sendPacket(iqPacket);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +223,7 @@ public class FileTransferNegotiator extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StreamNegotiator getNegotiator(final FormField field)
|
private StreamNegotiator getNegotiator(final FormField field)
|
||||||
throws XMPPErrorException {
|
throws NoAcceptableTransferMechanisms {
|
||||||
String variable;
|
String variable;
|
||||||
boolean isByteStream = false;
|
boolean isByteStream = false;
|
||||||
boolean isIBB = false;
|
boolean isIBB = false;
|
||||||
|
@ -236,9 +238,7 @@ public class FileTransferNegotiator extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isByteStream && !isIBB) {
|
if (!isByteStream && !isIBB) {
|
||||||
XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
|
throw new FileTransferException.NoAcceptableTransferMechanisms();
|
||||||
"No acceptable transfer mechanism");
|
|
||||||
throw new XMPPErrorException(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isByteStream && isIBB) {
|
if (isByteStream && isIBB) {
|
||||||
|
@ -299,10 +299,11 @@ public class FileTransferNegotiator extends Manager {
|
||||||
* @throws XMPPErrorException Thrown if there is an error negotiating the file transfer.
|
* @throws XMPPErrorException Thrown if there is an error negotiating the file transfer.
|
||||||
* @throws NotConnectedException
|
* @throws NotConnectedException
|
||||||
* @throws NoResponseException
|
* @throws NoResponseException
|
||||||
|
* @throws NoAcceptableTransferMechanisms
|
||||||
*/
|
*/
|
||||||
public StreamNegotiator negotiateOutgoingTransfer(final String userID,
|
public StreamNegotiator negotiateOutgoingTransfer(final String userID,
|
||||||
final String streamID, final String fileName, final long size,
|
final String streamID, final String fileName, final long size,
|
||||||
final String desc, int responseTimeout) throws XMPPErrorException, NotConnectedException, NoResponseException {
|
final String desc, int responseTimeout) throws XMPPErrorException, NotConnectedException, NoResponseException, NoAcceptableTransferMechanisms {
|
||||||
StreamInitiation si = new StreamInitiation();
|
StreamInitiation si = new StreamInitiation();
|
||||||
si.setSessionID(streamID);
|
si.setSessionID(streamID);
|
||||||
si.setMimeType(URLConnection.guessContentTypeFromName(fileName));
|
si.setMimeType(URLConnection.guessContentTypeFromName(fileName));
|
||||||
|
@ -337,8 +338,7 @@ public class FileTransferNegotiator extends Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StreamNegotiator getOutgoingNegotiator(final FormField field)
|
private StreamNegotiator getOutgoingNegotiator(final FormField field) throws NoAcceptableTransferMechanisms {
|
||||||
throws XMPPErrorException {
|
|
||||||
boolean isByteStream = false;
|
boolean isByteStream = false;
|
||||||
boolean isIBB = false;
|
boolean isIBB = false;
|
||||||
for (String variable : field.getValues()) {
|
for (String variable : field.getValues()) {
|
||||||
|
@ -351,9 +351,7 @@ public class FileTransferNegotiator extends Manager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isByteStream && !isIBB) {
|
if (!isByteStream && !isIBB) {
|
||||||
XMPPError error = new XMPPError(XMPPError.Condition.bad_request,
|
throw new FileTransferException.NoAcceptableTransferMechanisms();
|
||||||
"No acceptable transfer mechanism");
|
|
||||||
throw new XMPPErrorException(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isByteStream && isIBB) {
|
if (isByteStream && isIBB) {
|
||||||
|
|
|
@ -341,16 +341,15 @@ public class OutgoingFileTransfer extends FileTransfer {
|
||||||
private void handleXMPPException(XMPPErrorException e) {
|
private void handleXMPPException(XMPPErrorException e) {
|
||||||
XMPPError error = e.getXMPPError();
|
XMPPError error = e.getXMPPError();
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
String condition = error.getCondition();
|
switch (error.getCondition()) {
|
||||||
if (XMPPError.Condition.forbidden.equals(condition)) {
|
case forbidden:
|
||||||
setStatus(Status.refused);
|
setStatus(Status.refused);
|
||||||
return;
|
return;
|
||||||
}
|
case bad_request:
|
||||||
else if (XMPPError.Condition.bad_request.equals(condition)) {
|
|
||||||
setStatus(Status.error);
|
setStatus(Status.error);
|
||||||
setError(Error.not_acceptable);
|
setError(Error.not_acceptable);
|
||||||
}
|
break;
|
||||||
else {
|
default:
|
||||||
setStatus(FileTransfer.Status.error);
|
setStatus(FileTransfer.Status.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class CloseListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class DataListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class InBandBytestreamManagerTest {
|
||||||
fail("exception should be thrown");
|
fail("exception should be thrown");
|
||||||
}
|
}
|
||||||
catch (XMPPErrorException e) {
|
catch (XMPPErrorException e) {
|
||||||
assertEquals(XMPPError.Condition.feature_not_implemented.toString(),
|
assertEquals(XMPPError.Condition.feature_not_implemented,
|
||||||
e.getXMPPError().getCondition());
|
e.getXMPPError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class InBandBytestreamRequestTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.not_acceptable.toString(),
|
assertEquals(XMPPError.Condition.not_acceptable,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,7 +368,7 @@ public class InBandBytestreamSessionTest {
|
||||||
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
|
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
|
||||||
|
|
||||||
public void verify(IQ request, IQ response) {
|
public void verify(IQ request, IQ response) {
|
||||||
assertEquals(XMPPError.Condition.unexpected_request.toString(),
|
assertEquals(XMPPError.Condition.unexpected_request,
|
||||||
request.getError().getCondition());
|
request.getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ public class InBandBytestreamSessionTest {
|
||||||
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
|
protocol.addResponse(null, Verification.requestTypeERROR, new Verification<IQ, IQ>() {
|
||||||
|
|
||||||
public void verify(IQ request, IQ response) {
|
public void verify(IQ request, IQ response) {
|
||||||
assertEquals(XMPPError.Condition.bad_request.toString(),
|
assertEquals(XMPPError.Condition.bad_request,
|
||||||
request.getError().getCondition());
|
request.getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class InitiationListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.not_acceptable.toString(),
|
assertEquals(XMPPError.Condition.not_acceptable,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ public class InitiationListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.resource_constraint.toString(),
|
assertEquals(XMPPError.Condition.resource_constraint,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ public class InitiationListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.not_acceptable.toString(),
|
assertEquals(XMPPError.Condition.not_acceptable,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class InitiationListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.not_acceptable.toString(),
|
assertEquals(XMPPError.Condition.not_acceptable,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ public class InitiationListenerTest {
|
||||||
// assert that reply is the correct error packet
|
// assert that reply is the correct error packet
|
||||||
assertEquals(initiatorJID, argument.getValue().getTo());
|
assertEquals(initiatorJID, argument.getValue().getTo());
|
||||||
assertEquals(IQ.Type.error, argument.getValue().getType());
|
assertEquals(IQ.Type.error, argument.getValue().getType());
|
||||||
assertEquals(XMPPError.Condition.not_acceptable.toString(),
|
assertEquals(XMPPError.Condition.not_acceptable,
|
||||||
argument.getValue().getError().getCondition());
|
argument.getValue().getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertTrue(IQ.class.isInstance(targetResponse));
|
assertTrue(IQ.class.isInstance(targetResponse));
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
((IQ) targetResponse).getError().getCondition());
|
((IQ) targetResponse).getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertTrue(IQ.class.isInstance(targetResponse));
|
assertTrue(IQ.class.isInstance(targetResponse));
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
((IQ) targetResponse).getError().getCondition());
|
((IQ) targetResponse).getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertTrue(IQ.class.isInstance(targetResponse));
|
assertTrue(IQ.class.isInstance(targetResponse));
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
((IQ) targetResponse).getError().getCondition());
|
((IQ) targetResponse).getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertTrue(IQ.class.isInstance(targetResponse));
|
assertTrue(IQ.class.isInstance(targetResponse));
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(XMPPError.Condition.item_not_found.toString(),
|
assertEquals(XMPPError.Condition.item_not_found,
|
||||||
((IQ) targetResponse).getError().getCondition());
|
((IQ) targetResponse).getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.filter.PacketFilter;
|
import org.jivesoftware.smack.filter.PacketFilter;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Packet;
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
import org.jivesoftware.smack.packet.PacketExtension;
|
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
import org.jivesoftware.smackx.jingleold.listeners.JingleListener;
|
import org.jivesoftware.smackx.jingleold.listeners.JingleListener;
|
||||||
import org.jivesoftware.smackx.jingleold.listeners.JingleMediaListener;
|
import org.jivesoftware.smackx.jingleold.listeners.JingleMediaListener;
|
||||||
|
@ -1030,9 +1029,8 @@ public class JingleSession extends JingleNegotiator implements MediaReceivedList
|
||||||
public IQ createJingleError(IQ iq, JingleError jingleError) {
|
public IQ createJingleError(IQ iq, JingleError jingleError) {
|
||||||
IQ errorPacket = null;
|
IQ errorPacket = null;
|
||||||
if (jingleError != null) {
|
if (jingleError != null) {
|
||||||
List<PacketExtension> extList = new ArrayList<PacketExtension>();
|
// TODO This is wrong according to XEP-166 § 10, but this jingle implementation is deprecated anyways
|
||||||
extList.add(jingleError);
|
XMPPError error = new XMPPError(XMPPError.Condition.undefined_condition, jingleError);
|
||||||
XMPPError error = new XMPPError(XMPPError.Type.CANCEL, jingleError.toString(), "", extList);
|
|
||||||
|
|
||||||
errorPacket = IQ.createErrorResponse(iq, error);
|
errorPacket = IQ.createErrorResponse(iq, error);
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class MediaNegotiator extends JingleNegotiator {
|
||||||
setNegotiatorState(JingleNegotiatorState.FAILED);
|
setNegotiatorState(JingleNegotiatorState.FAILED);
|
||||||
triggerMediaClosed(getBestCommonAudioPt());
|
triggerMediaClosed(getBestCommonAudioPt());
|
||||||
// This next line seems wrong, and may subvert the normal closing process.
|
// This next line seems wrong, and may subvert the normal closing process.
|
||||||
throw new JingleException(iq.getError().getMessage());
|
throw new JingleException(iq.getError().getDescriptiveText());
|
||||||
} else if (iq.getType().equals(IQ.Type.result)) {
|
} else if (iq.getType().equals(IQ.Type.result)) {
|
||||||
// Process ACKs
|
// Process ACKs
|
||||||
if (isExpectedId(iq.getPacketID())) {
|
if (isExpectedId(iq.getPacketID())) {
|
||||||
|
|
|
@ -603,7 +603,7 @@ public abstract class TransportNegotiator extends JingleNegotiator {
|
||||||
setNegotiatorState(JingleNegotiatorState.FAILED);
|
setNegotiatorState(JingleNegotiatorState.FAILED);
|
||||||
triggerTransportClosed(null);
|
triggerTransportClosed(null);
|
||||||
// This next line seems wrong, and may subvert the normal closing process.
|
// This next line seems wrong, and may subvert the normal closing process.
|
||||||
throw new JingleException(iq.getError().getMessage());
|
throw new JingleException(iq.getError().getDescriptiveText());
|
||||||
} else if (iq.getType().equals(IQ.Type.result)) {
|
} else if (iq.getType().equals(IQ.Type.result)) {
|
||||||
// Process ACKs
|
// Process ACKs
|
||||||
if (isExpectedId(iq.getPacketID())) {
|
if (isExpectedId(iq.getPacketID())) {
|
||||||
|
|
|
@ -1101,7 +1101,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
break;
|
break;
|
||||||
case Failed.ELEMENT:
|
case Failed.ELEMENT:
|
||||||
Failed failed = ParseStreamManagement.failed(parser);
|
Failed failed = ParseStreamManagement.failed(parser);
|
||||||
XMPPError xmppError = failed.getXMPPError();
|
XMPPError xmppError = new XMPPError(failed.getXMPPErrorCondition());
|
||||||
XMPPException xmppException = new XMPPErrorException("Stream Management failed", xmppError);
|
XMPPException xmppException = new XMPPErrorException("Stream Management failed", xmppError);
|
||||||
// If only XEP-198 would specify different failure elements for the SM
|
// If only XEP-198 would specify different failure elements for the SM
|
||||||
// enable and SM resume failure case. But this is not the case, so we
|
// enable and SM resume failure case. But this is not the case, so we
|
||||||
|
|
|
@ -189,25 +189,26 @@ public class StreamManagement {
|
||||||
public static class Failed extends FullStreamElement {
|
public static class Failed extends FullStreamElement {
|
||||||
public static final String ELEMENT = "failed";
|
public static final String ELEMENT = "failed";
|
||||||
|
|
||||||
private XMPPError error;
|
private XMPPError.Condition condition;
|
||||||
|
|
||||||
public Failed() {
|
public Failed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Failed(XMPPError error) {
|
public Failed(XMPPError.Condition condition) {
|
||||||
this.error = error;
|
this.condition = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XMPPError getXMPPError() {
|
public XMPPError.Condition getXMPPErrorCondition() {
|
||||||
return error;
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence toXML() {
|
public CharSequence toXML() {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder(this);
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
if (error != null) {
|
if (condition != null) {
|
||||||
xml.rightAngleBracket();
|
xml.rightAngleBracket();
|
||||||
xml.append(error.toXML());
|
xml.append(condition.toString());
|
||||||
|
xml.xmlnsAttribute(XMPPError.NAMESPACE);
|
||||||
xml.closeElement(ELEMENT);
|
xml.closeElement(ELEMENT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class ParseStreamManagement {
|
||||||
public static Failed failed(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static Failed failed(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
ParserUtils.assertAtStartTag(parser);
|
ParserUtils.assertAtStartTag(parser);
|
||||||
String name;
|
String name;
|
||||||
String condition = "unknown";
|
XMPPError.Condition condition = null;
|
||||||
outerloop:
|
outerloop:
|
||||||
while(true) {
|
while(true) {
|
||||||
int event = parser.next();
|
int event = parser.next();
|
||||||
|
@ -53,7 +53,7 @@ public class ParseStreamManagement {
|
||||||
name = parser.getName();
|
name = parser.getName();
|
||||||
String namespace = parser.getNamespace();
|
String namespace = parser.getNamespace();
|
||||||
if (XMPPError.NAMESPACE.equals(namespace)) {
|
if (XMPPError.NAMESPACE.equals(namespace)) {
|
||||||
condition = name;
|
condition = XMPPError.Condition.fromString(name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XmlPullParser.END_TAG:
|
case XmlPullParser.END_TAG:
|
||||||
|
@ -65,8 +65,7 @@ public class ParseStreamManagement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParserUtils.assertAtEndTag(parser);
|
ParserUtils.assertAtEndTag(parser);
|
||||||
XMPPError error = new XMPPError(condition);
|
return new Failed(condition);
|
||||||
return new Failed(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Resumed resumed(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static Resumed resumed(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.jivesoftware.smack.tcp.sm.provider;
|
package org.jivesoftware.smack.tcp.sm.provider;
|
||||||
|
|
||||||
import com.jamesmurty.utils.XMLBuilder;
|
import com.jamesmurty.utils.XMLBuilder;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
import org.jivesoftware.smack.tcp.sm.packet.StreamManagement;
|
import org.jivesoftware.smack.tcp.sm.packet.StreamManagement;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
@ -34,6 +35,7 @@ import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class ParseStreamManagementTest {
|
public class ParseStreamManagementTest {
|
||||||
private static final Properties outputProperties = initOutputProperties();
|
private static final Properties outputProperties = initOutputProperties();
|
||||||
|
@ -83,19 +85,16 @@ public class ParseStreamManagementTest {
|
||||||
PacketParserUtils.getParserFor(failedStanza));
|
PacketParserUtils.getParserFor(failedStanza));
|
||||||
|
|
||||||
assertThat(failedPacket, is(notNullValue()));
|
assertThat(failedPacket, is(notNullValue()));
|
||||||
XMPPError error = failedPacket.getXMPPError();
|
assertTrue(failedPacket.getXMPPErrorCondition() == null);
|
||||||
|
|
||||||
assertThat(error, is(notNullValue()));
|
|
||||||
assertThat(error.getCondition(), equalTo("unknown"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseFailedError() throws Exception {
|
public void testParseFailedError() throws Exception {
|
||||||
String errorCondition = "failure";
|
XMPPError.Condition errorCondition = XMPPError.Condition.unexpected_request;
|
||||||
|
|
||||||
String failedStanza = XMLBuilder.create("failed")
|
String failedStanza = XMLBuilder.create("failed")
|
||||||
.a("xmlns", "urn:xmpp:sm:3")
|
.a("xmlns", "urn:xmpp:sm:3")
|
||||||
.element(errorCondition, XMPPError.NAMESPACE)
|
.element(errorCondition.toString(), XMPPError.NAMESPACE)
|
||||||
.asString(outputProperties);
|
.asString(outputProperties);
|
||||||
|
|
||||||
System.err.println(failedStanza);
|
System.err.println(failedStanza);
|
||||||
|
@ -104,10 +103,7 @@ public class ParseStreamManagementTest {
|
||||||
PacketParserUtils.getParserFor(failedStanza));
|
PacketParserUtils.getParserFor(failedStanza));
|
||||||
|
|
||||||
assertThat(failedPacket, is(notNullValue()));
|
assertThat(failedPacket, is(notNullValue()));
|
||||||
XMPPError error = failedPacket.getXMPPError();
|
assertTrue(failedPacket.getXMPPErrorCondition() == errorCondition);
|
||||||
|
|
||||||
assertThat(error, is(notNullValue()));
|
|
||||||
assertThat(error.getCondition(), equalTo(errorCondition));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in a new issue