// Sample code file: Communications.java

// Warning: This code has been marked up for HTML

/*
   Copyright (c) 2000 Novell, Inc.  All Rights Reserved.

   THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. 
   USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT 
   ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK. 
   PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A 
   ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS 
   PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET, 
   DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S 
   PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S 
   CUSTOMERS WITH RESPECT TO THIS CODE. 
*/
 


package com.novell.Chat;

//Java imports
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.Vector;
import java.util.ResourceBundle;
import java.text.MessageFormat;
import javax.swing.JOptionPane;
import javax.swing.Timer;

/**
 * Handles all of the communications between both clients and servers.
 * This class implements its own communications protocol using the 
 * TCP/IP stack inorder to make the communication's more efficent.
 */
public class Communications implements ActionListener
{
    /**
     * The default buffer size to read in at a time.
     */
    public static final int BUFFER_SIZE = 500;
    
    /**
     * Error message code send through comError().
     * Sent when a timeout error occurs.
     */
    public static final int ERROR_TIMEOUT = 0;
    
    /**
     * Error message code send through comError().
     * Sent when a no communications error occurs.
     */
    public static final int ERROR_NO_COM = 1;
    
    /**
     * Error message code send through comError().
     * Sent when an IO error occurs.
     */
    public static final int ERROR_IO = 2;
    
    /**
     * The default timeout in seconds that is used when
     * waiting for a connections to be established.
     */
    public static final int TIMEOUT = 60;
    
    /**
     * A reference to 'this'.  Used with the sub classes.
     */
    Communications com;
    
    /**
     * Thread that montiors the input.
     */
    InputListener inputListener;
    
    /**
     * Thread that handles the sending of data to the output stream.
     */
    DataSender dataSender;
    
    /**
     * Thread that handles the reading in of data from the input stream.
     */
    DataReader dataReader;
    
    /**
     * The ComListener that will receive the events from this class.
     */
    ComListener listener;
    
    /**
     * The socket the connection is over.
     */
    Socket socket;
    
    /**
     * The stream that receives the input from the connection.
     */
    InputStream inputStream;
    
    /**
     * The stream that sends the output to the connection.
     */
    OutputStream outputStream;
    
    /**
     * Queue that holds all of the input that has yet to be processed.
     */
    Vector inputQueue = new Vector();
    
    /**
     * Queue that holds all of the output that is waiting to be sent.
     */
    Vector outputQueue = new Vector();
    
    /**
     * The name of the local user.
     */
    String localName;
    
    /**
     * The fullname of the local user.
     */
    String localFullName;
    
    /**
     * The IPAddress of the local user.
     */
    String localIPAddress;
    
    /**
     * The port of the local user.
     */
    int localPort;
    
    /**
     * The name of the remote user.
     */
    String remoteName;
    
    /**
     * The fullname of the remote user.
     */
    String remoteFullName;
    
    /**
     * The IPAddress of the remote user.
     */
    String remoteIPAddress;
    
    /**
     * The port of the remote user.
     */
    int remotePort;
    
    /** 
         * When this timer expires, it checks to see if a valid connection has been established.
         * If not, then the session is terminated.
         */
        Timer timeOut;
        
        /**
         * The color code to use with this user.
         */
        int colorCode = 0;
        
        /**
         * Used to hold the thread until the server shut down is complete.
         */
        boolean shutDownWait = false;
    
    /////////////////////////////////////////////////////////////
    //  Constants used to define the communication's protocol. //
    /////////////////////////////////////////////////////////////
        
    /** 
     * Char used to find the beginning of a new tag.
     */
    public static final String CODE_STARTER = "{";  
    
    /**
     * Used to seperate various values found in the same message.
     */
    public static final String CODE_SEPERATOR = "|";
    
    /**
     * Proceeds the user's message.  This should always be the last
     * tag in data string so that it is impossible for the user to
     * enter data that would confuse the parser.
     */
    public static final String CODE_MSG = "{MSG}";
    
    /**
     * This should be the first tag in almost all messages.
     * The user's name should follow.  This identifies the
     * sender of the message.
     */
    public static final String CODE_USER = "{USER}";
    
    /** 
     * This is sent when this user is identifying himself
     * to the person he is connected to.
     * This is sent with this user's fullname following.
     */
    public static final String CODE_DN = "{DN}";    
    
