Created
July 15, 2016 03:24
-
-
Save protoss1010/be03e3600f9cfe4bb628809849ddf2ce to your computer and use it in GitHub Desktop.
Parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* $RCSfile$ $Revision$ $Date$ | |
* <p/> | |
* Copyright 2003-2007 Jive Software. | |
* <p/> | |
* All rights reserved. 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 | |
* <p/> | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* <p/> | |
* 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.util; | |
import android.text.TextUtils; | |
import com.fetnet.libfetnet.Log; | |
import org.jivesoftware.smack.Connection; | |
import org.jivesoftware.smack.SmackConfiguration; | |
import org.jivesoftware.smack.packet.AckMessage; | |
import org.jivesoftware.smack.packet.Authentication; | |
import org.jivesoftware.smack.packet.Bind; | |
import org.jivesoftware.smack.packet.DefaultPacketExtension; | |
import org.jivesoftware.smack.packet.IQ; | |
import org.jivesoftware.smack.packet.Message; | |
import org.jivesoftware.smack.packet.Packet; | |
import org.jivesoftware.smack.packet.PacketExtension; | |
import org.jivesoftware.smack.packet.Presence; | |
import org.jivesoftware.smack.packet.Registration; | |
import org.jivesoftware.smack.packet.RosterPacket; | |
import org.jivesoftware.smack.packet.StreamError; | |
import org.jivesoftware.smack.packet.XMPPError; | |
import org.jivesoftware.smack.provider.IQProvider; | |
import org.jivesoftware.smack.provider.PacketExtensionProvider; | |
import org.jivesoftware.smack.provider.ProviderManager; | |
import org.jivesoftware.smack.sasl.SASLMechanism.Failure; | |
import org.jivesoftware.smackx.packet.GroupEvent; | |
import org.jivesoftware.smackx.packet.GroupMessage; | |
import org.jivesoftware.smackx.packet.GroupSet; | |
import org.jivesoftware.smackx.packet.MUCAdmin; | |
import org.json.JSONArray; | |
import org.json.JSONObject; | |
import org.xmlpull.v1.XmlPullParser; | |
import org.xmlpull.v1.XmlPullParserException; | |
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.TimeZone; | |
/** | |
* Utility class that helps to parse packets. Any parsing packets method that | |
* must be shared between many clients must be placed in this utility class. | |
* | |
* @author Gaston Dombiak | |
*/ | |
public class PacketParserUtils { | |
static final String TAG = "PacketParserUtils"; //AL-log-01+ | |
/** | |
* Namespace used to store packet properties. | |
*/ | |
private static final String PROPERTIES_NAMESPACE | |
= "http://www.jivesoftware.com/xmlns/xmpp/properties"; | |
//AL-v2-01+[ | |
public static long dateStringToLong(String dateString, String format) { | |
if (TextUtils.isEmpty(dateString)) return 0L; | |
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US); | |
Date date; | |
try { | |
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); | |
date = sdf.parse(dateString); | |
return date.getTime(); | |
} catch (ParseException e) { | |
e.printStackTrace(); | |
return 0L; | |
} | |
} | |
//AL-v2-01+] | |
/** | |
* Parses a message packet. | |
* | |
* @param parser the XML parser, positioned at the start of a message | |
* packet. | |
* @return a Message packet. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static Packet parseMessage(XmlPullParser parser) throws Exception { | |
Message message = new Message(); | |
String id = parser.getAttributeValue("", "id"); | |
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id); | |
message.setTo(parser.getAttributeValue("", "to")); | |
message.setFrom(parser.getAttributeValue("", "from")); | |
message.setType(Message.Type.fromString(parser.getAttributeValue("", "type"))); | |
Log.d(TAG, "id=%s, from=%s, to=%s, type=%s", id, | |
parser.getAttributeValue("", "from"), | |
parser.getAttributeValue("", "to"), | |
parser.getAttributeValue("", "type")); //AL-log-01+ | |
String language = getLanguageAttribute(parser); | |
// determine message's default language | |
String defaultLanguage = null; | |
if (language != null && !"".equals(language.trim())) { | |
message.setLanguage(language); | |
defaultLanguage = language; | |
} else { | |
defaultLanguage = Packet.getDefaultLanguage(); | |
} | |
// Parse sub-elements. We include extra logic to make sure the values | |
// are only read once. This is because it's possible for the names to appear | |
// in arbitrary sub-elements. | |
boolean done = false; | |
String thread = null; | |
Map<String, Object> properties = null; | |
JSONArray itemArray = new JSONArray(); | |
GroupEvent event = null; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
Log.d(TAG, "en=%s, ns=%s", elementName, namespace); //AL-log-01+ | |
// 2015/05/12 因為新功能的需要,所以xmpp多了新的格式:群組更新 與 成員進出通知 | |
if (elementName.equals("item")) { | |
String itemAction = parser.getAttributeValue("", "action"); | |
String itemFrom = parser.getAttributeValue("", "from"); | |
String itemTo = parser.getAttributeValue("", "to"); | |
JSONObject item = new JSONObject(); | |
item.put("action", itemAction); | |
item.put("from", itemFrom); | |
item.put("to", itemTo); | |
item.put("name", ""); | |
if (itemAction.equals("groupname")) { | |
String itemName = parser.getAttributeValue("", "name"); | |
item.put("name", itemName); | |
} | |
itemArray.put(item); | |
properties = new HashMap<String, Object>(); | |
properties.put("itemArray", itemArray.toString()); | |
properties.put("itemArrayLength", itemArray.length()); | |
} else if (elementName.equals("subject")) { | |
String xmlLang = getLanguageAttribute(parser); | |
if (xmlLang == null) { | |
xmlLang = defaultLanguage; | |
} | |
String subject = parseContent(parser); | |
if (message.getSubject(xmlLang) == null) { | |
message.addSubject(xmlLang, subject); | |
} | |
} else if (elementName.equals("body")) { | |
String xmlLang = getLanguageAttribute(parser); | |
if (xmlLang == null) { | |
xmlLang = defaultLanguage; | |
} | |
String body = parseContent(parser); | |
Log.d(TAG, "body='%s'", body); //AL-log-01+ | |
if (message.getBody(xmlLang) == null) { | |
message.addBody(xmlLang, body); | |
} | |
} | |
//AL-v2-03+[ | |
else if (elementName.equals("headers")) { | |
if (SmackConfiguration.EN_XMPP_V2) | |
parseBodyHeadersV2(message, parser); | |
} | |
//AL-v2-03+] | |
else if (elementName.equals("thread")) { | |
if (thread == null) { | |
thread = parser.nextText(); | |
} | |
} else if (elementName.equals("error")) { | |
message.setError(parseError(parser)); | |
} else if (elementName.equals("properties") | |
&& namespace.equals(PROPERTIES_NAMESPACE)) { | |
properties = parseProperties(parser); | |
} else if (elementName.equals("emmaDisplayed")) { | |
message.addEmmaDisplayed(parser.getAttributeValue(null, "jid"), parser.nextText()); | |
} else if (elementName.equals("fin")) { // Query history finish | |
message.setQueryHistoryFinish(parser.getAttributeValue(null, "queryid"), parser.getAttributeValue(null, "complete")); | |
} // Otherwise, it must be a packet extension. | |
else { | |
message.addExtension( | |
PacketParserUtils.parsePacketExtension(elementName, namespace, parser)); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("message")) { | |
done = true; | |
} | |
} | |
} | |
message.setThread(thread); | |
//message.setEvent(event); //AL-v2-02+ | |
// Set packet properties. | |
if (properties != null) { | |
for (String name : properties.keySet()) { | |
message.setProperty(name, properties.get(name)); | |
} | |
} | |
return message; | |
} | |
public static Packet parseAck(XmlPullParser parser) throws Exception { | |
AckMessage message = new AckMessage(); | |
String id = parser.getAttributeValue("", "id"); | |
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id); | |
message.setTo(parser.getAttributeValue("", "to")); | |
message.setFrom(parser.getAttributeValue("", "from")); | |
message.setTime(parser.getAttributeValue("", "time")); | |
Log.d(TAG, "id=%s, from=%s, to=%s, time=%s, h=%s", id, | |
parser.getAttributeValue("", "from"), | |
parser.getAttributeValue("", "to"), | |
parser.getAttributeValue("", "time"), | |
parser.getAttributeValue("", "h") | |
); //AL-log-01+ | |
// message.setType(Message.Type.fromString(parser.getAttributeValue("", "type"))); | |
// String language = getLanguageAttribute(parser); | |
// | |
// // determine message's default language | |
// String defaultLanguage = null; | |
// if (language != null && !"".equals(language.trim())) { | |
// message.setLanguage(language); | |
// defaultLanguage = language; | |
// } | |
// else { | |
// defaultLanguage = Packet.getDefaultLanguage(); | |
// } | |
// Parse sub-elements. We include extra logic to make sure the values | |
// are only read once. This is because it's possible for the names to appear | |
// in arbitrary sub-elements. | |
boolean done = false; | |
String thread = null; | |
Map<String, Object> properties = null; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
//Log.d(TAG, "e=%s, n=%s", elementName, namespace); //AL-log-01+ | |
//AL-v2-01+[ | |
if (SmackConfiguration.EN_XMPP_V2) { | |
if (elementName.equals("delay")) { | |
message.setFrom(parser.getAttributeValue("", "from")); | |
//String tm = ""+ dateStringToLong(parser.getAttributeValue("", "stamp"), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); | |
//message.setTime(tm); | |
message.setTime(parser.getAttributeValue("", "stamp")); | |
} | |
} | |
//AL-v2-01+] | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("a")) { | |
done = true; | |
} | |
} | |
} | |
// message.setThread(thread); | |
// Set packet properties. | |
if (properties != null) { | |
for (String name : properties.keySet()) { | |
message.setProperty(name, properties.get(name)); | |
} | |
} | |
return message; | |
} | |
public static Packet parseGroup(XmlPullParser parser) throws Exception { | |
Log.d(TAG, "+"); //AL-log-01+ | |
// TODO 改為僅回傳GroupSet,GroupMessage不使用 | |
GroupMessage message = new GroupMessage(); | |
String id = parser.getAttributeValue("", "id"); | |
String to = parser.getAttributeValue("", "to"); | |
String from = parser.getAttributeValue("", "from"); | |
String type = parser.getAttributeValue("", "type"); | |
String roomName = parser.getAttributeValue("", "name"); | |
String opts = parser.getAttributeValue("", "opts"); | |
// message.setTime(parser.getAttributeValue("", "time")); | |
// message.setType(Message.Type.fromString(parser.getAttributeValue("", "type"))); | |
// String language = getLanguageAttribute(parser); | |
// | |
// // determine message's default language | |
// String defaultLanguage = null; | |
// if (language != null && !"".equals(language.trim())) { | |
// message.setLanguage(language); | |
// defaultLanguage = language; | |
// } | |
// else { | |
// defaultLanguage = Packet.getDefaultLanguage(); | |
// } | |
// Parse sub-elements. We include extra logic to make sure the values | |
// are only read once. This is because it's possible for the names to appear | |
// in arbitrary sub-elements. | |
boolean done = false; | |
GroupMessage.Item item = null; | |
GroupSet.Succeed succeed = null; | |
GroupSet.Failed failed = null; | |
String thread = null; | |
Map<String, Object> properties = null; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
if (parser.getName().equals("item")) { | |
String jid = parser.getAttributeValue("", "jid"); | |
// Create packet. | |
item = new GroupMessage.Item(jid); | |
String name = parser.getAttributeValue("", "name"); | |
String optsInItem = parser.getAttributeValue("", "opts"); | |
String owner = parser.getAttributeValue("", "owner"); | |
if (!TextUtils.isEmpty(name)) { | |
item.setName(name); | |
} | |
if (!TextUtils.isEmpty(optsInItem)) { | |
item.setOptsInItem(optsInItem); | |
} else { | |
item.setOptsInItem("0"); | |
} | |
if (!TextUtils.isEmpty(owner)) { | |
item.setOwner(owner); | |
} else { | |
item.setOwner("0"); | |
} | |
} else if (elementName.equals("succeed")) { | |
succeed = parseGroupSucceed(parser); | |
} else if (elementName.equals("failed")) { | |
failed = parseGroupFailed(parser); | |
} else if (elementName.equals("error")) { | |
message.setError(parseError(parser)); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("item")) { | |
message.addItem(item); | |
} | |
if (parser.getName().equals("group")) { | |
done = true; | |
} | |
} | |
} | |
// message.setThread(thread); | |
// Set packet properties. | |
if (properties != null) { | |
for (String name : properties.keySet()) { | |
message.setProperty(name, properties.get(name)); | |
} | |
} | |
message = new GroupSet(message); | |
if (succeed != null || failed != null) { | |
if (succeed != null) { | |
((GroupSet) message).setSucceed(succeed); | |
} | |
if (failed != null) { | |
((GroupSet) message).setFailed(failed); | |
} | |
} | |
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id); | |
message.setTo(to); | |
message.setFrom(from); | |
message.setType(GroupMessage.Type.valueOf(type)); | |
message.setName(roomName); | |
message.setOpts(opts); | |
return message; | |
} | |
private static GroupSet.Succeed parseGroupSucceed(XmlPullParser parser) throws Exception { | |
boolean done = false; | |
GroupSet.Item item = null; | |
GroupSet.Succeed succeed = new GroupSet.Succeed(); | |
succeed.setJid(parser.getAttributeValue("", "jid")); | |
succeed.setName(parser.getAttributeValue("", "name")); | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
// String elementName = parser.getName(); | |
// String namespace = parser.getNamespace(); | |
item = new GroupMessage.Item(parser.getAttributeValue("", "jid")); | |
succeed.addItem(item); | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("succeed")) { | |
done = true; | |
} | |
} | |
} | |
return succeed; | |
} | |
private static GroupSet.Failed parseGroupFailed(XmlPullParser parser) throws Exception { | |
boolean done = false; | |
GroupSet.Item item = null; | |
GroupSet.Failed failed = new GroupSet.Failed(); | |
failed.setJid(parser.getAttributeValue("", "jid")); | |
failed.setName(parser.getAttributeValue("", "name")); | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
// String elementName = parser.getName(); | |
// String namespace = parser.getNamespace(); | |
item = new GroupMessage.Item(parser.getAttributeValue("", "jid")); | |
failed.addItem(item); | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("failed")) { | |
done = true; | |
} | |
} | |
} | |
return failed; | |
} | |
/** | |
* Returns the content of a tag as string regardless of any tags included. | |
* | |
* @param parser the XML pull parser | |
* @return the content of a tag as string | |
* @throws XmlPullParserException if parser encounters invalid XML | |
* @throws IOException if an IO error occurs | |
*/ | |
private static String parseContent(XmlPullParser parser) | |
throws XmlPullParserException, IOException { | |
int parserDepth = parser.getDepth(); | |
return parseContentDepth(parser, parserDepth); | |
} | |
public static String parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException { | |
StringBuffer content = new StringBuffer(); | |
while (!(parser.next() == XmlPullParser.END_TAG && parser.getDepth() == depth)) { | |
//Log.d(TAG, "depth=%d/%d, text=%s", depth, parser.getDepth(), parser.getText()); //AL-log-01+ | |
content.append(parser.getText()); | |
} | |
return content.toString(); | |
} | |
/** | |
* Parses a presence packet. | |
* | |
* @param parser the XML parser, positioned at the start of a presence | |
* packet. | |
* @return a Presence packet. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static Presence parsePresence(XmlPullParser parser) throws Exception { | |
Log.d(TAG, "+"); //AL-log-01+ | |
Presence.Type type = Presence.Type.available; | |
String typeString = parser.getAttributeValue("", "type"); | |
if (typeString != null && !typeString.equals("")) { | |
try { | |
type = Presence.Type.valueOf(typeString); | |
} catch (IllegalArgumentException iae) { | |
System.err.println("Found invalid presence type " + typeString); | |
} | |
} | |
Presence presence = new Presence(type); | |
presence.setTo(parser.getAttributeValue("", "to")); | |
presence.setFrom(parser.getAttributeValue("", "from")); | |
String id = parser.getAttributeValue("", "id"); | |
presence.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id); | |
String language = getLanguageAttribute(parser); | |
if (language != null && !"".equals(language.trim())) { | |
presence.setLanguage(language); | |
} | |
presence.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id); | |
// Parse sub-elements | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
if (elementName.equals("status")) { | |
presence.setStatus(parser.nextText()); | |
} else if (elementName.equals("priority")) { | |
try { | |
int priority = Integer.parseInt(parser.nextText()); | |
Log.d("Presence", "priority=%d", priority); //AL-v2-01+ | |
presence.setPriority(priority); | |
} catch (NumberFormatException nfe) { | |
// Ignore. | |
} catch (IllegalArgumentException iae) { | |
Log.e(TAG, "IllegalArgumentException"); //AL-v2-01+ | |
// Presence priority is out of range so assume priority to be zero | |
presence.setPriority(0); | |
} | |
} else if (elementName.equals("show")) { | |
String modeText = parser.nextText(); | |
try { | |
presence.setMode(Presence.Mode.valueOf(modeText)); | |
} catch (IllegalArgumentException iae) { | |
System.err.println("Found invalid presence mode " + modeText); | |
} | |
} else if (elementName.equals("error")) { | |
presence.setError(parseError(parser)); | |
} else if (elementName.equals("properties") | |
&& namespace.equals(PROPERTIES_NAMESPACE)) { | |
Map<String, Object> properties = parseProperties(parser); | |
// Set packet properties. | |
for (String name : properties.keySet()) { | |
presence.setProperty(name, properties.get(name)); | |
} | |
} // Otherwise, it must be a packet extension. | |
else { | |
try { | |
presence.addExtension(PacketParserUtils.parsePacketExtension(elementName, namespace, parser)); | |
} catch (Exception e) { | |
System.err.println("Failed to parse extension packet in Presence packet."); | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("presence")) { | |
done = true; | |
} | |
} | |
} | |
return presence; | |
} | |
/** | |
* Parses an IQ packet. | |
* | |
* @param parser the XML parser, positioned at the start of an IQ packet. | |
* @return an IQ object. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static IQ parseIQ(XmlPullParser parser, Connection connection) throws Exception { | |
IQ iqPacket = null; | |
String id = parser.getAttributeValue("", "id"); | |
String to = parser.getAttributeValue("", "to"); | |
String from = parser.getAttributeValue("", "from"); | |
IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type")); | |
Log.d(TAG, "id=%s, from=%s, to=%s, type=%s", id, from, to, type.toString()); //AL-log-01+ | |
XMPPError error = null; | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
//Log.d(TAG, "e=%s, n=%s", elementName, namespace); //AL-log-01+ | |
if (elementName.equals("error")) { | |
error = PacketParserUtils.parseError(parser); | |
} else if (elementName.equals("query") && namespace.equals("jabber:iq:auth")) { | |
iqPacket = parseAuthentication(parser); | |
} else if (elementName.equals("query") && namespace.equals("jabber:iq:roster")) { | |
iqPacket = parseRoster(parser); | |
} else if (elementName.equals("query") && namespace.equals("jabber:iq:register")) { | |
iqPacket = parseRegistration(parser); | |
} | |
//AL-v2-02+[ | |
else if (elementName.equals("query") && | |
(namespace.equals("http://jabber.org/protocol/muc#admin#emma") || namespace.equals("http://jabber.org/protocol/muc#user#emma"))) { | |
iqPacket = parseMember(parser); | |
} | |
//AL-v2-02+] | |
else if (elementName.equals("bind") | |
&& namespace.equals("urn:ietf:params:xml:ns:xmpp-bind")) { | |
iqPacket = parseResourceBinding(parser); | |
} // Otherwise, see if there is a registered provider for | |
// this element name and namespace. | |
else { | |
Object provider = ProviderManager.getInstance().getIQProvider(elementName, namespace); | |
if (provider != null) { | |
if (provider instanceof IQProvider) { | |
iqPacket = ((IQProvider) provider).parseIQ(parser); | |
} else if (provider instanceof Class) { | |
iqPacket = (IQ) PacketParserUtils.parseWithIntrospection(elementName, | |
(Class<?>) provider, parser); | |
} | |
} // Only handle unknown IQs of type result. Types of 'get' and 'set' which are not understood | |
// have to be answered with an IQ error response. See the code a few lines below | |
else if (IQ.Type.RESULT == type) { | |
// No Provider found for the IQ stanza, parse it to an UnparsedIQ instance | |
// so that the content of the IQ can be examined later on | |
iqPacket = new UnparsedResultIQ(parseContent(parser)); | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("iq")) { | |
done = true; | |
} | |
} | |
} | |
// Decide what to do when an IQ packet was not understood | |
if (iqPacket == null) { | |
if (IQ.Type.GET == type || IQ.Type.SET == type) { | |
// If the IQ stanza is of type "get" or "set" containing a child element | |
// qualified by a namespace it does not understand, then answer an IQ of | |
// type "error" with code 501 ("feature-not-implemented") | |
iqPacket = new IQ() { | |
@Override | |
public String getChildElementXML() { | |
return null; | |
} | |
}; | |
iqPacket.setPacketID(id); | |
iqPacket.setTo(from); | |
iqPacket.setFrom(to); | |
iqPacket.setType(IQ.Type.ERROR); | |
iqPacket.setError(new XMPPError(XMPPError.Condition.feature_not_implemented)); | |
connection.sendPacket(iqPacket); | |
return null; | |
} else { | |
// If an IQ packet wasn't created above, create an empty IQ packet. | |
iqPacket = new IQ() { | |
@Override | |
public String getChildElementXML() { | |
return null; | |
} | |
}; | |
} | |
} | |
// Set basic values on the iq packet. | |
iqPacket.setPacketID(id); | |
iqPacket.setTo(to); | |
iqPacket.setFrom(from); | |
iqPacket.setType(type); | |
iqPacket.setError(error); | |
return iqPacket; | |
} | |
//AL-v2-02+[ | |
private static MUCAdmin parseMember(XmlPullParser parser) throws Exception { | |
MUCAdmin admin = new MUCAdmin(); | |
MUCAdmin.Item item = null; | |
boolean done = false; | |
Log.d(TAG, "+"); | |
while (!done) { | |
if (parser.getEventType() == XmlPullParser.START_TAG | |
&& parser.getName().equals("query")) { | |
String version = parser.getAttributeValue(null, "ver"); | |
//roster.setVersion(version); | |
} | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (parser.getName().equals("item")) { | |
String jid = parser.getAttributeValue("", "jid"); | |
//String name = parser.getAttributeValue("", "name"); | |
String affiliation = parser.getAttributeValue("", "affiliation"); | |
// Create packet. | |
item = new MUCAdmin.Item(affiliation, null); | |
item.setJid(jid); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("item")) { | |
admin.addItem(item); | |
} | |
if (parser.getName().equals("query")) { | |
done = true; | |
} | |
} | |
} | |
return admin; | |
} | |
private static String parseBodyHeaders(Message message, XmlPullParser parser) throws Exception { | |
GroupEvent event = null; | |
GroupEvent.Item item = null; | |
StringBuffer content = new StringBuffer(); | |
boolean done = false; | |
Log.d(TAG, "in.text=%s", parser.getText()); | |
int eventType = parser.getEventType(); | |
while (!done) { | |
if (eventType == XmlPullParser.START_TAG) { | |
String element = parser.getName(); | |
String namespace = parser.getNamespace(); | |
Log.d(TAG, "en=%s, ns=%s, text=%s", element, namespace, parser.getText()); | |
if (element.equals("headers") && namespace.equals(GroupEvent.NAMESPACE)) { | |
event = new GroupEvent(); | |
} else if (element.equals("header")) { | |
if (event == null) { | |
Log.d(TAG, "no event!"); | |
return null; | |
} | |
String action = parser.getAttributeValue("", "action"); | |
String from = parser.getAttributeValue("", "from"); | |
String to = parser.getAttributeValue("", "to"); | |
String name = parser.getAttributeValue("", "name"); | |
Log.d(TAG, "item: action=%s, from=%s, to=%s, name=%s", action, from, to, name); | |
item = new GroupEvent.Item(action, from, to, name); | |
//item.setName(name); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("header")) { | |
Log.d(TAG, "+item"); | |
event.addItem(item); | |
} else if (parser.getName().equals("headers")) { | |
Log.d(TAG, "end"); | |
done = true; | |
} else { | |
Log.d(TAG, "text=%s", parser.getText()); | |
content.append(parser.getText()); | |
} | |
} else if (eventType == XmlPullParser.TEXT) { | |
Log.d(TAG, "text=%s", parser.getText()); | |
} else { | |
Log.d(TAG, "???, type=%s", eventType); | |
done = true; | |
} | |
eventType = parser.next(); | |
} | |
Log.d(TAG, "done.1"); | |
message.setEvent(event); | |
Log.d(TAG, "done.2"); | |
String xml = event != null ? event.toXML() : content.toString(); | |
Log.d(TAG, "done.3, xml=%s", xml); | |
return xml; | |
} | |
private static String parseBodyHeadersV2(Message message, XmlPullParser parser) throws Exception { | |
Log.d(TAG, "+"); | |
GroupEvent event = new GroupEvent(); | |
GroupEvent.Item item = null; | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String element = parser.getName(); | |
String namespace = parser.getNamespace(); | |
Log.d(TAG, "en=%s, ns=%s, text=%s", element, namespace, parser.getText()); | |
if (element.equals("header")) { | |
String action = parser.getAttributeValue("", "action"); | |
String from = parser.getAttributeValue("", "from"); | |
String to = parser.getAttributeValue("", "to"); | |
String name = parser.getAttributeValue("", "name"); | |
Log.d(TAG, "item: action=%s, from=%s, to=%s, name=%s", action, from, to, name); | |
item = new GroupEvent.Item(action, from, to, name); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("header")) { | |
Log.d(TAG, "+item"); | |
event.addItem(item); | |
} else if (parser.getName().equals("headers")) { | |
Log.d(TAG, "end"); | |
done = true; | |
} | |
} else { | |
Log.d(TAG, "???, type=%s", eventType); | |
done = true; | |
} | |
} // while() | |
message.setEvent(event); | |
String xml = event.toXML(); | |
Log.d(TAG, "done, item=%d, xml=%s", event.getItemCount(), xml); | |
return xml; | |
} | |
//AL-v2-02+] | |
private static Authentication parseAuthentication(XmlPullParser parser) throws Exception { | |
Authentication authentication = new Authentication(); | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (parser.getName().equals("username")) { | |
authentication.setUsername(parser.nextText()); | |
} else if (parser.getName().equals("password")) { | |
authentication.setPassword(parser.nextText()); | |
} else if (parser.getName().equals("digest")) { | |
authentication.setDigest(parser.nextText()); | |
} else if (parser.getName().equals("resource")) { | |
authentication.setResource(parser.nextText()); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("query")) { | |
done = true; | |
} | |
} | |
} | |
return authentication; | |
} | |
private static RosterPacket parseRoster(XmlPullParser parser) throws Exception { | |
RosterPacket roster = new RosterPacket(); | |
boolean done = false; | |
RosterPacket.Item item = null; | |
while (!done) { | |
if (parser.getEventType() == XmlPullParser.START_TAG | |
&& parser.getName().equals("query")) { | |
String version = parser.getAttributeValue(null, "ver"); | |
roster.setVersion(version); | |
} | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (parser.getName().equals("item")) { | |
String jid = parser.getAttributeValue("", "jid"); | |
String name = parser.getAttributeValue("", "name"); | |
// Create packet. | |
item = new RosterPacket.Item(jid, name); | |
// Set status. | |
String ask = parser.getAttributeValue("", "ask"); | |
RosterPacket.ItemStatus status = RosterPacket.ItemStatus.fromString(ask); | |
item.setItemStatus(status); | |
// Set type. | |
String subscription = parser.getAttributeValue("", "subscription"); | |
RosterPacket.ItemType type = RosterPacket.ItemType.valueOf(subscription != null ? subscription : "none"); | |
item.setItemType(type); | |
} | |
if (parser.getName().equals("group") && item != null) { | |
final String groupName = parser.nextText(); | |
if (groupName != null && groupName.trim().length() > 0) { | |
item.addGroupName(groupName); | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("item")) { | |
roster.addRosterItem(item); | |
} | |
if (parser.getName().equals("query")) { | |
done = true; | |
} | |
} | |
} | |
return roster; | |
} | |
private static Registration parseRegistration(XmlPullParser parser) throws Exception { | |
Registration registration = new Registration(); | |
Map<String, String> fields = null; | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
// Any element that's in the jabber:iq:register namespace, | |
// attempt to parse it if it's in the form <name>value</name>. | |
if (parser.getNamespace().equals("jabber:iq:register")) { | |
String name = parser.getName(); | |
String value = ""; | |
if (fields == null) { | |
fields = new HashMap<String, String>(); | |
} | |
if (parser.next() == XmlPullParser.TEXT) { | |
value = parser.getText(); | |
} | |
// Ignore instructions, but anything else should be added to the map. | |
if (!name.equals("instructions")) { | |
fields.put(name, value); | |
} else { | |
registration.setInstructions(value); | |
} | |
} // Otherwise, it must be a packet extension. | |
else { | |
registration.addExtension( | |
PacketParserUtils.parsePacketExtension( | |
parser.getName(), | |
parser.getNamespace(), | |
parser)); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("query")) { | |
done = true; | |
} | |
} | |
} | |
registration.setAttributes(fields); | |
return registration; | |
} | |
private static Bind parseResourceBinding(XmlPullParser parser) throws IOException, | |
XmlPullParserException { | |
Bind bind = new Bind(); | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (parser.getName().equals("resource")) { | |
bind.setResource(parser.nextText()); | |
} else if (parser.getName().equals("jid")) { | |
bind.setJid(parser.nextText()); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("bind")) { | |
done = true; | |
} | |
} | |
} | |
return bind; | |
} | |
/** | |
* Parse the available SASL mechanisms reported from the server. | |
* | |
* @param parser the XML parser, positioned at the start of the mechanisms | |
* stanza. | |
* @return a collection of Stings with the mechanisms included in the | |
* mechanisms stanza. | |
* @throws Exception if an exception occurs while parsing the stanza. | |
*/ | |
public static Collection<String> parseMechanisms(XmlPullParser parser) throws Exception { | |
List<String> mechanisms = new ArrayList<String>(); | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
if (elementName.equals("mechanism")) { | |
mechanisms.add(parser.nextText()); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("mechanisms")) { | |
done = true; | |
} | |
} | |
} | |
return mechanisms; | |
} | |
/** | |
* Parse the available compression methods reported from the server. | |
* | |
* @param parser the XML parser, positioned at the start of the compression | |
* stanza. | |
* @return a collection of Stings with the methods included in the | |
* compression stanza. | |
* @throws Exception if an exception occurs while parsing the stanza. | |
*/ | |
public static Collection<String> parseCompressionMethods(XmlPullParser parser) | |
throws IOException, XmlPullParserException { | |
List<String> methods = new ArrayList<String>(); | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
if (elementName.equals("method")) { | |
methods.add(parser.nextText()); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("compression")) { | |
done = true; | |
} | |
} | |
} | |
return methods; | |
} | |
/** | |
* Parse a properties sub-packet. If any errors occur while de-serializing | |
* Java object properties, an exception will be printed and not thrown since | |
* a thrown exception will shut down the entire connection. | |
* ClassCastExceptions will occur when both the sender and receiver of the | |
* packet don't have identical versions of the same class. | |
* | |
* @param parser the XML parser, positioned at the start of a properties | |
* sub-packet. | |
* @return a map of the properties. | |
* @throws Exception if an error occurs while parsing the properties. | |
*/ | |
public static Map<String, Object> parseProperties(XmlPullParser parser) throws Exception { | |
Map<String, Object> properties = new HashMap<String, Object>(); | |
while (true) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("property")) { | |
// Parse a property | |
boolean done = false; | |
String name = null; | |
String type = null; | |
String valueText = null; | |
Object value = null; | |
while (!done) { | |
eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String elementName = parser.getName(); | |
if (elementName.equals("name")) { | |
name = parser.nextText(); | |
} else if (elementName.equals("value")) { | |
type = parser.getAttributeValue("", "type"); | |
valueText = parser.nextText(); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("property")) { | |
if ("integer".equals(type)) { | |
value = Integer.valueOf(valueText); | |
} else if ("long".equals(type)) { | |
value = Long.valueOf(valueText); | |
} else if ("float".equals(type)) { | |
value = Float.valueOf(valueText); | |
} else if ("double".equals(type)) { | |
value = Double.valueOf(valueText); | |
} else if ("boolean".equals(type)) { | |
value = Boolean.valueOf(valueText); | |
} else if ("string".equals(type)) { | |
value = valueText; | |
} else if ("java-object".equals(type)) { | |
try { | |
byte[] bytes = StringUtils.decodeBase64(valueText); | |
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes)); | |
value = in.readObject(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
if (name != null && value != null) { | |
properties.put(name, value); | |
} | |
done = true; | |
} | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("properties")) { | |
break; | |
} | |
} | |
} | |
return properties; | |
} | |
/** | |
* Parses SASL authentication error packets. | |
* | |
* @param parser the XML parser. | |
* @return a SASL Failure packet. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static Failure parseSASLFailure(XmlPullParser parser) throws Exception { | |
String condition = null; | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (!parser.getName().equals("failure")) { | |
condition = parser.getName(); | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("failure")) { | |
done = true; | |
} | |
} | |
} | |
return new Failure(condition); | |
} | |
/** | |
* Parses stream error packets. | |
* | |
* @param parser the XML parser. | |
* @return an stream error packet. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static StreamError parseStreamError(XmlPullParser parser) throws IOException, | |
XmlPullParserException { | |
final int depth = parser.getDepth(); | |
boolean done = false; | |
String code = null; | |
String text = null; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String namespace = parser.getNamespace(); | |
if (StreamError.NAMESPACE.equals(namespace)) { | |
String name = parser.getName(); | |
if (name.equals("text") && !parser.isEmptyElementTag()) { | |
parser.next(); | |
text = parser.getText(); | |
} else { | |
// If it's not a text element, that is qualified by the StreamError.NAMESPACE, | |
// then it has to be the stream error code | |
code = name; | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG && depth == parser.getDepth()) { | |
done = true; | |
} | |
} | |
return new StreamError(code, text); | |
} | |
/** | |
* Parses error sub-packets. | |
* | |
* @param parser the XML parser. | |
* @return an error sub-packet. | |
* @throws Exception if an exception occurs while parsing the packet. | |
*/ | |
public static XMPPError parseError(XmlPullParser parser) throws Exception { | |
final String errorNamespace = "urn:ietf:params:xml:ns:xmpp-stanzas"; | |
String errorCode = "-1"; | |
String type = null; | |
String message = null; | |
String condition = null; | |
List<PacketExtension> extensions = new ArrayList<PacketExtension>(); | |
// Parse the error header | |
for (int i = 0; i < parser.getAttributeCount(); i++) { | |
if (parser.getAttributeName(i).equals("code")) { | |
errorCode = parser.getAttributeValue("", "code"); | |
} | |
if (parser.getAttributeName(i).equals("type")) { | |
type = parser.getAttributeValue("", "type"); | |
} | |
} | |
boolean done = false; | |
// Parse the text and condition tags | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
if (parser.getName().equals("text")) { | |
message = parser.nextText(); | |
} else { | |
// Condition tag, it can be xmpp error or an application defined error. | |
String elementName = parser.getName(); | |
String namespace = parser.getNamespace(); | |
if (errorNamespace.equals(namespace)) { | |
condition = elementName; | |
} else { | |
extensions.add(parsePacketExtension(elementName, namespace, parser)); | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals("error")) { | |
done = true; | |
} | |
} | |
} | |
// Parse the error type. | |
XMPPError.Type errorType = XMPPError.Type.CANCEL; | |
try { | |
if (type != null) { | |
errorType = XMPPError.Type.valueOf(type.toUpperCase()); | |
} | |
} catch (IllegalArgumentException iae) { | |
// Print stack trace. We shouldn't be getting an illegal error type. | |
iae.printStackTrace(); | |
} | |
return new XMPPError(Integer.parseInt(errorCode), errorType, condition, message, extensions); | |
} | |
/** | |
* Parses a packet extension sub-packet. | |
* | |
* @param elementName the XML element name of the packet extension. | |
* @param namespace the XML namespace of the packet extension. | |
* @param parser the XML parser, positioned at the starting element of the | |
* extension. | |
* @return a PacketExtension. | |
* @throws Exception if a parsing error occurs. | |
*/ | |
public static PacketExtension parsePacketExtension(String elementName, String namespace, XmlPullParser parser) | |
throws Exception { | |
// See if a provider is registered to handle the extension. | |
Object provider = ProviderManager.getInstance().getExtensionProvider(elementName, namespace); | |
Log.d(TAG, "elem=%s, ns=%s, provider=%s", elementName, namespace, (provider != null ? provider.toString() : "null")); //AL-v2-01+ | |
if (provider != null) { | |
if (provider instanceof PacketExtensionProvider) { | |
Log.d(TAG, "PacketExtensionProvider"); //AL-v2-01+ | |
return ((PacketExtensionProvider) provider).parseExtension(parser); | |
} else if (provider instanceof Class) { | |
Log.d(TAG, "parseWithIntrospection"); //AL-v2-01+ | |
return (PacketExtension) parseWithIntrospection( | |
elementName, (Class<?>) provider, parser); | |
} | |
} | |
// No providers registered, so use a default extension. | |
DefaultPacketExtension extension = new DefaultPacketExtension(elementName, namespace); | |
Log.d(TAG, "elem=%s, ns=%s, extension=%s", elementName, namespace, (extension != null ? extension.toString() : "null")); //AL-v2-01+ | |
boolean done = false; | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String name = parser.getName(); | |
// If an empty element, set the value with the empty string. | |
if (parser.isEmptyElementTag()) { | |
extension.setValue(name, ""); | |
} // Otherwise, get the the element text. | |
else { | |
eventType = parser.next(); | |
if (eventType == XmlPullParser.TEXT) { | |
String value = parser.getText(); | |
extension.setValue(name, value); | |
} | |
} | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals(elementName)) { | |
done = true; | |
} | |
} | |
} | |
return extension; | |
} | |
private static String getLanguageAttribute(XmlPullParser parser) { | |
for (int i = 0; i < parser.getAttributeCount(); i++) { | |
String attributeName = parser.getAttributeName(i); | |
if ("xml:lang".equals(attributeName) | |
|| ("lang".equals(attributeName) | |
&& "xml".equals(parser.getAttributePrefix(i)))) { | |
return parser.getAttributeValue(i); | |
} | |
} | |
return null; | |
} | |
public static Object parseWithIntrospection(String elementName, | |
Class<?> objectClass, XmlPullParser parser) throws Exception { | |
boolean done = false; | |
Log.d(TAG, "elem=%s", elementName); //AL-v2-01+ | |
Object object = objectClass.newInstance(); | |
while (!done) { | |
int eventType = parser.next(); | |
if (eventType == XmlPullParser.START_TAG) { | |
String name = parser.getName(); | |
String stringValue = parser.nextText(); | |
//Log.d(TAG, "name=%s, value=%s", name, stringValue); //AL-v2-01+ | |
Class propertyType = object.getClass().getMethod( | |
"get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)).getReturnType(); | |
// Get the value of the property by converting it from a | |
// String to the correct object type. | |
Object value = decode(propertyType, stringValue); | |
// Set the value of the bean. | |
object.getClass().getMethod("set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), propertyType) | |
.invoke(object, value); | |
} else if (eventType == XmlPullParser.END_TAG) { | |
if (parser.getName().equals(elementName)) { | |
done = true; | |
} | |
} | |
} | |
return object; | |
} | |
/** | |
* Decodes a String into an object of the specified type. If the object type | |
* is not supported, null will be returned. | |
* | |
* @param type the type of the property. | |
* @param value the encode String value to decode. | |
* @return the String value decoded into the specified type. | |
* @throws Exception If decoding failed due to an error. | |
*/ | |
private static Object decode(Class<?> type, String value) throws Exception { | |
if (type.getName().equals("java.lang.String")) { | |
return value; | |
} | |
if (type.getName().equals("boolean")) { | |
return Boolean.valueOf(value); | |
} | |
if (type.getName().equals("int")) { | |
return Integer.valueOf(value); | |
} | |
if (type.getName().equals("long")) { | |
return Long.valueOf(value); | |
} | |
if (type.getName().equals("float")) { | |
return Float.valueOf(value); | |
} | |
if (type.getName().equals("double")) { | |
return Double.valueOf(value); | |
} | |
if (type.getName().equals("java.lang.Class")) { | |
return Class.forName(value); | |
} | |
return null; | |
} | |
/** | |
* This class represents and unparsed IQ of the type 'result'. Usually it's | |
* created when no IQProvider was found for the IQ element. | |
* <p/> | |
* The child elements can be examined with the getChildElementXML() method. | |
*/ | |
public static class UnparsedResultIQ extends IQ { | |
public UnparsedResultIQ(String content) { | |
this.str = content; | |
} | |
private final String str; | |
@Override | |
public String getChildElementXML() { | |
return this.str; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment