src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java
public class PacketParserUtils {

    public static String parseContentDepth(XmlPullParser parser, int depth)
            throws XmlPullParserException, IOException {
        StringBuffer content = new StringBuffer();
        while (!(parser.next() == XmlPullParser.END_TAG && parser.getDepth() == depth)) {
            content.append(parser.getText());
        }
        return content.toString();
    }

    /**
     * Parses stream error packets.
     * 
     * @param doc
     *            the XML parser.
     * @return an stream error packet.
     * @throws Exception
     *             if an exception occurs while parsing the packet.
     */
    public static StreamError parseStreamError(Element el) throws IOException,
            XmlPullParserException {
        String code = null;
        Element condEl = (Element) el.elements().iterator().next();
        if (condEl.getNamespace().getURI().equals(StreamError.NAMESPACE)) {
            code = condEl.getName();
        }
        String text = condEl.elementText("text");
        return new StreamError(code, text);
    }

    /**
     * Parse the available SASL mechanisms reported from the server.
     * 
     * @param mechanismsEl
     *            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.
     */
    @SuppressWarnings("unchecked")
    public static Collection<String> parseMechanisms(Element mechanismsEl)
            throws Exception {
        List<Element> mechanisms = mechanismsEl.elements("mechanism");
        List<String> mechanismsStr = new LinkedList<String>();
        for (Element mechanismEl : mechanisms) {
            mechanismsStr.add(mechanismEl.getText());
        }
        return mechanismsStr;
    }

    /**
     * Parse the available compression methods reported from the server.
     * 
     * @param compressionEl
     *            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.
     */
    @SuppressWarnings("unchecked")
    public static Collection<String> parseCompressionMethods(
            Element compressionEl) throws IOException, XmlPullParserException {
        List<Element> methodsEls = compressionEl.elements("method");
        List<String> methodsStr = new LinkedList<String>();
        for (Element methodEl : methodsEls) {
            methodsStr.add(methodEl.getText());
        }
        return methodsStr;
    }

    /**
     * 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 {
        DefaultPacketExtension extension = new DefaultPacketExtension(
                elementName, namespace);
        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;
    }

    public static Object parseWithIntrospection(String elementName,
            Class<?> objectClass, XmlPullParser parser) throws Exception {
        boolean done = false;
        Object object = objectClass.newInstance();
        while (!done) {
            int eventType = parser.next();
            if (eventType == XmlPullParser.START_TAG) {
                String name = parser.getName();
                String stringValue = parser.nextText();
                PropertyDescriptor descriptor = new PropertyDescriptor(name,
                        objectClass);
                // Load the class type of the property.
                Class<?> propertyType = descriptor.getPropertyType();
                // 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.
                descriptor.getWriteMethod().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;
    }

    public static void updateText(Element parentEl, String elName, String text) {
        Element el = parentEl.element(elName);
        if (el == null) {
            el = parentEl.addElement(elName);
        }
        el.setText(text);
    }

}
src/main/java/org/dom4j/io/XPPPacketReader.java
public class XPPPacketReader {

    /**
     * <code>DocumentFactory</code> used to create new document objects
     */
    private DocumentFactory factory;

    /**
     * <code>XmlPullParser</code> used to parse XML
     */
    private XmlPullParser xppParser;

    /**
     * <code>XmlPullParser</code> used to parse XML
     */
    private XmlPullParserFactory xppFactory;

    /**
     * DispatchHandler to call when each <code>Element</code> is encountered
     */
    private DispatchHandler dispatchHandler;

    public XPPPacketReader() {
    }

    public XPPPacketReader(DocumentFactory factory) {
        this.factory = factory;
    }

    /**
     * <p>
     * Reads a Document from the given <code>File</code>
     * </p>
     * 
     * @param file
     *            is the <code>File</code> to read from.
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     * @throws java.net.MalformedURLException
     *             if a URL could not be made for the given File
     */
    public Document read(File file) throws DocumentException, IOException,
            XmlPullParserException {
        String systemID = file.getAbsolutePath();
        return read(new BufferedReader(new FileReader(file)), systemID);
    }