    /**
     * Sent to accept a chat request.  No data need follow.
     */
    public static final String CODE_ACCEPT = "{ACC}";
    
    /**
     * Sent to reject a chat request.  No data need follow.
     */
    public static final String CODE_REJECT = "{REJ}";
    
    /**
     * Sent when a user disconnects.  Informs others that
     * he is no longer connected.  No data need follow.
     */
    public static final String CODE_DISCONNECT = "{DIS}";
    
    /**
     * Sent when a user is either added or removed from a chat room.
     */
    public static final String CODE_UPDATE = "{UP}";
    
    /**
     * Sent when the user is requesting a connection.
     * The user's fullname should follow.
     */
    public static final String CODE_REQUEST = "{CON}";
    
    /**
     * Sent when the user is requesting that the person he is
     * connected when identify himself.
     */
    public static final String CODE_ID = "{ID}";
    
    /**
     * Sent to request a server transfer.
     */
    public static final String CODE_TRAN_REQ = "{TRQ}";
    
    /**
     * Sent to all clients to command a server transfer.
     */
    public static final String CODE_TRAN_COM = "{TCD}";
    
    /**
     * Sent in response to a server Transfer request.
     */
    public static final String CODE_TRAN_RESP = "{TRS}";
    
    /**
     * Sent by a client to reconnect to a server after a server transfer.
     */
    public static final String CODE_RECONNECT = "{REC}";
    
    /**
     * Sent by a server to accept the reconnection.
     */
    public static final String CODE_REC_ACC = "{RCA}";
    
    /**
     * Sent to force a server shut down.
     */
    public static final String CODE_SHUTDOWN = "{SDN}";
    
    /**
     * Sent when the forced shut down is complete.
     */
    public static final String CODE_SHUTDOWN_DONE = "{SDD}";
    
    /**
     * Sent to force a client to disconnect.
     */
    public static final String CODE_FORCE_DIS = "{FDS}";
    
            
    
    /**
     * Constructor
     *
     * @param listener The ComListener that will receive the communication's events.
     * @param socket The socket it is connected at.
     * @param localName The name of this local user.
     * @param localFullName The fullname of this local user.
     */
    public Communications(ComListener listener, Socket socket, String localName, String localFullName)
    {        
        //Keeps a reference to this class for the sub class can reference it too.
        com = this;
        
        this.listener = listener;
        this.localName = localName;
        this.localFullName = localFullName;
        
        if(socket != null)
        {          
            try
            {
                timeOut = new Timer(TIMEOUT * 1000, this);
                
                //Get the communication streams
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();     
                
                //Get the localuser information
                localPort = socket.getLocalPort();
                localIPAddress = socket.getLocalAddress().toString();
                int index = localIPAddress.indexOf('/');
                    if(index != -1)
                        localIPAddress = localIPAddress.substring(index + 1, localIPAddress.length());
                        
                //Get the remote user information
                remotePort = socket.getPort();
                remoteIPAddress = socket.getInetAddress().toString();
                index = remoteIPAddress.indexOf('/');
                    if(index != -1)
                        remoteIPAddress = remoteIPAddress.substring(index + 1, remoteIPAddress.length());
                        
                //Start the threads if the connection is valid                                        
                if(inputStream != null && outputStream != null)
                {
                    inputListener = new InputListener();
                    inputListener.start();   
                    
                    dataSender = new DataSender();
                    dataSender.start();
                    
                    dataReader = new DataReader();
                    dataReader.start();
                    
                    return;
                }
            }
            catch(IOException e)
            {
                listener.comError(this, ERROR_IO, "Communications() - " + e.getMessage());
            }
        }
        
        listener.comError(this, ERROR_NO_COM, Chat.chatRes.getString("Com Error-No Com"));
    }
    
    /**
     * Tests to see if a connection exists by testing to see that all
     * three vital threads are running.
     *
     * @return True if connected.
     */
    public boolean isConnected()
    {
        if(dataSender.isAlive() && dataReader.isAlive() && inputListener.isAlive())
            return true;
       
        return false;
    }
        
    /**
     * Establishes communications by sending the ID message.
     *
     * @return True if the start was successfull.
     */
    public boolean estabCom()
    {
        if(dataSender.isAlive())
        {
            send(CODE_ID);
            timeOut.start();
            return true;
        }
        
        return false;
    }
    
