/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.vysper.xmpp.server.response; import org.apache.vysper.xml.fragment.XMLElement; import org.apache.vysper.xmpp.modules.core.sasl.SASLFailureType; import org.apache.vysper.xmpp.protocol.NamespaceURIs; import org.apache.vysper.xmpp.protocol.StreamErrorCondition; import org.apache.vysper.xmpp.stanza.Stanza; import org.apache.vysper.xmpp.stanza.StanzaBuilder; import org.apache.vysper.xmpp.stanza.StanzaErrorCondition; import org.apache.vysper.xmpp.stanza.StanzaErrorType; import org.apache.vysper.xmpp.stanza.XMPPCoreStanza; /** * * @author The Apache MINA Project (dev@mina.apache.org) */ public class ServerErrorResponses { private ServerErrorResponses() { // empty } public static Stanza getStreamError(StreamErrorCondition definedErrorCondition, String languageCode, String descriptiveText, XMLElement applicationSpecificError) { /* <stream:jabber> <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:jabber> */ if (languageCode == null) languageCode = "en_US"; StanzaBuilder stanzaBuilder = new StanzaBuilder("error", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_STREAMS); stanzaBuilder.startInnerElement(definedErrorCondition.value(), NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_STREAMS).endInnerElement(); if (descriptiveText != null) { stanzaBuilder.startInnerElement("text", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_STREAMS).addAttribute( NamespaceURIs.XML, "lang", languageCode).addText(descriptiveText).endInnerElement(); } if (applicationSpecificError != null) { stanzaBuilder.addPreparedElement(applicationSpecificError); } return stanzaBuilder.build(); } /** * TODO move to a more general error handling * @param errorCondition - corresponds to one of the defined stanza error conditions * @param stanza - the stanza to which the error stanza is the answer * @param type * @param errorText - is optional together with errorLang, both together might be NULL * @param errorLang - must be present, if errorText is not NULL * @param errorConditionElement - optional application specific error condition element * @return error response stanza */ public static Stanza getStanzaError(StanzaErrorCondition errorCondition, XMPPCoreStanza stanza, StanzaErrorType type, String errorText, String errorLang, XMLElement errorConditionElement) { if (stanza != null && "error".equals(stanza.getType())) { return ServerErrorResponses.getStreamError(StreamErrorCondition.UNSUPPORTED_STANZA_TYPE, errorLang, "cannot respond to IQ stanza of type error with the same", null); } StanzaBuilder responseBuilder = StanzaBuilder.createDirectReply(stanza, true, "error"); fillErrorStanza(stanza, type, errorCondition, -1, errorText, errorLang, errorConditionElement, responseBuilder); return responseBuilder.build(); } public static Stanza getStanzaError(StanzaErrorCondition errorCondition, XMPPCoreStanza stanza, StanzaErrorType type, int code, String errorText, String errorLang, XMLElement errorConditionElement) { if (stanza != null && "error".equals(stanza.getType())) { return ServerErrorResponses.getStreamError(StreamErrorCondition.UNSUPPORTED_STANZA_TYPE, errorLang, "cannot respond to IQ stanza of type error with the same", null); } StanzaBuilder responseBuilder = StanzaBuilder.createDirectReply(stanza, true, "error"); fillErrorStanza(stanza, type, errorCondition, code, errorText, errorLang, errorConditionElement, responseBuilder); return responseBuilder.build(); } private static void fillErrorStanza(XMPPCoreStanza stanza, StanzaErrorType type, StanzaErrorCondition errorCondition, int code, String errorText, String errorLang, XMLElement errorConditionElement, StanzaBuilder responseBuilder) { // inline incoming stanza as of RFC 3920 9.3.1 for (XMLElement innerElement : stanza.getInnerElements()) { responseBuilder.addPreparedElement(innerElement); } // error element responseBuilder.startInnerElement("error", NamespaceURIs.JABBER_CLIENT).addAttribute("type", type.value()); if(code != -1) responseBuilder.addAttribute("code", Integer.toString(code)); // insert defined error condition relating to the stanza error type responseBuilder.startInnerElement(errorCondition.value(), NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_STANZAS); responseBuilder.endInnerElement(); // optional error text if (errorText != null && errorLang != null) { responseBuilder.startInnerElement("text", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_STANZAS).addAttribute( NamespaceURIs.XML, "lang", errorLang).addText(errorText); } // optional application specific error condition element if (errorConditionElement != null) responseBuilder.addPreparedElement(errorConditionElement); responseBuilder.endInnerElement(); } public static Stanza getTLSFailure() { StanzaBuilder stanzaBuilder = new StanzaBuilder("failure", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS); return stanzaBuilder.build(); } public static Stanza getSASLFailure(SASLFailureType failureType) { StanzaBuilder stanzaBuilder = new StanzaBuilder("failure", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL); if (failureType != null) { stanzaBuilder.startInnerElement(failureType.toString(), NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_SASL) .endInnerElement(); } return stanzaBuilder.build(); } }