    /**
     * <p>
     * Reads a Document from the given <code>URL</code>
     * </p>
     * 
     * @param url
     *            <code>URL</code> to read from.
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(URL url) throws DocumentException, IOException,
            XmlPullParserException {
        String systemID = url.toExternalForm();
        return read(createReader(url.openStream()), systemID);
    }

    /**
     * <p>
     * Reads a Document from the given URL or filename.
     * </p>
     * <p/>
     * <p/>
     * If the systemID contains a <code>':'</code> character then it is assumed
     * to be a URL otherwise its assumed to be a file name. If you want finer
     * grained control over this mechansim then please explicitly pass in either
     * a {@link URL} or a {@link File} instance instead of a {@link String} to
     * denote the source of the document.
     * </p>
     * 
     * @param systemID
     *            is a URL for a document or a file name.
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     * @throws java.net.MalformedURLException
     *             if a URL could not be made for the given File
     */
    public Document read(String systemID) throws DocumentException,
            IOException, XmlPullParserException {
        if (systemID.indexOf(':') >= 0) {
            // lets assume its a URL
            return read(new URL(systemID));
        } else {
            // lets assume that we are given a file name
            return read(new File(systemID));
        }
    }

    /**
     * <p>
     * Reads a Document from the given stream
     * </p>
     * 
     * @param in
     *            <code>InputStream</code> to read from.
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(InputStream in) throws DocumentException, IOException,
            XmlPullParserException {
        return read(createReader(in));
    }

    /**
     * <p>
     * Reads a Document from the given <code>Reader</code>
     * </p>
     * 
     * @param reader
     *            is the reader for the input
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(Reader reader) throws DocumentException, IOException,
            XmlPullParserException {
        getXPPParser().setInput(reader);
        return parseDocument();
    }

    /**
     * <p>
     * Reads a Document from the given array of characters
     * </p>
     * 
     * @param text
     *            is the text to parse
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(char[] text) throws DocumentException, IOException,
            XmlPullParserException {
        getXPPParser().setInput(new CharArrayReader(text));
        return parseDocument();
    }

    /**
     * <p>
     * Reads a Document from the given stream
     * </p>
     * 
     * @param in
     *            <code>InputStream</code> to read from.
     * @param systemID
     *            is the URI for the input
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(InputStream in, String systemID)
            throws DocumentException, IOException, XmlPullParserException {
        return read(createReader(in), systemID);
    }

    /**
     * <p>
     * Reads a Document from the given <code>Reader</code>
     * </p>
     * 
     * @param reader
     *            is the reader for the input
     * @param systemID
     *            is the URI for the input
     * @return the newly created Document instance
     * @throws DocumentException
     *             if an error occurs during parsing.
     */
    public Document read(Reader reader, String systemID)
            throws DocumentException, IOException, XmlPullParserException {
        Document document = read(reader);
        document.setName(systemID);
        return document;
    }

    // Properties
    // -------------------------------------------------------------------------

    public XmlPullParser getXPPParser() throws XmlPullParserException {
        if (xppParser == null) {
            xppParser = getXPPFactory().newPullParser();
        }
        return xppParser;
    }