    /**
     * Re-establishes communications with a server after a server transfer.
     *
     * @param The old key to the client that is reconnecting.
     * @return True if successfull.
     */
    public boolean reEstabCom(String oldKey)
    {
        if(dataSender.isAlive())
        {
            send(CODE_RECONNECT + localFullName + CODE_SEPERATOR + oldKey);
            timeOut.start();
            return true;
        }
        
        return false;
    }
    
    /**
     * Sends the message to force the shut down of the server.
     *
     * @return True if successfull.
     */
    public boolean forceShutDown()
    {
        if(dataSender.isAlive())
        {
            shutDownWait = true;
            
            send(CODE_SHUTDOWN);
                        
            //Waits until a responce is received from the shut down message.          
            while(shutDownWait);
                        
            close();
            
            return true;
        }
        
        return false;
        
    }
    
    /**
     * Sends a message to force the disconnection of a client.
     *
     * @param key The client to disconnect.
     * @return True if successfull.
     */
    public boolean forceDisconnect(String key)
    {
        if(dataSender.isAlive())
        {
            send(CODE_FORCE_DIS + key);
            close();
            return true;
        }
        
        return false;
    }
    
    /**
     * Sends an update message.
     */
    public void sendUpdate()
    {
        send(CODE_UPDATE);   
    }
    
    /**
     * Gets the key associated with this connection.
     *
     * @return A string in the form of IP:Port
     */
    public String getKey()
    {
        return remoteIPAddress + ":" + remotePort;   
    }
    
    /**
     * Gets the key associated with this connection.
     * ChatClient version.
     *
     * @return A string in the form of IP:Port
     */
    public String getClientKey()
    {
        return localIPAddress + ":" + localPort;   
    }
    
    /**
     * Ends the connection.
     */
    public void disconnect()
    {
        //Notifies the remote user that he is disconnecting.
        send(CODE_DISCONNECT);
        
        //Notifies the listener that it is disconnecting itself.
        listener.disconnected(this);
        
        //Closes the connection.
        close();
    }
    
    /**
     * Closes the connections and stops all threads.
     */
    void close()
    {
        //stop the timeOut timer if running.
        timeOut.stop();                
        
        //We'll put these actions in a thread because they could take a second
        //to complete.
        Thread thread = new Thread(){
            public void run()
            {                
                //Stop listening for input.
                inputListener.stop();    
                
                //Wait for the outputQueue to be empty and then stop the thread.
                while(!outputQueue.isEmpty());
                dataSender.stop();
                                                   
                //Wait for the inputQueue to be empty and then stop the thread.
                while(!inputQueue.isEmpty());
                dataReader.stop();        
                
                try
                {
                    //Close the streams and the socket.
                    inputStream.close();
                    outputStream.close();
                    if(socket != null)
                        socket.close();                    
                }
                catch(IOException e)
                {
                    listener.comError(com, ERROR_IO, Chat.chatRes.getString("Com Error-Socket"));
                }
            }       
        };
        
        thread.start();        
    }
    
    ////////////////////////////////////////////////////////
    //   Getter methods for the user information.         //
    ////////////////////////////////////////////////////////
    public String getLocalName()
    {
        return localName;
    }    
    public String getLocalFullName()
    {
        return localFullName;
    }    
    public String getLocalIPAddress()
    {
        return localIPAddress;
    }    
    public int getLocalPort()
    {
        return localPort;
    }    
    public String getRemoteName()
    {
        //Pulls the remoteName from the remoteFullName.
        if(remoteName == null && remoteFullName != null)
        {
            int index1 = remoteFullName.indexOf('/');
            if(index1 == -1)
                index1 = 0;
            
            int index2 = remoteFullName.indexOf('.');
            if(index2 == -1)
                index2 = remoteFullName.length();
                
            remoteName = remoteFullName.substring(index1 + 1, index2);                        
        }
        return remoteName;
    }    
    public String getRemoteFullName()
    {
        return remoteFullName;
    }    
    public String getRemoteIPAddress()
    {
        return remoteIPAddress;
    }    
    public int getRemotePort()
    {
        return remotePort;
    }
    public int getColorCode()
    {
        return colorCode;
    }    
    public void setColorCode(int colorCode)
    {
        this.colorCode = colorCode;
    }
    
