net.skillupjapan.openfire.plugin.SUJMessageHandlerPlugin.java Source code

Java tutorial

Introduction

Here is the source code for net.skillupjapan.openfire.plugin.SUJMessageHandlerPlugin.java

Source

/**
 * $RCSfile$
 * $Revision: 1594 $
 * $Date: 2005-07-04 18:08:42 +0100 (Mon, 04 Jul 2005) $
 *
 * Copyright (C) 2004-2008 Jive Software. 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
 *
 *     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 net.skillupjapan.openfire.plugin;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;

import org.jivesoftware.openfire.MessageRouter;
import org.jivesoftware.openfire.IQRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.muc.MultiUserChatManager;
import org.jivesoftware.openfire.muc.MultiUserChatService;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.PresenceManager;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.openfire.handler.IQHandler;
import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.session.LocalClientSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;

import org.dom4j.Element;
import org.dom4j.Namespace;

/**
 * Packet handler plugin.
 * 
 * @author Daniel Pereira
 */
public class SUJMessageHandlerPlugin implements Plugin, PacketInterceptor {

    private static final Logger Log = LoggerFactory.getLogger(SUJMessageHandlerPlugin.class);

    /**
     * The expected value is a boolean
     */
    public static final String REGISTER_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.register.handler.enabled";

    /**
     * The expected value is a boolean
     */
    public static final String DATE_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.date.handler.enabled";

    /**
     * The expected value is a boolean
     */
    public static final String UNREAD_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.unread.handler.enabled";

    /**
     * The expected value is a boolean
     */
    public static final String OUT_OF_MUC_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.outofmuc.handler.enabled";

    /**
     * The expected value is a boolean
     */
    public static final String OFFLINE_MUC_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.offlinemuc.handler.enabled";

    /**
     * The expected value is a boolean
     */
    public static final String SECOND_DEVICE_HANDLER_ENABLED_PROPERTY = "plugin.sujMessageHandler.2nd_device.handler.enabled";

    /**
     * the hook into the inteceptor chain
     */
    private InterceptorManager interceptorManager;

    /**
     * the hook used for the group manager
     */
    private MultiUserChatManager mucManager;

    /**
     * the hook used for the presence manager
     */
    private PresenceManager presenceManager;

    /**
     * the hook used for the user manager
     */
    private UserManager userManager;

    /**
     * the hook used for the session manager
     */
    private SessionManager sessionManager;

    /**
     * the hook used to handle groups
     */
    private MultiUserChatService mucService;

    /**
     * the hook used to handle groups
     */
    private MultiUserChatService mucServicePrivate;

    /**
     * used to send messages
     */
    private MessageRouter messageRouter;

    /**
     * used to send iq packets
     */
    private IQRouter iqRouter;

    /**
     * delegate that does the real work of this plugin
     */
    private SUJMessageHandler sujMessageHandler;

    /**
     * flag if Registration parameters should be handled.
     */
    private boolean registerHandlerEnabled;

    /**
     * flag if Date appending should be handled.
     */
    private boolean dateHandlerEnabled;

    /**
     * flag if Unread queries should be handled.
     */
    private boolean unreadHandlerEnabled;

    /**
     * flag if MUC messages should be handled.
     */
    private boolean outOfMucHandlerEnabled;

    /**
     * flag if MUC messages should be handled.
     */
    private boolean offlineMucHandlerEnabled;

    /**
     * flag if second device messages should be handled.
     */
    private boolean secondDeviceHandlerEnabled;

    /**
     * Hash with all the rooms
     */
    private Map<JID, MUCRoom> rooms = new ConcurrentHashMap<JID, MUCRoom>();