    public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
        if (xppFactory == null) {
            xppFactory = XmlPullParserFactory.newInstance();
        }
        xppFactory.setNamespaceAware(true);
        return xppFactory;
    }

    public void setXPPFactory(XmlPullParserFactory xppFactory) {
        this.xppFactory = xppFactory;
    }

    /**
     * @return the <code>DocumentFactory</code> used to create document objects
     */
    public DocumentFactory getDocumentFactory() {
        if (factory == null) {
            factory = DocumentFactory.getInstance();
        }
        return factory;
    }

    /**
     * <p>
     * This sets the <code>DocumentFactory</code> used to create new documents.
     * This method allows the building of custom DOM4J tree objects to be
     * implemented easily using a custom derivation of {@link DocumentFactory}
     * </p>
     * 
     * @param factory
     *            <code>DocumentFactory</code> used to create DOM4J objects
     */
    public void setDocumentFactory(DocumentFactory factory) {
        this.factory = factory;
    }

    /**
     * Adds the <code>ElementHandler</code> to be called when the specified path
     * is encounted.
     * 
     * @param path
     *            is the path to be handled
     * @param handler
     *            is the <code>ElementHandler</code> to be called by the event
     *            based processor.
     */
    public void addHandler(String path, ElementHandler handler) {
        getDispatchHandler().addHandler(path, handler);
    }

    /**
     * Removes the <code>ElementHandler</code> from the event based processor,
     * for the specified path.
     * 
     * @param path
     *            is the path to remove the <code>ElementHandler</code> for.
     */
    public void removeHandler(String path) {
        getDispatchHandler().removeHandler(path);
    }

    /**
     * When multiple <code>ElementHandler</code> instances have been registered,
     * this will set a default <code>ElementHandler</code> to be called for any
     * path which does <b>NOT</b> have a handler registered.
     * 
     * @param handler
     *            is the <code>ElementHandler</code> to be called by the event
     *            based processor.
     */
    public void setDefaultHandler(ElementHandler handler) {
        getDispatchHandler().setDefaultHandler(handler);
    }

    // Implementation methods
    // -------------------------------------------------------------------------
    public Document parseDocument() throws DocumentException, IOException,
            XmlPullParserException {
        DocumentFactory df = getDocumentFactory();
        Document document = df.createDocument();
        Element parent = null;
        XmlPullParser pp = getXPPParser();
        int count = 0;
        while (true) {
            int type = -1;
            type = pp.nextToken();
            switch (type) {
            case XmlPullParser.PROCESSING_INSTRUCTION: {
                String text = pp.getText();
                int loc = text.indexOf(" ");
                if (loc >= 0) {
                    document.addProcessingInstruction(text.substring(0, loc),
                            text.substring(loc + 1));
                } else
                    document.addProcessingInstruction(text, "");
                break;
            }
            case XmlPullParser.COMMENT: {
                if (parent != null)
                    parent.addComment(pp.getText());
                else
                    document.addComment(pp.getText());
                break;
            }
            case XmlPullParser.CDSECT: {
                String text = pp.getText();
                if (parent != null) {
                    parent.addCDATA(text);
                } else {
                    if (text.trim().length() > 0) {
                        throw new DocumentException(
                                "Cannot have text content outside of the root document");
                    }
                }
                break;

            }
            case XmlPullParser.ENTITY_REF: {
                String text = pp.getText();
                if (parent != null) {
                    parent.addText(text);
                } else {
                    if (text.trim().length() > 0) {
                        throw new DocumentException(
                                "Cannot have an entityref outside of the root document");
                    }
                }
                break;
            }
            case XmlPullParser.END_DOCUMENT: {
                return document;
            }
            case XmlPullParser.START_TAG: {
                QName qname = (pp.getPrefix() == null) ? df.createQName(
                        pp.getName(), pp.getNamespace()) : df.createQName(
                        pp.getName(), pp.getPrefix(), pp.getNamespace());
                Element newElement = null;
                // Do not include the namespace if this is the start tag of a
                // new packet
                // This avoids including "jabber:client", "jabber:server" or
                // "jabber:component:accept"
                if ("jabber:client".equals(qname.getNamespaceURI())
                        || "jabber:server".equals(qname.getNamespaceURI())
                        || "jabber:component:accept".equals(qname
                                .getNamespaceURI())
                        || "http://jabber.org/protocol/httpbind".equals(qname
                                .getNamespaceURI())) {
                    newElement = df.createElement(pp.getName());
                } else {
                    newElement = df.createElement(qname);
                }
                int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
                int nsEnd = pp.getNamespaceCount(pp.getDepth());
                for (int i = nsStart; i < nsEnd; i++)
                    if (pp.getNamespacePrefix(i) != null)
                        newElement.addNamespace(pp.getNamespacePrefix(i),
                                pp.getNamespaceUri(i));
                for (int i = 0; i < pp.getAttributeCount(); i++) {
                    QName qa = (pp.getAttributePrefix(i) == null) ? df
                            .createQName(pp.getAttributeName(i)) : df
                            .createQName(pp.getAttributeName(i),
                                    pp.getAttributePrefix(i),
                                    pp.getAttributeNamespace(i));
                    newElement.addAttribute(qa, pp.getAttributeValue(i));
                }
                if (parent != null) {
                    parent.add(newElement);
                } else {
                    document.add(newElement);
                }
                parent = newElement;
                count++;
                break;
            }
            case XmlPullParser.END_TAG: {
                if (parent != null) {
                    parent = parent.getParent();
                }
                count--;
                if (count < 1) {
                    return document;
                }
                break;
            }
            case XmlPullParser.TEXT: {
                String text = pp.getText();
                if (parent != null) {
                    parent.addText(text);
                } else {
                    if (text.trim().length() > 0) {
                        throw new DocumentException(
                                "Cannot have text content outside of the root document");
                    }
                }
                break;
            }
            default: {
                ;
            }
            }
        }
    }

    protected DispatchHandler getDispatchHandler() {
        if (dispatchHandler == null) {
            dispatchHandler = new DispatchHandler();
        }
        return dispatchHandler;
    }

    protected void setDispatchHandler(DispatchHandler dispatchHandler) {
        this.dispatchHandler = dispatchHandler;
    }

    /**
     * Factory method to create a Reader from the given InputStream.
     */
    protected Reader createReader(InputStream in) throws IOException {
        return new BufferedReader(new InputStreamReader(in));
    }
}
src/main/java/org/jivesoftware/smack/packet/Bind.java
public class Bind extends IQ {

