/// <summary>
        /// Event called when a complete message has been recieved
        /// </summary>
        /// <param name="Message"></param>
        private void Stream_DataReceived(string message)
        {
            // Read client message, and parse it into key value pairs
            string[] recieved = message.TrimStart('\\').Split('\\');
            switch (recieved[0])
            {
            case "newuser":
                CreateNewUser(ConvertToKeyValue(recieved));
                break;

            case "login":
                ProcessLogin(ConvertToKeyValue(recieved));
                break;

            case "getprofile":
                SendProfile();
                break;

            case "updatepro":
                UpdateUser(ConvertToKeyValue(recieved));
                break;

            case "logout":
                Disconnect(0);
                break;

            default:
                Stream.SendAsync(@"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                GpcmServer.Log("NOTICE: [GpcmClient.Stream_DataReceived] Unkown Message Passed: {0}", message);
                break;
            }
        }
        /// <summary>
        /// Whenever the "newuser" command is recieved, this method is called to
        /// add the new users information into the database
        /// </summary>
        /// <param name="Recv">Array of parms sent by the server</param>
        private void CreateNewUser(Dictionary <string, string> Recv)
        {
            // Make sure the user doesnt exist already
            try
            {
                using (GamespyDatabase Database = new GamespyDatabase())
                {
                    // Check to see if user exists
                    if (Database.UserExists(Recv["nick"]))
                    {
                        Stream.SendAsync(@"\error\\err\516\fatal\\errmsg\This account name is already in use!\id\1\final\");
                        Disconnect(5);
                        return;
                    }

                    // We need to decode the Gamespy specific encoding for the password
                    string Password = GamespyUtils.DecodePassword(Recv["passwordenc"]);
                    string Cc       = (RemoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
                        ? Ip2nation.GetCountryCode(RemoteEndPoint.Address)
                        : Program.Config.ASP_LocalIpCountryCode;

                    // Attempt to create account. If Pid is 0, then we couldnt create the account
                    if ((PlayerId = Database.CreateUser(Recv["nick"], Password, Recv["email"], Cc)) == 0)
                    {
                        Stream.SendAsync(@"\error\\err\516\fatal\\errmsg\Error creating account!\id\1\final\");
                        Disconnect(6);
                        return;
                    }

                    Stream.SendAsync(@"\nur\\userid\{0}\profileid\{0}\id\1\final\", PlayerId);
                }
            }
            catch (Exception e)
            {
                // Check for invalid query params
                if (e is KeyNotFoundException)
                {
                    Stream.SendAsync(@"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                }
                else
                {
                    Stream.SendAsync(@"\error\\err\516\fatal\\errmsg\Error creating account!\id\1\final\");
                    GpcmServer.Log("ERROR: [Gpcm.CreateNewUser] An error occured while trying to create a new User account :: " + e.Message);
                }

                Disconnect(7);
                return;
            }
        }
        /// <summary>
        /// Logs the client out of the game client, and closes the stream
        /// </summary>
        /// <param name="code">
        /// The disconnect code. If set to 9, the OnDisconect event will not be called, the database
        /// will not be updated to reset everyone's session code, and the EventArgs objects will NOT
        /// be returned to the IO pool. You should only set to 9 for a planned server shutdown.
        /// </param>
        /// <remarks>
        ///   Codes:
        ///     0 => Client sends the "logout" command
        ///     1 => The login timer elapsed and the client wasnt logged in or this object was disposed, forcefully disconnected
        ///     2 => Invalid login query, or username was incorrect
        ///     3 => Incorrect Password
        ///     4 => An error occured while trying to login the client (could be database related)
        ///     5 => Cant create account, username exists already
        ///     6 => Error Creating new account in database
        ///     7 => Invalid query for account creation, or an exception was thrown while trying to create account
        ///     8 => Remote Connection closed the Stream or was un-readchable
        ///     9 => Forced server shutdown [No events called, database sessions are not updated, and EventArgs are disposed]
        /// </remarks>
        public void Disconnect(int code)
        {
            // Make sure we arent disposed
            if (Disposed)
            {
                return;
            }

            // Update database session
            if (Status == LoginStatus.Completed && code < 9)
            {
                try
                {
                    using (GamespyDatabase Database = new GamespyDatabase())
                        Database.Execute("UPDATE accounts SET session=0 WHERE id=" + PlayerId);
                }
                catch
                {
                    // We could be shutting this server down because of DB connection issues, don't do anything here.
                }
            }

            // Unregister for stream events and close the connection
            Stream.OnDisconnect -= Stream_OnDisconnect;
            Stream.DataReceived -= Stream_DataReceived;
            Stream.Close(code == 9);

            // Set status and log
            if (code == 1 && Status == LoginStatus.Processing)
            {
                GpcmServer.Log("Login Timeout:  {0} - {1} - {2}", PlayerNick, PlayerId, RemoteEndPoint);
            }
            else if (Status != LoginStatus.Disconnected)
            {
                GpcmServer.Log("Client Logout:  {0} - {1} - {2}, Code={3}", PlayerNick, PlayerId, RemoteEndPoint, code);
            }

            // Preapare to be unloaded from memory
            Status   = LoginStatus.Disconnected;
            Disposed = true;

            // Call disconnect event
            if (OnDisconnect != null)
            {
                OnDisconnect(this);
            }
        }
        /// <summary>
        /// Starts the Login Server listeners, and begins accepting new connections
        /// </summary>
        public static void Start()
        {
            // Make sure we arent already running!
            if (isRunning)
                return;

            // Start the DB Connection
            try {
                Database = new GamespyDatabase();
            }
            catch (Exception E) {
                Notify.Show("Failed to Start Login Server!", E.Message, AlertType.Warning);
                throw E;
            }

            // Bind gpcm server on port 29900
            try {
                CmServer = new GpcmServer();
            }
            catch (Exception E) {
                Notify.Show(
                    "Failed to Start Login Server!",
                    "Error binding to port 29900: " + Environment.NewLine + E.Message,
                    AlertType.Warning
                );
                throw E;
            }

            // Bind gpsp server on port 29901
            try {
                SpServer = new GpspServer();
            }
            catch (Exception E) {
                Notify.Show(
                    "Failed to Start Login Server!",
                    "Error binding to port 29901: " + Environment.NewLine + E.Message,
                    AlertType.Warning
                );
                throw E;
            }

            // Let the client know we are ready for connections
            isRunning = true;
            OnStart();
        }
        /// <summary>
        /// Starts the Login Server listeners, and begins accepting new connections
        /// </summary>
        public static void Start()
        {
            // Make sure we arent already running!
            if (bIsRunning)
            {
                return;
            }

            // Start the DB Connection
            using (GamespyDatabase Database = new GamespyDatabase())
            {
                // First, make sure our account table exists
                if (!Database.TablesExist)
                {
                    string message = "In order to use the Gamespy Emulation feature of this program, we need to setup a database. "
                                     + "You may choose to do this later by clicking \"Cancel\". Would you like to setup the database now?";
                    DialogResult R = MessageBox.Show(message, "Gamespy Database Setup", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (R == DialogResult.Yes)
                    {
                        SetupManager.ShowDatabaseSetupForm(DatabaseMode.Gamespy, MainForm.Instance);
                    }

                    // Call the stoOnShutdown event to Re-enable the main forms buttons
                    Stopped();
                    return;
                }
                else if (Database.NeedsUpdated)
                {
                    // We cannot run an outdated database
                    DialogResult R = MessageBox.Show(
                        String.Format(
                            "The Gamespy database tables needs to be updated to version {0} before using this feature. Would you like to do this now?",
                            GamespyDatabase.LatestVersion
                            ) + Environment.NewLine.Repeat(1) +
                        "NOTE: You should backup your gamespy account table if you are unsure as this update cannot be undone!",
                        "Gamespy Database Update", MessageBoxButtons.YesNo, MessageBoxIcon.Question
                        );

                    // If the user doesnt migrate the database tables, quit
                    if (R != DialogResult.Yes)
                    {
                        // Call the stoOnShutdown event to Re-enable the main forms buttons
                        Stopped();
                        return;
                    }

                    // Do table migrations
                    Database.MigrateTables();
                }
            }

            // Bind gpcm server on port 29900
            int port = 29900;

            // Setup the DebugLog
            DebugLog.LoggingEnabled = Program.Config.GamespyServerDebug;
            if (Program.Config.GamespyServerDebug)
            {
                DebugLog.ClearLog();
            }

            try
            {
                // Begin logging
                DebugLog.Write("=== Gamespy Emulator Initializing ===");
                DebugLog.Write("Starting Client Manager");

                // Start the client manager
                ClientManager = new GpcmServer();

                // Begin logging
                DebugLog.Write("Bound to TCP port: " + port);
                DebugLog.Write("Starting Account Service Provider");

                // Start search provider server
                port++;
                SearchProvider = new GpspServer();

                // Begin logging
                DebugLog.Write("Bound to TCP port: " + port);
                DebugLog.Write("Starting Master Server");

                // Start then Master Server
                MasterServer = new MasterServer(ref port, DebugLog);

                // Start CDKey Server
                port = 29910;
                DebugLog.Write("Starting Cdkey Server");
                CDKeyServer = new CDKeyServer(DebugLog);

                // Begin logging
                DebugLog.Write("=== Gamespy Emulator Initialized ===");
            }
            catch (Exception E)
            {
                Notify.Show(
                    "Failed to Start Gamespy Servers!",
                    "Error binding to port " + port + ": " + Environment.NewLine + E.Message,
                    AlertType.Warning
                    );

                // Append log
                if (DebugLog != null)
                {
                    DebugLog.Write("=== Failed to Start Emulator Servers! ===");
                    DebugLog.Write("Error binding to port " + port + ": " + E.Message);
                }

                // Shutdown all started servers
                if (ClientManager != null && ClientManager.IsListening)
                {
                    ClientManager.Shutdown();
                }
                if (SearchProvider != null && SearchProvider.IsListening)
                {
                    SearchProvider.Shutdown();
                }
                if (MasterServer != null && MasterServer.IsRunning)
                {
                    MasterServer.Shutdown();
                }
                // Cdkey server must have throwm the exception at this point, since it starts last

                // Throw excpetion to parent
                throw;
            }

            // Let the client know we are ready for connections
            bIsRunning = true;
            Started();
        }
        /// <summary>
        /// This method verifies the login information sent by
        /// the client, and returns encrypted data for the client
        /// to verify as well
        /// </summary>
        public void ProcessLogin(Dictionary <string, string> Recv)
        {
            // Make sure we have all the required data to process this login
            if (!Recv.ContainsKey("uniquenick") || !Recv.ContainsKey("challenge") || !Recv.ContainsKey("response"))
            {
                Stream.SendAsync(@"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                Disconnect(2);
                return;
            }

            // Warp this in a try/catch, incase database is offline or something
            try
            {
                using (GamespyDatabase Conn = new GamespyDatabase())
                {
                    // Try and fetch the user from the database
                    Dictionary <string, object> User = Conn.GetUser(Recv["uniquenick"]);
                    if (User == null)
                    {
                        Stream.SendAsync(@"\error\\err\265\fatal\\errmsg\The uniquenick provided is incorrect!\id\1\final\");
                        Disconnect(2);
                        return;
                    }

                    // Set player variables
                    PlayerId          = Int32.Parse(User["id"].ToString());
                    PlayerNick        = Recv["uniquenick"];
                    PlayerEmail       = User["email"].ToString();
                    PlayerCountryCode = User["country"].ToString();
                    PasswordHash      = User["password"].ToString();

                    // Use the GenerateProof method to compare with the "response" value. This validates the given password
                    if (Recv["response"] == GenerateProof(Recv["challenge"], ServerChallengeKey))
                    {
                        // Password is correct, Create session key and respond
                        SessionKey = Crc.ComputeChecksum(PlayerNick);
                        Stream.SendAsync(
                            @"\lc\2\sesskey\{0}\proof\{1}\userid\{2}\profileid\{2}\uniquenick\{3}\lt\{4}__\id\1\final\",
                            SessionKey,
                            GenerateProof(ServerChallengeKey, Recv["challenge"]), // Do this again, Params are reversed!
                            PlayerId,
                            PlayerNick,
                            GenerateRandomString(22) // Generate LT whatever that is (some sort of random string, 22 chars long)
                            );

                        // Log, Update database, and call event
                        GpcmServer.Log("Client Login:   {0} - {1} - {2}", PlayerNick, PlayerId, RemoteEndPoint);
                        Conn.Execute("UPDATE accounts SET lastip=@P0, session=@P1 WHERE id=@P2", RemoteEndPoint.Address, SessionKey, PlayerId);

                        // Update status last, and call success login
                        Status = LoginStatus.Completed;
                        if (OnSuccessfulLogin != null)
                        {
                            OnSuccessfulLogin(this);
                        }
                    }
                    else
                    {
                        // The proof string failed, so the password provided was incorrect
                        GpcmServer.Log("Failed Login Attempt: {0} - {1} - {2}", PlayerNick, PlayerId, RemoteEndPoint);
                        Stream.SendAsync(@"\error\\err\260\fatal\\errmsg\The password provided is incorrect.\id\1\final\");
                        Disconnect(3);
                    }
                }
            }
            catch
            {
                Disconnect(4);
                return;
            }
        }
        /// <summary>
        /// Starts the Login Server listeners, and begins accepting new connections
        /// </summary>
        public static void Start()
        {
            // Make sure we arent already running!
            if (bIsRunning) return;

            // Start the DB Connection
            using (GamespyDatabase Database = new GamespyDatabase())
            {
                // First, make sure our account table exists
                if (!Database.TablesExist)
                {
                    string message = "In order to use the Gamespy Emulation feature of this program, we need to setup a database. "
                    + "You may choose to do this later by clicking \"Cancel\". Would you like to setup the database now?";
                    DialogResult R = MessageBox.Show(message, "Gamespy Database Setup", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (R == DialogResult.Yes)
                        SetupManager.ShowDatabaseSetupForm(DatabaseMode.Gamespy, MainForm.Instance);

                    // Call the stoOnShutdown event to Re-enable the main forms buttons
                    Stopped();
                    return;
                }
                else if (Database.NeedsUpdated)
                {
                    // We cannot run an outdated database
                    DialogResult R = MessageBox.Show(
                        String.Format(
                            "The Gamespy database tables needs to be updated to version {0} before using this feature. Would you like to do this now?",
                            GamespyDatabase.LatestVersion
                        ) + Environment.NewLine.Repeat(1) +
                        "NOTE: You should backup your gamespy account table if you are unsure as this update cannot be undone!",
                        "Gamespy Database Update", MessageBoxButtons.YesNo, MessageBoxIcon.Question
                    );

                    // If the user doesnt migrate the database tables, quit
                    if (R != DialogResult.Yes)
                    {
                        // Call the stoOnShutdown event to Re-enable the main forms buttons
                        Stopped();
                        return;
                    }

                    // Do table migrations
                    Database.MigrateTables();
                }
            }

            // Bind gpcm server on port 29900
            int port = 29900;

            // Setup the DebugLog
            DebugLog.LoggingEnabled = Program.Config.GamespyServerDebug;
            if (Program.Config.GamespyServerDebug)
                DebugLog.ClearLog();

            try
            {
                // Begin logging
                DebugLog.Write("=== Gamespy Emulator Initializing ===");
                DebugLog.Write("Starting Client Manager");

                // Start the client manager
                ClientManager = new GpcmServer();

                // Begin logging
                DebugLog.Write("Bound to TCP port: " + port);
                DebugLog.Write("Starting Account Service Provider");

                // Start search provider server
                port++;
                SearchProvider = new GpspServer();

                // Begin logging
                DebugLog.Write("Bound to TCP port: " + port);
                DebugLog.Write("Starting Master Server");

                // Start then Master Server
                MasterServer = new MasterServer(ref port, DebugLog);

                // Start CDKey Server
                port = 29910;
                DebugLog.Write("Starting Cdkey Server");
                CDKeyServer = new CDKeyServer(DebugLog);

                // Begin logging
                DebugLog.Write("=== Gamespy Emulator Initialized ===");
            }
            catch (Exception E)
            {
                Notify.Show(
                    "Failed to Start Gamespy Servers!",
                    "Error binding to port " + port + ": " + Environment.NewLine + E.Message,
                    AlertType.Warning
                );

                // Append log
                if (DebugLog != null)
                {
                    DebugLog.Write("=== Failed to Start Emulator Servers! ===");
                    DebugLog.Write("Error binding to port " + port + ": " + E.Message);
                }

                // Shutdown all started servers
                if (ClientManager != null && ClientManager.IsListening) ClientManager.Shutdown();
                if (SearchProvider != null && SearchProvider.IsListening) SearchProvider.Shutdown();
                if (MasterServer != null && MasterServer.IsRunning) MasterServer.Shutdown();
                // Cdkey server must have throwm the exception at this point, since it starts last

                // Throw excpetion to parent
                throw;
            }

            // Let the client know we are ready for connections
            bIsRunning = true;
            Started();
        }