    public SUJMessageHandlerPlugin() {
        sujMessageHandler = new SUJMessageHandler();
        interceptorManager = InterceptorManager.getInstance();
        mucManager = XMPPServer.getInstance().getMultiUserChatManager();
        presenceManager = XMPPServer.getInstance().getPresenceManager();
        userManager = XMPPServer.getInstance().getUserManager();
        sessionManager = XMPPServer.getInstance().getSessionManager();

        messageRouter = XMPPServer.getInstance().getMessageRouter();
        iqRouter = XMPPServer.getInstance().getIQRouter();
        mucService = mucManager.getMultiUserChatService("conference");
        mucServicePrivate = mucManager.getMultiUserChatService("private");

        // Initialy populate the hash of rooms in the server
        makeHashByJID();

        iqRouter.addHandler(new SecondDeviceIQHandler());
    }

    /**
     * Restores the plugin defaults.
     */
    public void reset() {
        setRegistHandlerEnabled(false);
        setDateHandlerEnabled(false);
        setUnreadHandlerEnabled(false);
        setOutOfMUCHandlerEnabled(false);
        setOfflineMUCHandlerEnabled(false);
        setSecondDeviceHandlerEnabled(false);
    }

    public boolean isRegisterHandlerEnabled() {
        return registerHandlerEnabled;
    }

    public boolean isDateHandlerEnabled() {
        return dateHandlerEnabled;
    }

    public boolean isUnreadHandlerEnabled() {
        return unreadHandlerEnabled;
    }

    public boolean isOutOfMUCHandlerEnabled() {
        return outOfMucHandlerEnabled;
    }

    public boolean isOfflineMUCHandlerEnabled() {
        return offlineMucHandlerEnabled;
    }

    public boolean isSecondDeviceHandlerEnabled() {
        return secondDeviceHandlerEnabled;
    }