    /**
     * Place output on the queue.
     *
     * @param str The string to place on the queue.
     */
    void send(String str)
    {
        outputQueue.addElement(str);
    }
    
    /** 
     * Sends the message from the given user.
     *
     * @param nameColor The color to print the name in.
     * @param name The user's name who sent it.
     * @param message The message to send.
     */
    public void sendMessage(int nameColor, String name, String message)
    {
        send(CODE_MSG + nameColor + CODE_SEPERATOR + name + CODE_SEPERATOR + message);
    }
    
    /** 
     * Sends the message from the given user.
     *
     * @param name The user's name who sent it.
     * @param message The message to send.
     */
    public void sendMessage(String name, String message)
    {
        send(CODE_MSG + colorCode + CODE_SEPERATOR + name + CODE_SEPERATOR + message);
    }
    
    /**
     * Sends the request to transfer the control of the server to this client.
     */
    public void sendTransferMessage(int startColor)
    {
        send(CODE_TRAN_REQ + startColor);   
    }     
    
    /**
     * Sends the command to transfer the control of the server to another server.
     */
    public void sendTransferCommand(String roomFullName)
    {
        send(CODE_TRAN_COM + roomFullName);   
    }  
    
    /**
         * Implements the ActionListener Interface.
         *
         * Triggered when the timeOut timer expires.
         *
         * @param e The ActionEvent
         */
        public void actionPerformed(ActionEvent e)
        {
            if(!isConnected())
            {
                timeOut.stop();
                listener.comError(this, ERROR_TIMEOUT, Chat.chatRes.getString("Com Error-Timeout"));
                disconnect();                  
            }
        }
    
    /**
     * This thread waits for data to be placed in the inputQueue and then
     * decodes the data received.
     */
    class DataReader extends Thread
    {                
        public void run()
        {
            //This loop will continue until the thread is interrupted
                    while(!isInterrupted())
                    {
                        //Waits for input to become available.
                while(inputQueue.isEmpty())
                    yield();  //Allows other threads to act since this one won't be.
                
                //Remove it from the queue
                String dataString = (String)inputQueue.elementAt(0);
                inputQueue.removeElementAt(0);
                                
                //Decode the data.
                decodeData(dataString);
            }
        }
        