    public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-bind";
    public static final String ELEMENT = "bind";
    private Element bindEl;

    public Bind(Element el) {
        super(el);
        this.bindEl = element.element(ELEMENT);
    }

    public Bind() {
        super();
        setType(IQ.Type.set);
        this.bindEl = element.addElement(ELEMENT, NAMESPACE);
    }

    public String getResource() {
        return bindEl.elementText("resource");
    }

    public void setResource(String resource) {
        PacketParserUtils.updateText(bindEl, "resource", resource);
    }

    public String getJid() {
        return bindEl.elementText("jid");
    }

    public void setJid(String jid) {
        PacketParserUtils.updateText(bindEl, "jid", jid);
    }
}
src/main/java/org/jivesoftware/smack/packet/Authentication.java
public class Authentication extends IQ {

    private Element queryEl;

    /**
     * Create a new authentication packet. By default, the packet will be in
     * "set" mode in order to perform an actual authentication with the server.
     * In order to send a "get" request to get the available authentication
     * modes back from the server, change the type of the IQ packet to "get":
     * <p/>
     * <p>
     * <tt>setType(IQ.Type.GET);</tt>
     */
    public Authentication() {
        super();
        setType(IQ.Type.set);
        queryEl = element.addElement("query", "jabber:iq:auth");
        queryEl.addElement("username");
        queryEl.addElement("digest");
        queryEl.addElement("password");
        queryEl.addElement("resource");
    }

    public Authentication(Element el) {
        super(el);
        queryEl = element.element("query");
    }

    /**
     * Returns the username, or <tt>null</tt> if the username hasn't been sent.
     * 
     * @return the username.
     */
    public String getUsername() {
        return queryEl.elementText("username");
    }

    /**
     * Sets the username.
     * 
     * @param username
     *            the username.
     */
    public void setUsername(String username) {
        PacketParserUtils.updateText(queryEl, "username", username);
    }

    /**
     * Returns the plain text password or <tt>null</tt> if the password hasn't
     * been set.
     * 
     * @return the password.
     */
    public String getPassword() {
        return queryEl.elementText("password");
    }

    /**
     * Sets the plain text password.
     * 
     * @param password
     *            the password.
     */
    public void setPassword(String password) {
        PacketParserUtils.updateText(queryEl, "password", password);
    }

    /**
     * Returns the password digest or <tt>null</tt> if the digest hasn't been
     * set. Password digests offer a more secure alternative for authentication
     * compared to plain text. The digest is the hex-encoded SHA-1 hash of the
     * connection ID plus the user's password. If the digest and password are
     * set, digest authentication will be used. If only one value is set, the
     * respective authentication mode will be used.
     * 
     * @return the digest of the user's password.
     */
    public String getDigest() {
        return queryEl.elementText("digest");
    }

    /**
     * Sets the digest value using a connection ID and password. Password
     * digests offer a more secure alternative for authentication compared to
     * plain text. The digest is the hex-encoded SHA-1 hash of the connection ID
     * plus the user's password. If the digest and password are set, digest
     * authentication will be used. If only one value is set, the respective
     * authentication mode will be used.
     * 
     * @param connectionID
     *            the connection ID.
     * @param password
     *            the password.
     * @see org.jivesoftware.smack.Connection#getConnectionID()
     */
    public void setDigest(String connectionID, String password) {
        setDigest(StringUtils.hash(connectionID + password));
    }

