//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "ChatClientMainForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdTCPClient"
#pragma link "IdTCPConnection"
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma resource "*.dfm"
TfrmChatClientMain *frmChatClientMain;
// For Unicode support
#define ENCODING
TEncoding* CharacterEncoding = TIdTextEncoding::UTF8;
//---------------------------------------------------------------------------
__fastcall TfrmChatClientMain::TfrmChatClientMain(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::FormCreate(TObject *Sender)
{
mmoHistory->Align = alClient;
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::btnConnectClick(TObject *Sender)
{
try
{
try
{
// If we're already connect, disconnect from the server
if (tcpClient->Connected())
{
DisconnectFromServer();
}
else // we're not connected, so connect to the server
{
ConnectToServer(); // this is a blocking call
}
}
catch (const Exception& e)
{
ShowMessage(e.Message);
}
}
__finally
{
if (tcpClient->Connected())
btnConnect->Caption = "Disconnect";
else
btnConnect->Caption = "Connect";
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void TfrmChatClientMain::ConnectToServer(void)
{
tcpClient->Host = lstServer->Text;
tcpClient->Port = (short)ledtPort->Text.ToInt();
btnConnect->Caption = "Disconnect";
tcpClient->Connect();
}
//---------------------------------------------------------------------------
void TfrmChatClientMain::DisconnectFromServer(void)
{
btnConnect->Caption = "Connect";
if (tcpClient->Connected())
{
tcpClient->Disconnect();
}
}
//---------------------------------------------------------------------------
// Send text command to the server and to the output window
void TfrmChatClientMain::SendCommand(const String& command)
{
if (tcpClient->Connected())
{
String msg = "SEND " + command;
tcpClient->Socket->WriteLn(msg);
String out = "[" + FClientIP + ":" + FClientPort + "] " + command;
UpdateOutput(out, dirSEND);
}
else
{
UpdateOutput("Not connected [" + command + "]");
}
}
void TfrmChatClientMain::UpdateOutput(const String& s, TDirection dir)
{
String d = "";
TColor attr = clBlack;
if (dir == dirSEND)
{
d = "SEND --> ";
attr = clBlue;
}
else if (dir == dirRECV)
{
d = "RECV <-- ";
attr = clRed;
}
d = "";
/*
This works differently than I expected. If you set the attributes, and
then Add() lines to the control, everything works fine. But, if you
Insert() the lines, you need to insert them before setting the attribute.
If you don't, you'll get the new attribute applied to the item at index
0, which will be scrolled down to index 1 after the insert and will have
the new attribute applied.
*/
String str = d + s;
mmoHistory->Lines->BeginUpdate();
if (chkInsertLinesAtTop->Checked)
{
// Insert the line
mmoHistory->Lines->Insert(0, str);
// Select the line and then apply the color (attributes) to the selection
mmoHistory->SelStart = 0;
mmoHistory->SelLength = str.Length();
mmoHistory->SelAttributes->Color = attr;
}
else
{
mmoHistory->SelAttributes->Color = attr;
mmoHistory->Lines->Add(str);
}
mmoHistory->Lines->EndUpdate();
}
void __fastcall TfrmChatClientMain::btnSendClick(TObject *Sender)
{
SendCommand(ledtCommand->Text);
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::tcpClientConnected(TObject *Sender)
{
//////////////////////////////////////////////////////////////////////////////
// This block of code is executed once when the client first connects.
String s = "Connected to " + lstServer->Text;
UpdateOutput(s, dirNEITHER);
s = "Remote " + tcpClient->Socket->Binding->PeerIP + ":" + tcpClient->Socket->Binding->PeerPort;
FClientIP = tcpClient->Socket->Binding->IP;
FClientPort = tcpClient->Socket->Binding->Port;
UpdateOutput(s, dirNEITHER);
s = "Local " + tcpClient->Socket->Binding->IP + ":" + tcpClient->Socket->Binding->Port;
UpdateOutput(s, dirNEITHER);
//////////////////////////////////////////////////////////////////////////////
#ifdef ENCODING
tcpClient->IOHandler->DefStringEncoding = CharacterEncoding;
#endif
// Continue to process all messages from the server until we disconnect
while (tcpClient->Connected())
{
// See if there is a message from the server
String s = tcpClient->Socket->ReadLn("", 50);
if (tcpClient->Socket->ReadLnTimedout)
{
// This will occur when there is no message waiting
}
else if (s != "")
{
if (!CompareText(s.SubString(1, 4), "MESG"))
{
// TODO: Clean this up. Kind of a hack to parse the string
TStringList *list = new TStringList;
list->DelimitedText = s;
list->Delimiter = ' ';
// Don't display our own message
if (list->Strings[1] == FClientIP + ":" + FClientPort)
{
delete list;
continue;
}
String out = "[" + list->Strings[1] + "]";
for (int j = 2; j < list->Count; j++)
out += " " + list->Strings[j];
UpdateOutput(out, dirRECV);
delete list;
}
else
{
UpdateOutput(s, dirNEITHER);
}
}
else
{
// do something?
}
}
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::FormClose(TObject *Sender, TCloseAction &Action)
{
DisconnectFromServer();
}
//---------------------------------------------------------------------------
void __fastcall TfrmChatClientMain::ledtCommandKeyPress(TObject *Sender, wchar_t &Key)
{
if (Key == VK_RETURN)
{
SendCommand(ledtCommand->Text);
Key = 0;
}
}
//---------------------------------------------------------------------------