    public void setRegistHandlerEnabled(boolean enabled) {
        registerHandlerEnabled = enabled;
        JiveGlobals.setProperty(REGISTER_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void setDateHandlerEnabled(boolean enabled) {
        dateHandlerEnabled = enabled;
        JiveGlobals.setProperty(DATE_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void setUnreadHandlerEnabled(boolean enabled) {
        unreadHandlerEnabled = enabled;
        JiveGlobals.setProperty(UNREAD_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void setOutOfMUCHandlerEnabled(boolean enabled) {
        outOfMucHandlerEnabled = enabled;
        JiveGlobals.setProperty(OUT_OF_MUC_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void setOfflineMUCHandlerEnabled(boolean enabled) {
        offlineMucHandlerEnabled = enabled;
        JiveGlobals.setProperty(OFFLINE_MUC_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void setSecondDeviceHandlerEnabled(boolean enabled) {
        secondDeviceHandlerEnabled = enabled;
        JiveGlobals.setProperty(SECOND_DEVICE_HANDLER_ENABLED_PROPERTY, enabled ? "true" : "false");
    }

    public void initializePlugin(PluginManager pManager, File pluginDirectory) {
        // configure this plugin
        initHandlers();

        // register with interceptor manager
        interceptorManager.addInterceptor(this);
    }

    private void initHandlers() {
        // default to false
        registerHandlerEnabled = JiveGlobals.getBooleanProperty(REGISTER_HANDLER_ENABLED_PROPERTY, false);
        dateHandlerEnabled = JiveGlobals.getBooleanProperty(DATE_HANDLER_ENABLED_PROPERTY, false);
        unreadHandlerEnabled = JiveGlobals.getBooleanProperty(UNREAD_HANDLER_ENABLED_PROPERTY, false);
        outOfMucHandlerEnabled = JiveGlobals.getBooleanProperty(OUT_OF_MUC_HANDLER_ENABLED_PROPERTY, false);
        offlineMucHandlerEnabled = JiveGlobals.getBooleanProperty(OFFLINE_MUC_HANDLER_ENABLED_PROPERTY, false);
        secondDeviceHandlerEnabled = JiveGlobals.getBooleanProperty(SECOND_DEVICE_HANDLER_ENABLED_PROPERTY, false);
    }

    /**
     * @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
     */
    public void destroyPlugin() {
        // unregister with interceptor manager
        interceptorManager.removeInterceptor(this);
    }

    public void interceptPacket(Packet packet, Session session, boolean read, boolean processed)
            throws PacketRejectedException {

        if ((packet instanceof Message)) {
            Log.warn("Got message: " + packet.toString());
        }

        /**
         * Ignore forwarded messages
         */
        if ((packet instanceof Message) && (((Message) packet).getElement().attributeValue("forwarded") != null)) {
            if (Log.isDebugEnabled()) {
                Log.warn("Ignoring forwarded message: " + packet.toString());
            }
            return;
        }

        /**
         * Adds date to all conversation packets, in the same fashion
         * as an offline packet, as described below.
         *
         * Returned message:
         * <message from='romeo@montague.net/orchard' to='juliet@capulet.com' type='chat'>
         *    <body>
         *        O blessed, blessed night! I am afeard.
         *        Being in night, all this is but a dream,
         *        Too flattering-sweet to be substantial.
         *    </body>
         *    <delay xmlns='urn:xmpp:delay' from='capulet.com' stamp='2002-09-10T23:08:25Z'/>
         * </message>
         */
        if (isValidAddDataPacket(packet, read, processed)) {
            Packet original = packet;

            // Add date to message packets
            Packet dated_packet = sujMessageHandler.addDate(packet);
            original = dated_packet;

            if (Log.isDebugEnabled()) {
                Log.debug("SUJ Message Handler: modified packet:" + original.toString());
            }
        }

        /**
        * An IQ packet can send a query for the count of messages for the given rooms
        *
        * Example query:
        * <iq type='get' id='xdfw-1'>
        *   <query xmlns='xmpp:join:msgq'>
        *      <room room_jid='rm_015551123@conference.mediline-jabber01' since='CCYY-MM-DDThh:mm:ss[.sss]TZD' />
        *      <room room_jid='rm_515156520@conference.mediline-jabber01' since='2014-04-11T09:10:59.303+0000' />
        *      <room room_jid='pc_845169551@conference.mediline-jabber01' since='1970-01-01T00:00:00Z' />
        *      ...
        *   </query>
        * </iq>
        *
        * Replied query:
        * <iq type='result' id='xdfw-1'>
        *    <query xmlns='xmpp:join:msgq'>
        *       <room room_jid='rm_015551123@conference.mediline-jabber01'>
        *           <msg_count>3</msg_count>
        *       </room>
        *       <room room_jid='rm_515156520@conference.mediline-jabber01'>
        *           <msg_count>0</msg_count>
        *       </room>
        *       ...
        *    </query>
        * </iq>
        */
        if (isValidMsgQueryPacket(packet, read, processed)) {
            Element child = ((IQ) packet).getChildElement();
            if (child != null) {
                String uri = ((Element) child).getNamespaceURI().toString();
                String qualifiedname = ((Element) child).getQualifiedName().toString();

                if (uri.equals("xmpp:join:msgq") && qualifiedname.equals("query")) {
                    Log.warn("MSGQ packet: " + packet.toString());

                    JID from = new JID(((IQ) packet).getElement().attribute("from").getValue());
                    //Get the fields we are interested in (all the "room" requests)
                    List children = ((IQ) packet).getChildElement().elements("room");
                    if (!children.isEmpty()) {
                        Iterator fieldElems = children.iterator();
                        int rescount = 0;

                        // Create reply
                        IQ reply = ((IQ) packet).createResultIQ(((IQ) packet)).createCopy();
                        reply.setChildElement("query", "xmpp:join:msgq");

                        Element cur;
                        String qroom;
                        String qdate;
                        while (fieldElems.hasNext()) {
                            cur = (Element) fieldElems.next();
                            qroom = cur.attribute("room_jid").getValue();
                            qdate = cur.attribute("since").getValue();
                            rescount = sujMessageHandler.getArchivedMessageCount(qroom, qdate, from.toBareJID());

                            // Choo choo, makes the train
                            ((IQ) reply).getChildElement().addElement("room").addAttribute("room_jid", qroom)
                                    .addElement("msg_count").addText(Integer.toString(rescount));

                            if (Log.isDebugEnabled()) {
                                Log.warn("I got the query token! Search for messages in " + qroom + " older than "
                                        + qdate + ": " + rescount + " messages ");
                            }
                        }

                        if (Log.isDebugEnabled()) {
                            Log.warn("Sending IQ reply: " + reply.toString());
                        }
                        // Send packet
                        try {
                            iqRouter.route(reply);
                        } catch (Exception rf) {
                            Log.error("Routing failed for IQ packet: " + reply.toString());
                        }

                    } else {
                        Log.warn("Empty MsgQueryPacket!");
                    }
                }
            }
        }

        /**
        * Hijack the registration request and parse information related to the JOIN service
        * This information is sent in the body of the register query.
        *
        * Example registration packet:
        * <iq type="set" id="purple343f3f96" from="mediline-jabber01/68b64d0a">
        *   <query xmlns="xmpp:iq:register">
        *     <x xmlns="xmpp:x:data" type="submit">
        *       <field var="FORM_TYPE">
        *         <value>xmpp:iq:register</value>
        *       </field>
        *       ...
        *     </x>
        *   </query>
        * </iq>
        */
        if (isValidRegisterPacket(packet, read, processed)) {
            String uri = ((IQ) packet).getChildElement().getNamespaceURI().toString();
            String qualifiedname = ((IQ) packet).getChildElement().getQualifiedName().toString();

            if (uri.equals("xmpp:iq:register") && qualifiedname.equals("query")) {
                String innerUri = ((IQ) packet).getChildElement().element("x").getNamespaceURI().toString();
                String innerQualifiedname = ((IQ) packet).getChildElement().element("x").getQualifiedName()
                        .toString();
                String innerType = ((IQ) packet).getChildElement().element("x").attribute("type").getValue()
                        .toString();
                if (Log.isDebugEnabled()) {
                    Log.warn("Possible register packet... ");
                }

                if (innerUri.equals("xmpp:x:data") && innerQualifiedname.equals("x")
                        && innerType.equals("submit")) {
                    if (Log.isDebugEnabled()) {
                        Log.warn("We got a registration submission!!");
                        Log.warn("packet:" + packet.toString());
                    }

                    //Get the field we are interested in, in this example we use the "email" attribute as the token
                    Iterator fieldElems = ((IQ) packet).getChildElement().element("x").elementIterator();
                    Element cur;
                    while (fieldElems.hasNext()) {
                        cur = (Element) fieldElems.next();
                        if (("email").equals(cur.attribute("var").getValue())) {
                            Log.warn("I got the token! It's " + cur.getStringValue());
                        }
                    }

                    try {
                        if (Log.isDebugEnabled()) {
                            Log.warn("Sleeping ...");
                        }

                        //Thread.sleep(1000);
                        sujMessageHandler.googleReq();

                        if (Log.isDebugEnabled()) {
                            Log.warn("Slept");
                        }
                    } catch (Exception ie) {
                        if (Log.isDebugEnabled()) {
                            Log.warn("Problem sleeping: " + ie.toString());
                        }
                    }
                }
            }
        }

        /**
        * Hijack the MUC requests and check if notifications should be sent when:
        * - user is online but there's ongoing activity on a MUC the user belongs to (live notifications/IQ messages)
        * - user if offline and there are unread messages (push notifications)
        *
        * Example MUC activity packet:
        * <message content="text" to="gc_930f3e070d7@conference.mediline" type="groupchat" from="test2@mediline/7e3">
        *   <body>Message</body>
        *   <delay xmlns="urn:xmpp:delay" from="test2@mediline/7e3" stamp="2010-02-12T13:36:22.715Z"/>
        * </message>
        */
        if (isValidOutOfMUCPacket(packet, read, processed)) {
            //Log.warn("We got a MUC packet!" + packet.toString());

            // This needs to be improved!!!
            // Right now, I'm only remaking the map if new chat messages from an unknown (new) room appear
            // A listener for new MUC rooms should be handling this
            MUCRoom room = rooms.get(new JID(packet.getElement().attribute("to").getValue()));
            if (room == null) {
                makeHashByJID();
                room = rooms.get(new JID(packet.getElement().attribute("to").getValue()));
            }

            if (room != null) {
                if (room.getMembers() != null) {
                    if (!room.getMembers().isEmpty()) {
                        Iterator room_users = room.getMembers().iterator();
                        JID user;
                        while (room_users.hasNext()) {
                            user = (JID) room_users.next();
                            MUCRole role = room.getOccupantByFullJID(user);

                            // User not in chatroom
                            if (role == null) {
                                if (Log.isDebugEnabled()) {
                                    Log.warn("User " + user.toString() + " not in chatroom!");
                                }
                                try {
                                    // If user is online still send the message (soft-forward)
                                    if (presenceManager.isAvailable(userManager.getUser(user.getNode()))) {
                                        if (Log.isDebugEnabled()) {
                                            Log.warn("Forwarding message to user " + user.toString());
                                        }
                                        Message forwardMsg = (Message) packet.createCopy();
                                        forwardMsg.setFrom(new JID(packet.getElement().attribute("to").getValue()));
                                        forwardMsg.setTo(user);
                                        forwardMsg.getElement().addAttribute("forwarded", "1");
                                        messageRouter.route(forwardMsg);
                                    } else {
                                        // If push notifications are enabled
                                        if (offlineMucHandlerEnabled) {
                                            // Send push notification to user, call you favouritest APN
                                            // ... Good luck! :D
                                            if (Log.isDebugEnabled()) {
                                                Log.warn("Sending push notification to user " + user.toString());
                                            }
                                        }

                                    }
                                } catch (Exception e) {
                                    Log.warn("User " + user.getNode() + " not found: " + e);
                                }
                            }
                        }
                    }
                }
            }
        }

        /**
         * Handles the second device check requests. This request is received
         * without the client being authenticated with the server.
         *
         * Received message:
         * <iq type="get" id="purple3436">
         *   <query xmlns="xmpp:join:2nd_device">
         *     <id>username</id>
         *     <password>drowssap</password>
         *   </query>
         * </iq>
         * 
         * A successful reply is:
         * <iq type="result" id="purple343f3f96">
         *   <query xmlns="xmpp:join:2nd_device">
         *     <jid>test2@mediline</jid>
         *   </query>
         * </iq>
         *
         * A failed password reply is:
         * <iq type="error" id="purple343f3f96">
         *   <error type="cancel">
         *     <not-allowed xmlns="xmpp:join:2nd_device"/>
         *   </error>
         * </iq>
         *
         * An empty JID and secondID matchs reply is:
         * <iq type="error" id="purple343f3f96">
         *   <error type="cancel">
         *     <not-acceptable xmlns="xmpp:join:2nd_device"/>
         *   </error>
         * </iq>
         */
        if (isValidCheck2ndDevicePacket(packet, read, processed)) {
            String uri = ((IQ) packet).getChildElement().getNamespaceURI().toString();
            String qualifiedname = ((IQ) packet).getChildElement().getQualifiedName().toString();
            String jid = null;

            if (uri.equals("xmpp:join:2nd_device") && qualifiedname.equals("query")) {

                //Get the id and password fields
                String id = ((IQ) packet).getChildElement().element("id").getStringValue();
                String password = ((IQ) packet).getChildElement().element("password").getStringValue();

                Log.warn("Just got a 2nd device check IQ with username " + id + " and password " + password);
                Log.warn("Reply: " + packet.toString());

                try {
                    jid = sujMessageHandler.getSecondDeviceJID(id, password);
                } catch (Exception ie) {
                    if (Log.isDebugEnabled()) {
                        Log.warn("Problem on request: " + ie.toString());
                    }
                }

                // Build reply
                IQ replyPacket = ((IQ) packet).createResultIQ(((IQ) packet)).createCopy();
                //replyPacket.setTo((JID)null);

                if (jid == null) {
                    ((IQ) replyPacket).setType(IQ.Type.error);
                    ((IQ) replyPacket).getElement().addElement("error").addAttribute("type", "cancel")
                            .addElement("not-acceptable").addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
                } else if (jid == "invalid username or password") {
                    ((IQ) replyPacket).setType(IQ.Type.error);
                    ((IQ) replyPacket).getElement().addElement("error").addAttribute("type", "cancel")
                            .addElement("not-allowed").addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
                } else {
                    ((IQ) replyPacket).setChildElement("query", "xmpp:join:2nd_device");
                    ((IQ) replyPacket).getChildElement().addElement("jid").addText(jid);
                }

                Log.warn("Reply: " + replyPacket.toString());

                // Send packet
                try {
                    //iqRouter.route(replyPacket);
                    session.process(replyPacket);
                } catch (Exception rf) {
                    Log.error("Routing failed for IQ getting 2nd device packet");
                }
            }
        }

        /**
         * Handles the second device setup requests.
         *
         * Received message:
         * <iq type="set" id="purple3436">
         *   <query xmlns="xmpp:join:2nd_device">
         *     <id>username</id>
         *     <password>drowssap</password>
         *     <jid>aa@bbb.com<jid>
         *   </query>
         * </iq>
         *
         * On ok, send:
         * <iq type="result" id="purple343f3f96">
         *   <query xmlns="xmpp:join:2nd_device"/>
         * </iq>    
         *
         * On error, the reply is:
         * <iq type="error" id="purple343f3f96">
         *   <error type="cancel">
         *     <not-acceptable xmlns="xmpp:join:2nd_device"/>
         *   </error>
         * </iq>         
         */
        if (isValidCreate2ndDevicePacket(packet, read, processed)) {
            Log.warn("Inside 2nd device SET");
            Log.warn("WHO? " + packet.toString());
            String uri = ((IQ) packet).getChildElement().getNamespaceURI().toString();
            String qualifiedname = ((IQ) packet).getChildElement().getQualifiedName().toString();

            if (uri.equals("xmpp:join:2nd_device") && qualifiedname.equals("query") && session.getStatus() == 3) {

                //Get the id and password fields
                String id = ((IQ) packet).getChildElement().element("id").getStringValue();
                String password = ((IQ) packet).getChildElement().element("password").getStringValue();
                String jid = ((IQ) packet).getElement().attribute("from").getValue();
                int queryRes = 0;

                Log.warn("Just got a 2nd device registration IQ with username " + id + " password " + password
                        + " and jid " + jid);

                try {
                    queryRes = sujMessageHandler.setSecondDeviceJID(id, password, jid);

                    // Build reply
                    IQ replyPacket = ((IQ) packet).createResultIQ(((IQ) packet)).createCopy();

                    if (queryRes == 0) {
                        ((IQ) replyPacket).setType(IQ.Type.error);
                        ((IQ) replyPacket).getElement().addElement("error").addAttribute("type", "cancel")
                                .addElement("conflict").addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
                    } else {
                        ((IQ) replyPacket).setChildElement("query", "xmpp:join:2nd_device");
                    }

                    Log.warn("Reply: " + replyPacket.toString());

                    if (replyPacket != null) {
                        iqRouter.route(replyPacket);
                    } else {
                        Log.error("Routing failed for IQ setting 2nd device packet: ");
                    }

                } catch (Exception ie) {
                    if (Log.isDebugEnabled()) {
                        Log.warn("Problem on request: " + ie.toString());
                    }
                }
            }
        }
    }

    /**
     * Build a map with JID, MUCRoom from all chatrooms in the system
     */
    private void makeHashByJID() {
        Iterator mucs = mucService.getChatRooms().iterator();
        Iterator mucsPrivate = mucServicePrivate.getChatRooms().iterator();
        MUCRoom cr;

        while (mucs.hasNext()) {
            cr = (MUCRoom) mucs.next();
            rooms.put((JID) cr.getJID(), (MUCRoom) cr);
        }

        while (mucsPrivate.hasNext()) {
            cr = (MUCRoom) mucsPrivate.next();
            rooms.put((JID) cr.getJID(), (MUCRoom) cr);
        }
    }

    private boolean isValidAddDataPacket(Packet packet, boolean read, boolean processed) {
        return dateHandlerEnabled && !processed && read && packet instanceof Message;
    }

    private boolean isValidMsgQueryPacket(Packet packet, boolean read, boolean processed) {
        return unreadHandlerEnabled && !processed && read && packet instanceof IQ
                && ((IQ) packet).getType().equals(IQ.Type.get);
    }

    private boolean isValidRegisterPacket(Packet packet, boolean read, boolean processed) {
        return registerHandlerEnabled && !processed && read && packet instanceof IQ
                && ((IQ) packet).getType().equals(IQ.Type.set);
    }

    private boolean isValidOutOfMUCPacket(Packet packet, boolean read, boolean processed) {
        return outOfMucHandlerEnabled && !processed && read && packet instanceof Message
                && ((Message) packet).getType().equals(Message.Type.groupchat);
    }

    private boolean isValidCheck2ndDevicePacket(Packet packet, boolean read, boolean processed) {
        return secondDeviceHandlerEnabled && !processed && read && packet instanceof IQ
                && ((IQ) packet).getType().equals(IQ.Type.get);
    }

    private boolean isValidCreate2ndDevicePacket(Packet packet, boolean read, boolean processed) {
        return secondDeviceHandlerEnabled && !processed && read && packet instanceof IQ
                && ((IQ) packet).getType().equals(IQ.Type.set);
    }
}

class SecondDeviceIQHandler extends IQHandler {
    private static final Logger Log = LoggerFactory.getLogger(SecondDeviceIQHandler.class);

    public SecondDeviceIQHandler() {
        super(null);
    }

    public IQHandlerInfo getInfo() {
        return new IQHandlerInfo("query", "xmpp:join:2nd_device");
    }

    public IQ handleIQ(IQ packet) {
        Log.warn("Inside 2nd device Handler");

        Log.warn("Handler packet: " + packet.toString());

        //Get the id and password fields
        // String id = ((IQ) packet).getChildElement().element("id").getStringValue();
        // String password = ((IQ) packet).getChildElement().element("password").getStringValue();
        String jid = ((IQ) packet).getElement().attribute("to").getValue();
        // int queryRes = 0;

        SUJMessageHandler sujMessageHandler = new SUJMessageHandler();

        Log.warn("Step 1");

        LocalClientSession session = (LocalClientSession) sessionManager.getSession(packet.getTo());

        Log.warn("Step 2");

        try {
            //queryRes = sujMessageHandler.setSecondDeviceJID(id, password, jid);

            Log.warn("Step 2.5");
            // Build reply
            IQ replyPacket = ((IQ) packet).createCopy();
            Log.warn("Step 3");
            //replyPacket.setTo((JID)null);

            //Log.warn("Just got a 2nd device registration IQ with username " + id + " password " + password + " and jid " + jid);

            // if (queryRes == 0) {
            //     ((IQ) replyPacket).setType(IQ.Type.error);
            //     ((IQ) replyPacket).getElement().addElement("error").addAttribute("type", "cancel").addElement("conflict").addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
            // }
            // else {
            ((IQ) replyPacket).setChildElement("query", "xmpp:join:2nd_device");
            ((IQ) replyPacket).getElement().addAttribute("jid", jid).addElement("something").addNamespace("",
                    "xmpp:something:sebastian");
            // }

            Log.warn("Handler reply: " + replyPacket.toString());

            session.process(replyPacket);

            Log.warn("Step 4");

        } catch (Throwable ie) {
            Log.warn("Problem on request: " + ie.toString());
        }

        Log.warn("Step 5");

        return null;

    }
}