    /**
     * Sets the digest value directly. Password digests offer a more secure
     * alternative for authentication compared to plain text. The digest is the
     * hex-encoded SHA-1 hash of the connection ID plus the user's password. If
     * the digest and password are set, digest authentication will be used. If
     * only one value is set, the respective authentication mode will be used.
     * 
     * @param digest
     *            the digest, which is the SHA-1 hash of the connection ID the
     *            user's password, encoded as hex.
     * @see org.jivesoftware.smack.Connection#getConnectionID()
     */
    public void setDigest(String digest) {
        PacketParserUtils.updateText(queryEl, "digest", digest);
    }

    /**
     * Returns the resource or <tt>null</tt> if the resource hasn't been set.
     * 
     * @return the resource.
     */
    public String getResource() {
        return queryEl.elementText("resource");
    }

    /**
     * Sets the resource.
     * 
     * @param resource
     *            the resource.
     */
    public void setResource(String resource) {
        PacketParserUtils.updateText(queryEl, "resource", resource);
    }
}
src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
public static class Failure extends Packet {
    private String condition;

    public Failure(String condition) {
        super(createEl(condition));
        this.condition = condition;
    }

    @SuppressWarnings("unchecked")
    public Failure(Element element) {
        super(element);
        List<Element> conds = element.elements();
        if (!conds.isEmpty()) {
            this.condition = conds.iterator().next().getName();
        }
    }

    private static Element createEl(String condition) {
        Element el = new DefaultElement("failure",
                Namespace.get("urn:ietf:params:xml:ns:xmpp-sasl"));
        if (condition != null && condition.trim().length() > 0) {
            el.addElement(condition);
        }
        return el;
    }

    /**
     * Get the SASL related error condition.
     * 
     * @return the SASL related error condition.
     */
    public String getCondition() {
        return condition;
    }

    @Override
    public Packet createCopy() {
        return new Failure(this.getElement().createCopy());
    }
}
src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
public static class Success extends Packet {

    public Success(Element element) {
        super(element);
    }

    @Override
    public Packet createCopy() {
        return new Success(this.getElement().createCopy());
    }
}
src/main/java/org/jivesoftware/smack/Connection.java
protected static class ListenerWrapper {

    private PacketListener packetListener;
    private PacketFilter packetFilter;

    /**
     * Create a class which associates a packet filter with a listener.
     * 
     * @param packetListener
     *            the packet listener.
     * @param packetFilter
     *            the associated filter or null if it listen for all
     *            packets.
     */
    public ListenerWrapper(PacketListener packetListener,
            PacketFilter packetFilter) {
        this.packetListener = packetListener;
        this.packetFilter = packetFilter;
    }

    /**
     * Notify and process the packet listener if the filter matches the
     * packet.
     * 
     * @param packet
     *            the packet which was sent or received.
     */
    public void notifyListener(Packet packet) {
        if (packetFilter == null || packetFilter.accept(packet)) {
            packetListener.processPacket(packet);
        }
    }
}
src/main/java/org/jivesoftware/smack/sasl/SASLMechanism.java
public static class Challenge extends Packet {

    public Challenge(String data) {
        super(createChallengeEl(data));
    }

    public Challenge(Element createCopy) {
        super(createCopy);
    }

    @Override
    public Packet createCopy() {
        return new Challenge(this.element.createCopy());
    }
}
src/main/java/org/jamppa/client/plugin/Plugin.java
public interface Plugin {

    public void create(XMPPClient xmppClient);

    public void checkSupport(Element featuresEl);

    public Packet parse(Element el);
    
    public void shutdown();

}
src/main/java/org/jivesoftware/smack/ping/packet/Ping.java
public class Ping extends IQ {

    public static final String NAMESPACE = "urn:xmpp:ping";
    public static final String ELEMENT = "ping";

    public Ping() {
        element.addElement(ELEMENT, NAMESPACE);
    }

    public Ping(String to) {
        this();
        setTo(to);
        setType(IQ.Type.get);
    }

    public Ping(Element doc) {
        super(doc);
    }

}


