protected virtual Response callChecked_Connect(AmTcpClient newConnection, string commandString, out string requestedUsername)
        {
            requestedUsername = "";

            // This function is special and has to do the extra work of splitting and checking the commandstring.
            string[] commandSplit = CpParseUtilities.SplitMessage(commandString, m_stringDelimiter, 2);
            // check it is a "connect" request
            if (commandSplit[0].ToLower() != "connect")
            {
                return(new Response(false, "Expected connection request."));
            }

            // check arguments (should be 2)
            string errMessage = "";

            if (!CpParseUtilities.CheckArgCount(commandSplit, 2, 2, ref errMessage))
            {
                return(new Response(false, errMessage));
            }

            // check if name has a colon in it (not allowed)
            requestedUsername = commandSplit[1];
            if (requestedUsername.Contains(m_stringDelimiter))
            {
                return(new Response(false, String.Format("Name shall not contain the delimiter character '{0}'.", m_stringDelimiter)));
            }

            // attempt to register the user
            return(handle_Connect(requestedUsername, newConnection));
        }
        private async Task cpClientServiceLoopAsync(SslEgg egg)
        {
            AmTcpClient client = new AmTcpClient(egg);

            // shortcut lambda
            Func <Response, Task <bool> > lSendResponseAsync = async(response) =>
            {
                return(await SendResponseAsync(client.Serializer, response.Success, response.Message));
            };

            // establish connection / register user
            string username;

            {
                // read from the new client (expecting a "connect" commandstring).
                var tup = await client.Deserializer.DeserializeAsync("");

                bool   stillConnected = tup.Item1;
                string commandString  = tup.Item2;

                if (!stillConnected)
                {
                    Logging.DebugWriteLine("Client connected but disconnected before trying to register.");
                    client.Close();
                    return;
                }
                // parse the command string and register the user
                Response res = callChecked_Connect(client, commandString, out username);
                await lSendResponseAsync(res);  // don't need to check result as a disconnected client will be detected upon first read

                if (!res.Success)
                {
                    Logging.DebugWriteLine(String.Format("Unable to register new client '{0}'. {1}", username, res.Message));
                    client.Close();
                    return;
                }

                Logging.DebugWriteLine(String.Format("Client '{0}' connected. {1}", username, client.RemoteEndPoint.ToString()));
            }

            while (true)
            {
                // the command string read from client
                var tup = await client.Deserializer.DeserializeAsync("");

                bool   stillConnected = tup.Item1;
                string commandString  = tup.Item2;

                if (!stillConnected)
                {
                    // remove the user from various data structures
                    Response result = handle_Disconnect(username);
                    Logging.DebugWriteLine(String.Format("Client {0} disconnected.", username));
                    if (!result.Success)
                    {
                        Logging.DebugWriteLine(result.Message);
                    }
                    goto exit_while;
                }

                // an array of strings parsed from the sent command string by splitting by colon :
                // hard-coded max 10 substrings. Change if needed.
                string[] commandSplit = CpParseUtilities.SplitMessage(commandString, m_stringDelimiter, 10);


                switch (commandSplit[0].ToLower())
                {
                case "disconnect":
                {
                    Response result = callChecked_Disconnect(commandSplit, username);
                    await lSendResponseAsync(result);

                    if (result.Success)
                    {
                        Logging.DebugWriteLine(String.Format("Client {0} disconnected gracefully.", username));
                        goto exit_while;
                    }
                    Logging.DebugWriteLine(String.Format("From server: Client {0} requested disconnect but was denied. {1}", username, result.Message));
                    break;
                }

                case "create_room":
                {
                    Response result = callChecked_CreateRoom(commandSplit);
                    await lSendResponseAsync(result);

                    if (result.Success)
                    {
                        Logging.DebugWriteLine(String.Format("Client {0} created room '{1}'.", username, commandSplit[1]));
                    }
                    break;
                }

                case "delete_room":
                {
                    Response result = await callChecked_DeleteRoom(commandSplit);
                    await lSendResponseAsync(result);

                    if (result.Success)
                    {
                        Logging.DebugWriteLine(String.Format("Client {0} deleted room '{1}'.", username, commandSplit[1]));
                    }
                    break;
                }

                case "list_rooms":
                {
                    Response result = callChecked_ListRooms(commandSplit);
                    await lSendResponseAsync(result);

                    break;
                }

                case "subscribe_room":
                {
                    Response result = callChecked_SubscribeRoom(commandSplit, username);
                    await lSendResponseAsync(result);

                    break;
                }

                case "unsubscribe_room":
                {
                    Response result = callChecked_UnsubscribeRoom(commandSplit, username);
                    await lSendResponseAsync(result);

                    break;
                }

                case "list_room_members":
                {
                    Response result = callChecked_ListRoomMembers(commandSplit);
                    await lSendResponseAsync(result);

                    break;
                }

                case "send_message_room":
                {
                    Response result = await callChecked_MessageRoomAsync(commandSplit, username);
                    await lSendResponseAsync(result);

                    break;
                }

                case "send_message_personal":
                {
                    Response result = await callChecked_MessagePersonalAsync(commandSplit, username);
                    await lSendResponseAsync(result);

                    break;
                }

                default:
                    await lSendResponseAsync(new Response(false, "Unknown command."));

                    Logging.DebugWriteLine(String.Format("Client sent unknown command. '{0}'", commandString));
                    break;
                }
            }

exit_while:
            // cleanup socket resources
            client.Close();
        }
 abstract protected Response handle_Connect(string username, AmTcpClient newConnection);