        /**
         * Parses the data and responds appropriately.
         *
         * @param data The data to parse and decode.
         */
        void decodeData(String data)
        {
            String str = null;   
                int index;
            
            //This is what is sent when a user sends a message.
            if(data.startsWith(CODE_MSG))
            {
                if(!listener.echoData(data))
                {               
                        index = data.indexOf(CODE_SEPERATOR);                   
                        if(index != -1)
                        {                       
                            //Sets this variable to the user who sent the data.
                            int color = (new Integer(data.substring(CODE_MSG.length(), index))).intValue();
                        
                            str = data.substring(index + 1);   
                            index = str.indexOf(CODE_SEPERATOR);                        
                            if(index != -1)
                            {
                                //Sets this variable to the user who sent the data.
                                String userName = str.substring(0, index);
                                str = str.substring(index + 1);      
                                //Raise the event on the listener.
                                listener.messageReceived(color, userName, str);                 
                            }
                        }
                    }
            }
            //Request to identify yourself
            else if(data.startsWith(CODE_ID))
            {
                send(CODE_DN + localFullName);
            }
            //Identity returned after an ID is sent
            else if(data.startsWith(CODE_DN))
            {
                //There are communications, so the timer can stop.
                timeOut.stop();
                    
                    //This code is followed by the remote user's fullname.
                    remoteFullName = data.substring(CODE_DN.length());
                    
                    //It now verifies that the connection is with who it things it is.
                    if(listener.verifyConnection(remoteFullName, remoteIPAddress))
                        send(CODE_REQUEST + localFullName); //If so, it requests communications
                    else        
                        disconnect();  //If not, it disconnects.
            }
            //Received when a client is requesting to establish communications.
            else if(data.startsWith(CODE_REQUEST))
            {
                listener.comStatus(com, Chat.chatRes.getString("Com Status-Con Request"));
                    
                    //The remote user's full name will follow this code.
                    remoteFullName = data.substring(CODE_REQUEST.length());
                    
                    //Verifies that the request is coming from who the request said
                    //he was.
                    if(listener.verifyConnection(remoteFullName, remoteIPAddress))
                    {
                        //Allows the listener to decide if it will accept or
                        //reject the request.
                        int color = listener.acceptConnection(com);
                        if(color != -1)
                        {                           
                            send(CODE_ACCEPT + color);
                            listener.connectionEstablished(com);
                        }
                        else                
                        {
                            //If it rejects, then it will close down the connection.
                            send(CODE_REJECT);
                            close();
                        }
                    }
                    else                    
                    {
                        //If the user doesn't verify, then it will close down the connection.
                        send(CODE_REJECT);
                        close();
                    }
            }
            //Sent when the remote user accepts the request to establish communications.
            else if(data.startsWith(CODE_ACCEPT))
            {
                str = data.substring(CODE_ACCEPT.length());                 
                        
                colorCode = (new Integer(str)).intValue();                      
                
                listener.comStatus(com, Chat.chatRes.getString("Com Status-Request Acc"));
                listener.connectionEstablished(com);                    
            }
            //Sent when the remote user rejects the request to establish communications.
            else if(data.startsWith(CODE_REJECT))
            {
                listener.comStatus(com, Chat.chatRes.getString("Com Status-Request Rej"));
                JOptionPane.showMessageDialog(Chat.getInstance().getShell().getShellFrame(), MessageFormat.format(Chat.chatRes.getString("Not Interested"), new Object[]{getRemoteName()}), Chat.chatRes.getString("Chat"), JOptionPane.INFORMATION_MESSAGE);
                close();
            }
            //Sent when the remote user disconnects.
            else if(data.startsWith(CODE_DISCONNECT))
                {
                    listener.disconnected(com);
                    close();
                }
                //Sent when changes have occurred in the chat room object.
                else if(data.startsWith(CODE_UPDATE))
                {
                    listener.connectionUpdate(com);
                }           
                //Received when this client is being requested to act as server
                //for the chat room.
                else if(data.startsWith(CODE_TRAN_REQ))
                {
                    str = data.substring(CODE_TRAN_REQ.length());                
                        
                if(listener.serverTransferRequest((new Integer(str)).intValue()))
                    send(CODE_TRAN_RESP + "Okay");
                else
                    send(CODE_TRAN_RESP);  //Reject
                }
                //Received when the new server responds to the transfer request.
                else if(data.startsWith(CODE_TRAN_RESP))
                {
                    str = data.substring(CODE_TRAN_RESP.length());
                    
                    if(str.length() > 0)
                        listener.serverTransferResponse(true);
                    else
                        listener.serverTransferResponse(false);             
                }
                //Received when this client is requested to change chat room servers.
                else if(data.startsWith(CODE_TRAN_COM))
                {                                 
                    str = data.substring(CODE_TRAN_COM.length());
                    
                    listener.changeServer(str);
                }               
                //Received when a client is requesting to re-establish communications.
            else if(data.startsWith(CODE_RECONNECT))
            {
                listener.comStatus(com, Chat.chatRes.getString("Com Status-Got Request"));
                
                str = data.substring(CODE_RECONNECT.length());
                
                //The remote user's full name will follow this code.
                remoteFullName = str.substring(0, str.indexOf(CODE_SEPERATOR));
                String oldKey = str.substring(str.indexOf(CODE_SEPERATOR) + 1);     
                
                    //Verifies that the request is coming from who the requester said
                    //he was.
                    if(listener.verifyConnection(remoteFullName, remoteIPAddress))
                    {
                            send(CODE_REC_ACC + localFullName);
                            listener.reConnectionEstablished(com, oldKey);
                    }
                    else
                    {
                        //If it rejects, then it will close down the connection.
                        send(CODE_REJECT);
                        close();
                    }
            }
            //Received when a reconnection attempt is accepted.
            else if(data.startsWith(CODE_REC_ACC))
            {
                //There are communications, so the timer can stop.
                timeOut.stop();
                
                //This code is followed by the remote user's fullname.
                remoteFullName = data.substring(CODE_REC_ACC.length());                         
                    
                    //It now verifies that the connection is with who it things it is.
                    if(listener.verifyConnection(remoteFullName, remoteIPAddress))
                        listener.reConnectionEstablished(com, null);   
                    else        
                        disconnect();  //If not, it disconnects.
            }
            //Received when this server is forced to shut down.
            else if(data.startsWith(CODE_SHUTDOWN))
            {
                String owner = listener.getOwnerName();
                
                if(owner != null)
                {
                    //Verifies that the request is coming from who the requester said
                        //he was.
                        if(listener.verifyConnection(owner, remoteIPAddress))
                        {
                            listener.disconnect();
                            
                            send(CODE_SHUTDOWN_DONE);                   
                            close();
                            listener.close();
                            
                            return;
                        }
                    }
                    send(CODE_SHUTDOWN_DONE);                   
                    close();                                
            }
            //Received when this server is asked to force a client to
            //disconnect.
            else if(data.startsWith(CODE_FORCE_DIS))
            {
                str = data.substring(CODE_FORCE_DIS.length());
                
                String owner = listener.getOwnerName();
                
                if(owner != null)
                {
                    //Verifies that the request is coming from who the requester said
                        //he was.
                        if(listener.verifyConnection(owner, remoteIPAddress))
                            listener.disconnect(str);
                    }
                        
                    close();
            }
            //Received when a forced shut down is complete.
            else if(data.startsWith(CODE_SHUTDOWN_DONE))
            {
                shutDownWait = false;
            }               
        }
    }
    