Question: import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.dom4j.Element;
import org.dom4j.io.XPPPacketReader;
import org.jamppa.client.plugin.Plugin;
import org.jivesoftware.smack.Connection.ListenerWrapper;
import org.jivesoftware.smack.packet.Authentication;
import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.ping.packet.Ping;
import org.jivesoftware.smack.sasl.SASLMechanism.Challenge;
import org.jivesoftware.smack.sasl.SASLMechanism.Failure;
import org.jivesoftware.smack.sasl.SASLMechanism.Success;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketError.Condition;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Roster;
            innerReader = new XPPPacketReader();
            innerReader.setXPPFactory(XmlPullParserFactory.newInstance());
            innerReader.getXPPParser().setInput(connection.reader);
            reset = true;
        } catch (Exception xppe) {
            LOGGER.log(Level.WARN, "Error while resetting parser", xppe);
        }
    }

    private void startStream() throws XmlPullParserException, IOException {
        XmlPullParser xpp = innerReader.getXPPParser();
        for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
            eventType = xpp.next();
        }
        parseStreamStart(xpp);
    }

    private void parseStreamStart(XmlPullParser parser) {
        if ("jabber:client".equals(parser.getNamespace(null))) {
            for (int i = 0; i < parser.getAttributeCount(); i++) {
                if (parser.getAttributeName(i).equals("id")) {
                    connectionID = parser.getAttributeValue(i);
                    if (!"1.0".equals(parser.getAttributeValue("", "version"))) {
                        releaseConnectionIDLock();
                    }
                } else if (parser.getAttributeName(i).equals("from")) {
                    connection.config.setServiceName(parser
                            .getAttributeValue(i));
                }
            }
        }
    }

    /**
     * Parse top-level packets in order to process them further.
     * 
     * @param thread
     *            the thread that is being used by the reader to parse incoming
     *            packets.
     */
    private void parsePackets(Thread thread) {
        try {
            while (!done) {
                if (reset) {
                    startStream();
                    LOGGER.debug("Started xmlstream...");
                    reset = false;
                    continue;
                }
                Element doc = innerReader.parseDocument().getRootElement();
                if (doc == null) {
                    connection.disconnect();
                    LOGGER.debug("End of xmlstream.");
                    continue;
                }
                Packet packet = null;
                LOGGER.debug("Processing packet " + doc.asXML());
                packet = parseFromPlugins(doc, packet);
                if (packet == null) {
                    packet = parseFromCore(doc);
                }
                if (packet != null) {
                    processPacket(packet);
                }
            }
        } catch (Exception e) {
            if (!done && !connection.isSocketClosed()) {
                connection.notifyConnectionError(e);
                if (!connection.isConnected()) {
                    releaseConnectionIDLock();
                }
            }
        }
    }

    private Packet parseFromCore(Element doc) throws XMPPException,
            IOException, XmlPullParserException, Exception {
        String tag = doc.getName();
        Packet packet = null;
        if ("message".equals(tag)) {
            packet = new Message(doc);
        } else if ("presence".equals(tag)) {
            packet = new Presence(doc);
        } else if ("iq".equals(tag)) {
            packet = parseIQ(doc);
        } else if ("error".equals(tag)) {
            throw new XMPPException(PacketParserUtils.parseStreamError(doc));
        } else if ("features".equals(tag)) {
            parseFeatures(doc);
        } else if ("proceed".equals(tag)) {
            connection.proceedTLSReceived();
            resetParser();
        } else if ("failure".equals(tag)) {
            parseFailure(doc);
        } else if ("challenge".equals(tag)) {
            parseChallenge(doc);
        } else if ("success".equals(tag)) {
            parseSuccess(doc);
        } else if ("compressed".equals(tag)) {
            connection.startStreamCompression();
            resetParser();
        } else {
            throw new XmlPullParserException("Unknown packet type was read: "
                    + tag);
        }
        return packet;
    }

    private Packet parseFromPlugins(Element doc, Packet packet) {
        for (Plugin plugin : connection.getPlugins()) {
            packet = plugin.parse(doc);
            if (packet != null) {
                break;
            }
        }
        return packet;
    }

    private void parseChallenge(Element doc) throws IOException {
        String challengeData = doc.getText();
Answer:         processPacket(new Challenge(doc));