morphy.service.SocketConnectionService.java Source code

Java tutorial

Introduction

Here is the source code for morphy.service.SocketConnectionService.java

Source

/*
 *   Morphy Open Source Chess Server
 *   Copyright (c) 2008-2010, 2016-2017  http://code.google.com/p/morphy-chess-server/
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package morphy.service;

import java.io.IOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import morphy.Morphy;
import morphy.channel.Channel;
import morphy.properties.MorphyPreferences;
import morphy.properties.PreferenceKeys;
import morphy.service.ScreenService.Screen;
import morphy.timeseal.TimesealCoder;
import morphy.timeseal.TimesealParseResult;
import morphy.user.PersonalList;
import morphy.user.PlayerType;
import morphy.user.SocketChannelUserSession;
import morphy.user.User;
import morphy.user.UserLevel;
import morphy.user.UserSession;
import morphy.user.UserVars;
import morphy.utils.BufferUtils;
import morphy.utils.MorphyStringUtils;
import morphy.utils.SocketUtils;
import morphy.utils.john.DatabaseConnection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SocketConnectionService implements Service {
    protected static Log LOG = LogFactory.getLog(SocketConnectionService.class);
    private static final SocketConnectionService singletonInstance = new SocketConnectionService();

    public static SocketConnectionService getInstance() {
        return singletonInstance;
    }

    protected ServerSocketChannel serverSocketChannel;
    protected Selector serverSocketSelector;
    protected int maxCommunicationSizeBytes;
    protected Thread selectionThread = null;

    protected Map<Socket, SocketChannelUserSession> socketToSession = new HashMap<Socket, SocketChannelUserSession>();
    protected Map<Socket, StringBuilder> socketInputForCmd = new HashMap<Socket, StringBuilder>();

    protected TimesealCoder timesealCoder;
    protected String MSG_TIMESEAL_OK = "MSG_TIMESEAL_OK";

    protected Runnable selectSocketRunnable = new Runnable() {
        public void run() {
            try {
                while (true) {
                    if (Morphy.getInstance().isShutdown()) {
                        return;
                    }
                    serverSocketSelector.select();
                    Set<SelectionKey> keys = serverSocketSelector.selectedKeys();

                    // if (LOG.isInfoEnabled()) {
                    // LOG.info("Selected " + keys.size() + " keys.");
                    // }

                    Iterator<SelectionKey> i = keys.iterator();

                    while (i.hasNext()) {
                        SelectionKey key = i.next();
                        i.remove();

                        try {
                            if (key.isAcceptable()) {
                                final SocketChannel channel = serverSocketChannel.accept();
                                channel.configureBlocking(false);
                                channel.register(serverSocketSelector, SelectionKey.OP_READ);

                                ThreadService.getInstance().run(new Runnable() {
                                    public void run() {
                                        onNewChannel(channel);
                                    }
                                });
                            }
                            if (key.isReadable()) {
                                final SocketChannel channel = (SocketChannel) key.channel();
                                ThreadService.getInstance().run(new Runnable() {
                                    public void run() {
                                        onNewInput(channel);
                                    }
                                });
                            }
                        } catch (CancelledKeyException e) {
                            // logging the user out now.
                        }
                    }
                }
            } catch (Throwable t) {
                if (LOG.isErrorEnabled())
                    LOG.error("Error reading selector in SocketConnectionService", t);
            }
        }
    };

    private SocketConnectionService() {
        MorphyPreferences morphyPreferences = Morphy.getInstance().getMorphyPreferences();
        try {
            maxCommunicationSizeBytes = morphyPreferences
                    .getInt(PreferenceKeys.SocketConnectionServiceMaxCommunicationBytes);
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);

            /*Object obj = PreferenceService.getInstance().getProperty(PreferenceKeys.SocketConnectionServicePorts.toString());
            System.out.println(obj.getClass());
            if (obj instanceof java.util.ArrayList) {
               //System.out.println((java.util.ArrayList<String>)obj);
               String[] arr = ((java.util.ArrayList<String>)obj).toArray(new String[0]);
               System.out.println(java.util.Arrays.toString(arr));
               //serverSocketChannel.socket().
               for(int i=0;i<arr.length;i++) {
                  serverSocketChannel.socket().bind( 
                 new java.net.InetSocketAddress( Integer.parseInt(arr[i]) ));
                  if (LOG.isInfoEnabled()) {
              LOG.info("Listening on port " + arr[i]);
                  }
               }
            } else {
               if (LOG.isInfoEnabled()) {
                  serverSocketChannel.socket().bind( new java.net.InetSocketAddress( 5000 ));
                  LOG.info("LOAD CONFIG FAILED - Listening on port 5000");
               }
            }*/

            serverSocketChannel.socket().bind(new java.net.InetSocketAddress(
                    morphyPreferences.getInt(PreferenceKeys.SocketConnectionServicePorts.toString())));
            serverSocketSelector = Selector.open();
            serverSocketChannel.register(serverSocketSelector, SelectionKey.OP_ACCEPT);

            selectionThread = new Thread(selectSocketRunnable);
            selectionThread.setPriority(Thread.MAX_PRIORITY);
            selectionThread.start();

            LOG.info("Initialized Socket Connection Service host:" + serverSocketChannel.socket().getInetAddress()
                    + " " + serverSocketChannel.socket().getLocalPort());

            this.timesealCoder = new TimesealCoder();
        } catch (Throwable t) {
            if (LOG.isErrorEnabled())
                LOG.error("Error initializing SocketConnectionService", t);
        }
    }

    public void dispose() {
        try {
            serverSocketChannel.close();
        } catch (Throwable t) {
            if (LOG.isErrorEnabled())
                LOG.error("Error disposing SocketConnectionService", t);
        }
    }

    public String formatMessage(UserSession userSession, String message) {
        // In the future this might adjust width and handle nowrap.
        return MorphyStringUtils.formatServerMessage(message);
    }

    public void removeUserSession(SocketChannelUserSession session) {
        disposeSocketChannel(session.getChannel());
    }

    protected void disposeSocketChannel(SocketChannel channel) {
        if (channel.isConnected()) {
            try {
                channel.close();
            } catch (Throwable t) {
            }
        }
        socketToSession.remove(channel.socket());
    }

    protected void handleLoginPromptText(SocketChannelUserSession userSession, String message) {
        sendWithoutPrompt("\n", userSession);

        String name = message;
        if (name.equalsIgnoreCase("g"))
            name = "guest";

        if (name.matches("\\w{3,17}")) {
            if (LOG.isInfoEnabled()) {
                LOG.info("name=" + name);
            }

            UserService instance = UserService.getInstance();
            boolean isGuest = false;

            if (name.equalsIgnoreCase("g") || name.equalsIgnoreCase("guest")) {
                do {
                    name = instance.generateAnonymousHandle();
                } while (instance.isLoggedIn(name));

                //            userSession
                //                  .send("Logging you in as \""
                //                        + name
                //                        + "\"; you may use this name to play unrated games.\n"
                //                        + "(After logging in, do \"help register\" for more info on how to register.)\n\n"
                //                        + "" + "Press return to enter the server as \""
                //                        + name + "\":\n");
            }

            isGuest = !instance.isRegistered(name);

            if (isGuest) {
                sendWithoutPrompt(
                        "\"" + name + "\" is not a registered name. You may use this name to play unrated games.\n"
                                + "(After logging in, do \"help register\" for more info on how to register.)\n\n"
                                + "" + "Press return to enter the server as \"" + name + "\":",
                        userSession);
                //return;
            } else {
                sendWithoutPrompt(
                        "\"" + name + "\" is a registered name.  If it is yours, type the password.\n"
                                + "If not, just hit return to try another name.\n\n" + "" + "password: ",
                        userSession);
            }

            userSession.setCurrentState(SocketChannelUserSession.UserSessionState.LOGIN_NEED_PASSWORD);
            userSession.getUser().setUserName(name);
            userSession.getUser().setRegistered(!isGuest);
        } else {
            sendWithoutPrompt("Invalid user name: " + name + " Good Bye.\n", userSession);
            userSession.disconnect();
        }
    }

    protected void handlePasswordPromptText(SocketChannelUserSession userSession, String message) {
        String userPasswordEntered = message;
        String name = userSession.getUser().getUserName();
        boolean isGuest = !userSession.getUser().isRegistered();

        UserService instance = UserService.getInstance();
        /*try { userSession.getChannel().configureBlocking(true); } catch(Exception e) { e.printStackTrace(System.err); }*/

        if (!isGuest) {

            try {
                DatabaseConnection conn = DatabaseConnectionService.getInstance().getDBConnection();
                java.sql.Statement s = conn.getStatement();
                s.execute("SELECT `password` FROM `users` WHERE `username` = '" + name + "'");
                java.sql.ResultSet r = s.getResultSet();
                if (r.next()) {
                    String actualpass = r.getString(1);

                    if (!actualpass.equals(userPasswordEntered)) {
                        sendWithoutPrompt("**** Invalid password! ****\n\n"
                                + "If you cannot remember your password, please log in with \"g\" and ask for help\n"
                                + "in channel 4. Type \"tell 4 I've forgotten my password\". If that is not\n"
                                + "possible, please email: support@freechess.org\n\n"
                                + "\tIf you are not a registered player, enter guest or a unique ID.\n"
                                + "\t\t(If your return key does not work, use cntrl-J)\n\nlogin: ", userSession);
                        userSession.setCurrentState(SocketChannelUserSession.UserSessionState.LOGIN_NEED_USERNAME);
                        //userSession.disconnect();
                        return;
                    }
                }
            } catch (java.sql.SQLException e) {
                e.printStackTrace(System.err);
            }
        }

        boolean isLoggedIn = instance.isLoggedIn(name);
        if (isLoggedIn) {
            /* this code in this logic block should be commented out to support multiple-login. */
            userSession.send(name + " is already logged in - kicking them out.");

            UserSession sess = instance.getUserSession(name);
            sess.send("**** " + name + " has arrived - you can't both be logged in. ****");
            sess.disconnect();
            isLoggedIn = !isLoggedIn;
        }

        userSession.getUser().setUserName(name);
        userSession.getUser().setPlayerType(PlayerType.Human);
        userSession.getUser().setUserLevel(isGuest ? UserLevel.Guest : UserLevel.Player);
        userSession.getUser().setRegistered(!isGuest);
        userSession.getUser().setUserVars(new morphy.user.UserVars(userSession.getUser()));
        if (isGuest) {
            userSession.getUser().getUserVars().getVariables().put("rated", "0");
        }
        userSession.setCurrentState(SocketChannelUserSession.UserSessionState.LOGGED_IN);
        if (!isLoggedIn) {
            instance.addLoggedInUser(userSession);
        } else {
            // This code is used for multiple-login.
            /*SocketChannelUserSession sess = (SocketChannelUserSession) instance.getUserSession(name);
            sess.addUserOnMultipleLogins(userSession);
            userSession.addParentOnMultipleLogins(sess);*/
        }
        userSession.getUser().setDBID(instance.getDBID(name));

        boolean isHeadAdmin = false;

        if (!isGuest) {
            DatabaseConnection conn = DatabaseConnectionService.getInstance().getDBConnection();

            String query = "SELECT pl.`name`,pe.`value` FROM personallist pl INNER JOIN personallist_entry pe ON (pe.personallist_id = pl.id) WHERE pl.user_id = '"
                    + userSession.getUser().getDBID() + "'";
            java.sql.ResultSet rs = conn.executeQueryWithRS(query);
            try {
                while (rs.next()) {
                    PersonalList pl = PersonalList.valueOf(rs.getString(1));
                    String val = rs.getString(2);
                    userSession.getUser().getLists().get(pl).add(val);
                    if (pl == PersonalList.channel) {
                        int channelNum = Integer.parseInt(val);
                        Channel c = ChannelService.getInstance().getChannel(channelNum);
                        if (c != null) {
                            c.addListener(userSession);
                        }
                    }
                }
            } catch (SQLException e) {
                Morphy.getInstance().onError(e);
            }

            Map<PersonalList, Integer> map = new HashMap<PersonalList, Integer>();
            query = "SELECT `name`,`id` FROM `personallist` WHERE `user_id` = '" + userSession.getUser().getDBID()
                    + "'";
            rs = conn.executeQueryWithRS(query);
            try {
                while (rs.next()) {
                    map.put(PersonalList.valueOf(rs.getString(1)), rs.getInt(2));
                }
            } catch (SQLException e) {
                Morphy.getInstance().onError(e);
            }
            userSession.getUser().setPersonalListDBIDs(map);

            conn.executeQuery("UPDATE `users` SET `lastlogin` = CURRENT_TIMESTAMP, `ipaddress` = '"
                    + SocketUtils.getIpAddress(userSession.getChannel().socket()) + "' WHERE `username` = '" + name
                    + "'");
            ResultSet r = conn
                    .executeQueryWithRS("SELECT `adminLevel` FROM `users` WHERE `username` = '" + name + "'");
            try {
                if (r.next()) {
                    String level = r.getString(1);
                    UserLevel val = UserLevel.valueOf(level);
                    userSession.getUser().setUserLevel(val);
                    if (val == UserLevel.Admin || val == UserLevel.SuperAdmin || val == UserLevel.HeadAdmin) {
                        ServerListManagerService s = ServerListManagerService.getInstance();
                        s.getElements().get(s.getList("admin")).add(name);
                    }

                    if (val == UserLevel.HeadAdmin) {
                        isHeadAdmin = true;
                    }
                }
            } catch (SQLException e) {
                if (LOG.isErrorEnabled()) {
                    LOG.error("Unable to set user level from database for name \"" + name + "\"");
                    LOG.error(e);
                }
            }
        }

        StringBuilder loginMessage = new StringBuilder(200);
        loginMessage.append(
                formatMessage(userSession, "**** Starting FICS session as " + instance.getTags(name) + " ****\n"));
        if (isHeadAdmin)
            loginMessage.append("\n  ** LOGGED IN AS HEAD ADMIN **\n");
        loginMessage.append(ScreenService.getInstance().getScreen(Screen.SuccessfulLogin));
        userSession.send(loginMessage.toString());

        //         query = "SELECT DISTINCT u.username FROM `morphyics`.`personallist` pl INNER JOIN users u ON (pl.user_id = u.id) WHERE pl.`name` = 'notify'";
        //         rs = dbcs.getDBConnection().executeQueryWithRS(query);
        //         try {
        //            UserService us = UserService.getInstance();
        //            while(rs.next()) {
        //               String username = rs.getString(1);
        //               UserSession sess = us.getUserSession(username);
        //               sess.send("Notification: " + name + " has arrived.");
        //            }
        //         } catch(SQLException e) { Morphy.getInstance().onError(e); }

        UserSession[] sessions = UserService.getInstance().fetchAllUsersWithVariable("pin", "1");
        for (UserSession s : sessions) {
            UserLevel adminLevel = s.getUser().getUserLevel();

            if (adminLevel == UserLevel.Admin || adminLevel == UserLevel.SuperAdmin
                    || adminLevel == UserLevel.HeadAdmin) {
                s.send(String.format("[%s (%s: %s) has connected.]", userSession.getUser().getUserName(),
                        !isGuest ? "R" : "U", SocketUtils.getIpAddress(userSession.getChannel().socket())));
            } else {
                s.send(String.format("[%s has connected.]", userSession.getUser().getUserName()));
            }
        }

        DatabaseConnectionService dbcs = DatabaseConnectionService.getInstance();

        java.util.List<String> arrivalNotedBy = new java.util.ArrayList<String>(10);
        // this query gets all usernames with this player on their notify list.
        String query = "SELECT u.username FROM personallist pl INNER JOIN personallist_entry ple ON (pl.id = ple.personallist_id) INNER JOIN users u ON (u.id = pl.user_id) WHERE pl.`name` = 'notify' && ple.`value` LIKE '"
                + userSession.getUser().getUserName() + "';";
        ResultSet rs = dbcs.getDBConnection().executeQueryWithRS(query);
        try {
            UserService us = UserService.getInstance();
            while (rs.next()) {
                String username = rs.getString(1);
                UserSession sess = us.getUserSession(username);
                if (sess != null) {
                    UserVars uv = sess.getUser().getUserVars();
                    boolean highlight = uv.getVariables().get("highlight").equals("1");
                    if (sess != null && sess.isConnected()) {
                        sess.send("Notification: " + (highlight ? ((char) 27) + "[7m" : "") + name
                                + (highlight ? ((char) 27) + "[0m" : "") + " has arrived.");
                        arrivalNotedBy.add(sess.getUser().getUserName());
                    }
                }
            }
        } catch (SQLException e) {
            Morphy.getInstance().onError(e);
        }
        if (arrivalNotedBy.size() > 0) {
            userSession.send("Your arrival was noted by: " + MorphyStringUtils
                    .toDelimitedString(arrivalNotedBy.toArray(new String[arrivalNotedBy.size()]), " "));
        }

        query = "SELECT ple.`value` FROM personallist pl INNER JOIN personallist_entry ple ON (pl.id = ple.personallist_id) WHERE pl.user_id = "
                + userSession.getUser().getDBID() + " && pl.`name` = 'notify'"; // get this player's notify list
        rs = dbcs.getDBConnection().executeQueryWithRS(query);
        try {
            UserService us = UserService.getInstance();
            while (rs.next()) {
                String username = rs.getString(1);
                if (arrivalNotedBy.contains(username))
                    continue;
                UserSession sess = us.getUserSession(username);
                if (sess == null)
                    continue;
                UserVars uv = sess.getUser().getUserVars();
                boolean highlight = uv.getVariables().get("highlight").equals("1");
                if (sess != null && sess.isConnected())
                    sess.send("Notification: " + (highlight ? ((char) 27) + "[7m" : "") + name
                            + (highlight ? ((char) 27) + "[0m" : "")
                            + " has arrived and isn't on your notify list.");
            }
        } catch (SQLException e) {
            Morphy.getInstance().onError(e);
        }
        // Notification: ChannelBot has arrived and isn't on your notify list.
    }

    protected synchronized String readMessage(SocketChannel channel) {
        try {
            ByteBuffer buffer = ByteBuffer.allocate(maxCommunicationSizeBytes);
            int charsRead = -1;
            try {
                charsRead = channel.read(buffer);
            } catch (IOException cce) {
                if (channel.isOpen()) {
                    channel.close();
                    if (LOG.isInfoEnabled()) {
                        LOG.info("Closed channel " + channel);
                    }
                }
            }
            if (charsRead == -1) {
                return null;
            } else if (charsRead > 0) {
                buffer.flip();

                Charset charset = Charset.forName(Morphy.getInstance().getMorphyPreferences()
                        .getString(PreferenceKeys.SocketConnectionServiceCharEncoding));

                SocketChannelUserSession socketChannelUserSession = socketToSession.get(channel.socket());

                byte[] bytes = buffer.array();
                buffer.position(0);

                System.out.println("IN: " + new String(bytes).trim());
                if (looksLikeTimesealInit(bytes)) {
                    if (socketChannelUserSession.usingTimeseal == false) {
                        // First time?
                        socketChannelUserSession.usingTimeseal = true;
                        return MSG_TIMESEAL_OK;
                    }
                }

                if (socketChannelUserSession.usingTimeseal) {
                    /*
                     * Clients may pass multiple Timeseal-encoded messages at once.
                     * We need to parse each separated message to Timeseal decoder as necessary. 
                     */

                    byte[] bytesToDecode = Arrays.copyOfRange(bytes, 0, charsRead - 1 /* \n or 10 */);
                    byte[][] splitBytes = TimesealCoder.splitBytes(bytesToDecode, (byte) 10);

                    buffer = ByteBuffer.allocate(bytesToDecode.length);
                    buffer.position(0);
                    for (int i = 0; i < splitBytes.length; i++) {
                        byte[] splitBytesToDecode = splitBytes[i];
                        TimesealParseResult parseResult = timesealCoder.decode(splitBytesToDecode);
                        if (parseResult != null) {
                            System.out.println(parseResult.getTimestamp());
                            parseResult.setMessage(parseResult.getMessage() + "\n");
                            System.out.println(parseResult.getMessage());

                            buffer.put(parseResult.getMessage().getBytes(charset));
                        }
                    }
                    //buffer.position(0);
                    buffer.flip();
                }

                CharsetDecoder decoder = charset.newDecoder();
                CharBuffer charBuffer = decoder.decode(buffer);
                String message = charBuffer.toString();
                return message;
                //System.out.println(message);
                //return "";
            } else {
                return "";
            }
        } catch (Throwable t) {
            if (LOG.isErrorEnabled())
                LOG.error("Error reading SocketChannel " + channel.socket().getLocalAddress(), t);
            return null;
        }
    }

    private boolean looksLikeTimesealInit(byte[] bytes) {
        return Arrays.equals(Arrays.copyOfRange(bytes, 0, 8),
                new byte[] { -101, -128, 113, -128, -98, -128, -128, -98 })
                || Arrays.equals(Arrays.copyOfRange(bytes, 0, 8),
                        new byte[] { -124, -128, 113, -128, -97, -111, -128, -98 });
    }

    protected void sendWithoutPrompt(String message, SocketChannelUserSession session) {
        try {
            if (session.isConnected()) {
                ByteBuffer buffer = BufferUtils.createBuffer(formatMessage(session, message));
                session.getChannel().write(buffer);
            } else {
                if (LOG.isInfoEnabled()) {
                    LOG.info("Tried to send message to a logged off user " + session.getUser().getUserName() + " "
                            + message);
                }
                if (LOG.isInfoEnabled())
                    LOG.info("ession.disconnect(); called");
                session.disconnect();
            }
        } catch (Throwable t) {
            if (LOG.isErrorEnabled())
                LOG.error("Error sending message to user " + session.getUser().getUserName() + " " + message, t);
            session.disconnect();
        }
    }

    private synchronized void onNewChannel(SocketChannel channel) {
        if (LOG.isInfoEnabled()) {
            LOG.info("onNewChannel();");
        }

        try {
            SocketChannelUserSession session = new SocketChannelUserSession(new User(), channel);
            session.setCurrentState(SocketChannelUserSession.UserSessionState.LOGIN_NEED_USERNAME);
            socketToSession.put(channel.socket(), session);

            //         ByteBuffer buffer = BufferUtils.createBuffer(ScreenService
            //               .getInstance().getScreen(Screen.Login));
            //         channel.write(buffer);
            sendWithoutPrompt(ScreenService.getInstance().getScreen(Screen.Login), session);

            if (LOG.isInfoEnabled()) {
                LOG.info("Received socket connection " + channel.socket().getInetAddress());
            }
        } catch (Throwable t) {
            if (LOG.isErrorEnabled()) {
                LOG.error("Error writing to SocketChannel " + channel.socket().getInetAddress(), t);
            }

            disposeSocketChannel(channel);
        }
    }

    private synchronized void onNewInput(SocketChannel channel) {
        if (!channel.isOpen())
            return;

        try {
            if (channel.isConnected()) {
                SocketChannelUserSession session = socketToSession.get(channel.socket());

                if (session == null) {
                    if (LOG.isErrorEnabled()) {
                        LOG.error("Received a read on a socket not being managed. This is likely a bug.");
                    }

                    disposeSocketChannel(channel);
                } else {
                    synchronized (session.getInputBuffer()) {
                        String message = readMessage(channel);
                        if (message != null && message.equals(MSG_TIMESEAL_OK)) {
                            // Don't need to do anything. This was just the timeseal init string.
                        } else if (message == null && channel.isOpen()) {
                            session.disconnect();
                        } else if (message == null) {
                            session.disconnect();
                        } else if (message.length() > 0) {
                            /*if (!socketInputForCmd.containsKey(channel.socket())) {
                               socketInputForCmd.put(channel.socket(), new StringBuilder());
                            }
                            int c = (int)message.charAt(0);
                            if (c != 10 && c != 13) {
                               socketInputForCmd.get(channel.socket()).append(message);
                               //LOG.info(c);
                            } else {
                               message = socketInputForCmd.get(channel.socket()).toString();
                               socketInputForCmd.put(channel.socket(), new StringBuilder()); 
                               LOG.info("Read: "
                                     + session.getUser().getUserName() + " \""
                                     + message + "\"");
                            }
                            LOG.info(c + " " + socketInputForCmd.get(channel.socket()));*/

                            boolean expandAliases = true;
                            if (message.startsWith("$$")) {
                                message = message.substring(2);
                                expandAliases = false;
                            } else {
                                session.touchLastReceivedTime();
                                session.getUser().getUserVars().getVariables().put("busy", "");
                                expandAliases = true;
                            }

                            session.getInputBuffer().append(message);
                            if (session.getInputBuffer().indexOf("\n") != -1) {
                                LOG.info("Read: " + session.getUser().getUserName() + " \"" + message + "\"");
                            }
                            int carrageReturnIndex = -1;
                            while ((carrageReturnIndex = session.getInputBuffer().indexOf("\n")) != -1) {

                                String command = session.getInputBuffer().substring(0, carrageReturnIndex).trim();
                                session.getInputBuffer().delete(0, carrageReturnIndex + 1);

                                if (session
                                        .getCurrentState() == SocketChannelUserSession.UserSessionState.LOGIN_NEED_PASSWORD) {
                                    handlePasswordPromptText(session, command);
                                } else if (command.equals("") || command.equals("\n") || command.equals("\n\r")) {
                                    session.send("");
                                } else if (session
                                        .getCurrentState() == SocketChannelUserSession.UserSessionState.LOGIN_NEED_USERNAME) {
                                    handleLoginPromptText(session, command);
                                } else {
                                    if (expandAliases) {
                                        CommandService.getInstance().processCommandAndCheckAliases(command,
                                                session);
                                    } else {
                                        CommandService.getInstance().processCommand(command, session);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Throwable t) {
            if (LOG.isErrorEnabled()) {
                LOG.error("Error reading socket channel or processing command ", t);
            }

        }
    }
}