    /**
     * This thread waits for data to appear in the outputQueue and then
     * sends it to the remote user.
     */
    class DataSender extends Thread
    {
        public void run()
        {
            //This loop will continue until either the thread is interrupted.
                    while(!isInterrupted())
                    {
                        //Waits for output to become available.
                while(outputQueue.isEmpty())
                    yield();  //Allows other threads to act since this one won't be.
                
                //Remove the data from the queue
                String dataString = (String)outputQueue.elementAt(0);
                outputQueue.removeElementAt(0);
                byte[] data = dataString.getBytes();
                                               
                try 
                    {                    
                                //Writing the message to the output stream and sends it to the server.
                                outputStream.write(data);//, 0, data.length);
                        } 
                        catch (IOException e) 
                        { 
                            //This occurs when the outputStream becomes bad, therefore it will disconnect.
                            listener.comError(com, ERROR_IO, "DataSender.run() - " + e.getMessage());               
                            disconnect();                           
                            break;
                        }
            }
        }
        
    }
    
    /**
     * This thread waits for data to appear on the input stream.  When
     * it does, it places that data on the inputQueue so that it can be
     * processed.
     */
    class InputListener extends Thread
    {        
        public void run()
        {
            byte[] buffer = new byte[BUFFER_SIZE];
                
            int offSet = 0;
                    int length = -1;
            
            try
                    {            
                //This loop will continue until either the thread is interrupted
                        while(!isInterrupted())
                        {                                                                      
                                //Waits until data is available
                                    while(inputStream.available() == 0)
                                        yield();  //Allows other threads to act since this one won't be.
                                                                
                                    buffer = new byte[BUFFER_SIZE];
                            String dataString = new String();
                                
                                    //Put the input into the buffer
                                    do{
                                        offSet = 0;
                                        length = inputStream.read(buffer, offSet, buffer.length);
                                        offSet += BUFFER_SIZE;
                                        
                                        if(length > 0)
                                            dataString += new String(buffer, 0, length);
                                        
                                    }while(length == BUFFER_SIZE);
                                
                                    //If the length is < 0, then the stream was lost meaning that the connection
                                    //was lost.
                                    if(length < 0) 
                                    {
                                        disconnect();
                                        break;
                                    }
                                
                                //Puts the data in the queue.
                                    if(dataString.length() > 0)
                                    {
                                        int index1 = 0;
                                        int index2 = dataString.indexOf(CODE_STARTER, index1 + 1);
                                        
                                        if(index2 == -1)
                                            inputQueue.addElement(dataString);
                                        else
                                        {
                                            //Makes sure two messages weren't doubled up.
                                            while(index2 != -1) 
                                            {
                                                String str = dataString.substring(index1, index2);
                                                inputQueue.addElement(str);
                                                index1 = index2;
                                                index2 = dataString.indexOf(CODE_STARTER, index1 + 1);
                                            }
                                        }
                                    }
                            }
                    } 
                    catch(IOException e)
                    {
                        listener.comError(com, ERROR_IO, "InputListener.run() - " + e.getMessage());
                        disconnect();
                    }         
            }       
    }
}