001/** 002 * 003 * Copyright 2017-2022 Florian Schmaus 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.jingle.provider; 018 019import java.io.IOException; 020import java.util.logging.Logger; 021 022import org.jivesoftware.smack.packet.IqData; 023import org.jivesoftware.smack.packet.StandardExtensionElement; 024import org.jivesoftware.smack.packet.XmlElement; 025import org.jivesoftware.smack.packet.XmlEnvironment; 026import org.jivesoftware.smack.parsing.SmackParsingException; 027import org.jivesoftware.smack.parsing.StandardExtensionElementProvider; 028import org.jivesoftware.smack.provider.IqProvider; 029import org.jivesoftware.smack.util.PacketParserUtils; 030import org.jivesoftware.smack.util.ParserUtils; 031import org.jivesoftware.smack.xml.XmlPullParser; 032import org.jivesoftware.smack.xml.XmlPullParserException; 033 034import org.jivesoftware.smackx.jingle.element.Jingle; 035import org.jivesoftware.smackx.jingle.element.JingleAction; 036import org.jivesoftware.smackx.jingle.element.JingleContent; 037import org.jivesoftware.smackx.jingle.element.JingleContentDescription; 038import org.jivesoftware.smackx.jingle.element.JingleContentTransport; 039import org.jivesoftware.smackx.jingle.element.JingleReason; 040import org.jivesoftware.smackx.jingle.element.JingleReason.Reason; 041import org.jivesoftware.smackx.jingle.element.UnknownJingleContentDescription; 042import org.jivesoftware.smackx.jingle.element.UnknownJingleContentTransport; 043 044import org.jxmpp.jid.FullJid; 045 046public class JingleProvider extends IqProvider<Jingle> { 047 048 private static final Logger LOGGER = Logger.getLogger(JingleProvider.class.getName()); 049 050 @Override 051 public Jingle parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment) throws XmlPullParserException, IOException, SmackParsingException { 052 Jingle.Builder builder = Jingle.builder(iqData); 053 054 String actionString = parser.getAttributeValue("", Jingle.ACTION_ATTRIBUTE_NAME); 055 if (actionString != null) { 056 JingleAction action = JingleAction.fromString(actionString); 057 builder.setAction(action); 058 } 059 060 FullJid initiator = ParserUtils.getFullJidAttribute(parser, Jingle.INITIATOR_ATTRIBUTE_NAME); 061 builder.setInitiator(initiator); 062 063 FullJid responder = ParserUtils.getFullJidAttribute(parser, Jingle.RESPONDER_ATTRIBUTE_NAME); 064 builder.setResponder(responder); 065 066 String sessionId = parser.getAttributeValue("", Jingle.SESSION_ID_ATTRIBUTE_NAME); 067 builder.setSessionId(sessionId); 068 069 070 outerloop: while (true) { 071 XmlPullParser.Event eventType = parser.next(); 072 switch (eventType) { 073 case START_ELEMENT: 074 String tagName = parser.getName(); 075 switch (tagName) { 076 case JingleContent.ELEMENT: 077 JingleContent content = parseJingleContent(parser, parser.getDepth()); 078 builder.addJingleContent(content); 079 break; 080 case JingleReason.ELEMENT: 081 JingleReason reason = parseJingleReason(parser); 082 builder.setReason(reason); 083 break; 084 default: 085 LOGGER.severe("Unknown Jingle element: " + tagName); 086 break; 087 } 088 break; 089 case END_ELEMENT: 090 if (parser.getDepth() == initialDepth) { 091 break outerloop; 092 } 093 break; 094 default: 095 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 096 break; 097 } 098 } 099 100 return builder.build(); 101 } 102 103 public static JingleContent parseJingleContent(XmlPullParser parser, final int initialDepth) 104 throws XmlPullParserException, IOException, SmackParsingException { 105 JingleContent.Builder builder = JingleContent.getBuilder(); 106 107 String creatorString = parser.getAttributeValue("", JingleContent.CREATOR_ATTRIBUTE_NAME); 108 JingleContent.Creator creator = JingleContent.Creator.valueOf(creatorString); 109 builder.setCreator(creator); 110 111 String disposition = parser.getAttributeValue("", JingleContent.DISPOSITION_ATTRIBUTE_NAME); 112 builder.setDisposition(disposition); 113 114 String name = parser.getAttributeValue("", JingleContent.NAME_ATTRIBUTE_NAME); 115 builder.setName(name); 116 117 String sendersString = parser.getAttributeValue("", JingleContent.SENDERS_ATTRIBUTE_NAME); 118 if (sendersString != null) { 119 JingleContent.Senders senders = JingleContent.Senders.valueOf(sendersString); 120 builder.setSenders(senders); 121 } 122 123 outerloop: while (true) { 124 XmlPullParser.Event eventType = parser.next(); 125 switch (eventType) { 126 case START_ELEMENT: 127 String tagName = parser.getName(); 128 String namespace = parser.getNamespace(); 129 switch (tagName) { 130 case JingleContentDescription.ELEMENT: { 131 JingleContentDescription description; 132 JingleContentDescriptionProvider<?> provider = JingleContentProviderManager.getJingleContentDescriptionProvider(namespace); 133 if (provider == null) { 134 StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); 135 description = new UnknownJingleContentDescription(standardExtensionElement); 136 } 137 else { 138 description = provider.parse(parser); 139 } 140 builder.setDescription(description); 141 break; 142 } 143 case JingleContentTransport.ELEMENT: { 144 JingleContentTransport transport; 145 JingleContentTransportProvider<?> provider = JingleContentProviderManager.getJingleContentTransportProvider(namespace); 146 if (provider == null) { 147 StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); 148 transport = new UnknownJingleContentTransport(standardExtensionElement); 149 } 150 else { 151 transport = provider.parse(parser); 152 } 153 builder.setTransport(transport); 154 break; 155 } 156 default: 157 LOGGER.severe("Unknown Jingle content element: " + tagName); 158 break; 159 } 160 break; 161 case END_ELEMENT: 162 if (parser.getDepth() == initialDepth) { 163 break outerloop; 164 } 165 break; 166 default: 167 // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement. 168 break; 169 } 170 } 171 172 return builder.build(); 173 } 174 175 public static JingleReason parseJingleReason(XmlPullParser parser) 176 throws XmlPullParserException, IOException, SmackParsingException { 177 ParserUtils.assertAtStartTag(parser); 178 final int initialDepth = parser.getDepth(); 179 final String jingleNamespace = parser.getNamespace(); 180 181 JingleReason.Reason reason = null; 182 XmlElement element = null; 183 String text = null; 184 185 // 'sid' is only set if the reason is 'alternative-session'. 186 String sid = null; 187 188 outerloop: while (true) { 189 XmlPullParser.TagEvent event = parser.nextTag(); 190 switch (event) { 191 case START_ELEMENT: 192 String elementName = parser.getName(); 193 String namespace = parser.getNamespace(); 194 if (namespace.equals(jingleNamespace)) { 195 switch (elementName) { 196 case "text": 197 text = parser.nextText(); 198 break; 199 case "alternative-session": 200 parser.next(); 201 sid = parser.nextText(); 202 break; 203 default: 204 reason = Reason.fromString(elementName); 205 break; 206 } 207 } else { 208 element = PacketParserUtils.parseExtensionElement(elementName, namespace, parser, null); 209 } 210 break; 211 case END_ELEMENT: 212 if (parser.getDepth() == initialDepth) { 213 break outerloop; 214 } 215 break; 216 } 217 } 218 219 JingleReason res; 220 if (sid != null) { 221 res = new JingleReason.AlternativeSession(sid, text, element); 222 } else { 223 res = new JingleReason(reason, text, element); 224 } 225 return res; 226 } 227}