using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using Chop.Database;
using System.Data;
using System.Threading;
namespace Chop
{
public class GameClient
{
public static uint MESSAGEID_MAX = 2002;
//public static string POLICY = " ";
private uint mID;
private Socket mSocket;
private byte[] mBuffer;
private bool mPonged;
private Request mRequest;
private Response mResponse;
private Habbo mHabbo;
private delegate void requestHandler();
private requestHandler[] mRequestHandlers;
public uint ID { get { return mID; } }
public string IP { get { return mSocket.RemoteEndPoint.ToString().Split(':')[0]; } }
public bool Ponged { get { return mPonged; } set { mPonged = value; } }
public GameClient(uint ID, Socket Socket)
{
this.mID = ID;
this.mSocket = Socket;
this.mPonged = true;
this.mBuffer = new byte[1024];
this.mRequestHandlers = new requestHandler[MESSAGEID_MAX + 1];
this.mResponse = new Response();
mSocket.BeginReceive(mBuffer, 0, mBuffer.Length, SocketFlags.None, new AsyncCallback(DataIn), null);
RegisterGlobal();
}
private void DataIn(IAsyncResult iAr)
{
try
{
int bytesIn = mSocket.EndReceive(iAr);
if (bytesIn > 0)
{
string data = Encoding.Default.GetString(mBuffer, 0, bytesIn);
while (data.Length > 0)
{
string cData = data.Substring(3, HabboEncoding.decodeB64(data.Substring(1, 2)));
string consoleText = cData; // We want to replace some chars with readable text!
for (int i = 0; i < 13; i++) // char 0-13
{
consoleText = consoleText.Replace(Convert.ToChar(i).ToString(), "{" + i + "}");
}
Console.WriteLine("Incoming data from client [" + mID + "]: \"" + consoleText + "\"");
mRequest = Request.Parse(cData);
if (mRequest.HeaderID <= MESSAGEID_MAX)
if (mRequestHandlers[mRequest.HeaderID] != null)
mRequestHandlers[mRequest.HeaderID].Invoke();
else
{
Console.WriteLine("Message ID [" + mRequest.HeaderID + "] is not registered"); // Not registered
}
else
{
Console.WriteLine("Message ID [" + mRequest.HeaderID + "] is over the max message ID"); // Over max ID
}
data = data.Substring(cData.Length + 3);
}
}
else
{
Core.ClientManager.RemoveClient(mID);
return;
}
}
catch (SocketException) // Nothing special
{
Core.ClientManager.RemoveClient(mID);
}
catch (ObjectDisposedException) // Nothing special
{
Core.ClientManager.RemoveClient(mID);
}
catch (Exception x)
{
Console.WriteLine(x.ToString() + " (GameClient.DataIn)");
Core.ClientManager.RemoveClient(mID);
}
finally
{
if (mSocket.Connected)
mSocket.BeginReceive(mBuffer, 0, mBuffer.Length, SocketFlags.None, new AsyncCallback(DataIn), null);
}
}
public void SendData(string data)
{
try
{
string consoleText = data; // We want to replace some chars with readable text!
for (int i = 0; i < 13; i++) // char 0-13
{
consoleText = consoleText.Replace(Convert.ToChar(i).ToString(), "{" + i + "}");
}
Console.WriteLine("Outgoing data to client [" + mID + "]: \"" + consoleText + "\"");
mSocket.Send(Encoding.Default.GetBytes(data));
}
catch (SocketException) // Nothing special
{
Core.ClientManager.RemoveClient(mID);
}
catch (Exception x)
{
Console.WriteLine(x.ToString() + " (GameClient.SendData)");
Core.ClientManager.RemoveClient(mID);
}
}
private void SendResponse()
{
SendMessage(mResponse);
}
public void SendMessage(Response Message)
{
SendData(Message.ToString() + Convert.ToChar(1));
}
internal void Destroy()
{
if (mSocket.Connected)
{
mSocket.Shutdown(SocketShutdown.Both);
mSocket.Close();
mSocket.Dispose();
}
}
private void RegisterGlobal()
{
mRequestHandlers[196] = new requestHandler(PONG);
mRequestHandlers[202] = new requestHandler(GENERATEKEY);
mRequestHandlers[206] = new requestHandler(INIT_CRYPTO);
mRequestHandlers[49] = new requestHandler(GDATE);
mRequestHandlers[42] = new requestHandler(APPROVENAME);
mRequestHandlers[203] = new requestHandler(APPROVE_PASSWORD);
mRequestHandlers[197] = new requestHandler(APPROVEEMAIL);
mRequestHandlers[46] = new requestHandler(AC);
mRequestHandlers[131] = new requestHandler(COPPA_REG_GETREALTIME);
mRequestHandlers[43] = new requestHandler(REGISTER);
mRequestHandlers[4] = new requestHandler(TRY_LOGIN);
mRequestHandlers[7] = new requestHandler(GET_INFO);
mRequestHandlers[8] = new requestHandler(GET_CREDITS);
}
///
/// 196 - "CD" - "PONG"
///
private void PONG()
{
mPonged = true;
}
///
/// 206 - "CN" - "INIT_CRYPTO"
///
private void INIT_CRYPTO()
{
mResponse.Init(277); // "DU"
mResponse.AppendWired(0);
SendResponse();
}
///
/// 202 - "CJ" - "GENERATEKEY"
///
private void GENERATEKEY()
{
mResponse.Init(8); // "@H"
mResponse.Append("[100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,176,177,178,180,185,190,195,200,205,206,207,210,215,220,225,230,235,240,245,250,255,260,265,266,267,270,275,280,281,285,290,295,300,305,500,505,510,515,520,525,530,535,540,545,550,555,565,570,575,580,585,590,595,596,600,605,610,615,620,625,626,627,630,635,640,645,650,655,660,665,667,669,670,675,680,685,690,695,696,700,705,710,715,720,725,730,735,740,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873]");
SendResponse();
mResponse.Init(257); // "DA"
mResponse.AppendWired(6);
mResponse.AppendWired(0);
mResponse.AppendWired(1);
mResponse.AppendWired(1);
mResponse.AppendWired(1);
mResponse.AppendWired(3);
mResponse.AppendWired(0);
mResponse.AppendWired(2);
mResponse.AppendWired(1);
mResponse.AppendWired(4);
mResponse.AppendWired(1);
mResponse.AppendWired(5);
mResponse.AppendString(Core.Config.GetString("core.date.format")); // Date format
SendResponse();
}
///
/// 49 - "@q" - "GDATE"
///
private void GDATE()
{
mResponse.Init(163); // "Bc"
mResponse.Append(DateTime.Today.ToString(Core.Config.GetString("core.date.format")));
SendResponse();
}
///
/// 42 - "@j" - "APPROVENAME"
///
private void APPROVENAME()
{
// Errors:
// 0 = valid
// 1 = too long
// 2 = unacceptable to staff
// 3 = 2 (unacceptable to staff)
// 4 = name taken
string Name = mRequest.PopString();
int ErrorID = 0;
if (Name.Length > 15) // Name too long
ErrorID = 1;
if (Name.Length < 2) // Name too short
ErrorID = 2;
else if (Name.Contains("MOD-") || StringHelper.ContainsOtherChars(Name, Core.Config.GetString("game.registration.characters.allowed"))) // invalid name
ErrorID = 3;
else if (false) // name taken
ErrorID = 4;
mResponse.Init(36); // "@d"
mResponse.AppendWired(ErrorID);
SendResponse();
}
///
/// 203 - "CK" - "APPROVE_PASSWORD"
///
private void APPROVE_PASSWORD()
{
// Errors:
// 0 = valid
// 1 = too short
// 2 = too long
// 3 = invalid chars
// 4 = needs atleast 1 number
// 5 = name & password too similar
// must be 6 chr long
// only chars = 1234567890qwertyuiopasdfg hjklzxcvbnm-=?!@@:.,
string Name = mRequest.PopString();
string Password = mRequest.PopString();
int ErrorID = 0;
if (Password.Length < 6)
ErrorID = 1;
else if (Password.Length > 10)
ErrorID = 2;
else if (StringHelper.ContainsOtherChars(Password, Core.Config.GetString("game.registration.characters.allowed")))
ErrorID = 3;
else if (!StringHelper.ContainsNumber(Password))
ErrorID = 4;
else if (Password.Contains(Name))
ErrorID = 5;
mResponse.Init(282); // "DZ"
mResponse.AppendWired(ErrorID);
SendResponse();
}
///
/// 197 - "CK" - "APPROVEEMAIL"
///
private void APPROVEEMAIL()
{
string Mail = mRequest.PopString();
if (Mail.Contains('@') && Mail.Contains('.')) // TODO: Maybe better check?
mResponse.Init(271); // "DO"
else
mResponse.Init(272); // "DP"
SendResponse();
}
///
/// 46 - "@n" - "AC"
///
private void AC()
{
try
{
DateTime Birth = DateTime.Parse(mRequest.Content, new System.Globalization.CultureInfo("en-GB"));
if (Birth.Year > DateTime.Now.Year - Core.Config.GetInt("game.registration.age.min"))
mResponse.Init(272); // "DP"
else if (Birth.Year < DateTime.Now.Year - Core.Config.GetInt("game.registration.age.max"))
mResponse.Init(272); // "DP"
else
mResponse.Init(271); // "DO"
}
catch
{
mResponse.Init(272); // "DP"
}
SendResponse();
}
///
/// 131 - "BC" - "COPPA_REG_GETREALTIME"
///
private void COPPA_REG_GETREALTIME()
{
mResponse.Init(214); // "CV"
SendResponse();
}
///
/// 43 - "@k" - "REGISTER"
///
private void REGISTER()
{
#region Decoding
//newUser.sPassword = FuseMessage.getStructured(3, mPacketBody);
//newUser.sFigure = FuseMessage.getStructured(4, mPacketBody);
//newUser.sSex = FuseMessage.getStructured(5, mPacketBody);
//newUser.sMission = FuseMessage.getStructured(6, mPacketBody);
//newUser.sEmail = FuseMessage.getStructured(7, mPacketBody);
//newUser.sDOB = FuseMessage.getStructured(8, mPacketBody);
//mRequest.Content = mRequest.Content.Replace("A@", "@E");
string Name = "MOD-|"; // mRequest.GetStructured(2);
string Figure = "f"; // mRequest.GetStructured(4);
char Gender = 'g'; // Convert.ToChar(mRequest.GetStructured(5));
string Mail = "m"; // mRequest.GetStructured(7);
string Birth = "b"; // mRequest.GetStructured(8);
string Password = "p"; // mRequest.GetStructured(3);
bool ReceiveMails = false;
for (int i = 0; i < 6; i++)
{
int ID = mRequest.PopBase64Int();
string Content = mRequest.PopString();
switch (ID)
{
case 2:
Name = Content;
break;
case 4:
Figure = Content;
break;
case 5:
Gender = Convert.ToChar(Content);
break;
case 6: // Unknown, maybe parent mail?
break;
case 7:
Mail = Content;
break;
case 8:
Birth = Content;
break;
}
}
// Get rid of trash
mRequest.PopBase64Int();
mRequest.PopBase64Int();
mRequest.PopBase64Int();
mRequest.PopBase64Int();
ReceiveMails = mRequest.PopBase64Boolean();
// More trash...
mRequest.PopBase64Int();
Password = mRequest.PopString();
#endregion
#region Checking
bool Error = false;
if (Name.Length > 15) // Name too long
Error = true;
if (Name.Length < 2) // Name too short
Error = true;
else if (Name.Contains("MOD-") || StringHelper.ContainsOtherChars(Name, Core.Config.GetString("game.registration.characters.allowed"))) // invalid name
return;
else if (false) // name taken
Error = true;
if (Password.Length < 6)
return;
else if (Password.Length > 10)
Error = true;
else if (StringHelper.ContainsOtherChars(Password, Core.Config.GetString("game.registration.characters.allowed")))
Error = true;
else if (!StringHelper.ContainsNumber(Password))
Error = true;
else if (Password.Contains(Name))
Error = true;
try
{
DateTime BirthTime = DateTime.Parse(Birth, new System.Globalization.CultureInfo("en-GB"));
if (BirthTime.Year > DateTime.Now.Year - Core.Config.GetInt("game.registration.age.min"))
Error = true;
else if (BirthTime.Year < DateTime.Now.Year - Core.Config.GetInt("game.registration.age.max"))
Error = true;
}
catch
{
Error = true;
}
if (!(Mail.Contains('@') && Mail.Contains('.'))) // TODO: Maybe better check?
Error = true;
if (Gender != 'M' && Gender != 'F')
Error = true;
// TODO: Figure check
if (Error)
{
Core.ClientManager.RemoveClient(ID);
return;
}
#endregion
#region Saving
using (DatabaseClient dbClient = Core.DatabaseManager.GetClient())
{
dbClient.AddParamWithValue("name", Name);
dbClient.AddParamWithValue("figure", Figure);
dbClient.AddParamWithValue("gender", Gender);
dbClient.AddParamWithValue("mail", Mail);
dbClient.AddParamWithValue("birth", Birth);
dbClient.AddParamWithValue("password", Password);
dbClient.AddParamWithValue("credits", Core.Config.GetInt("game.registration.default.credits"));
dbClient.AddParamWithValue("motto", Core.Config.GetString("game.registration.default.motto"));
dbClient.ExecuteQuery("INSERT INTO habbos(name,figure,gender,mail,birth,password,credits,motto) VALUES(@name,@figure,@gender,@mail,@birth,@password,@credits,@motto)");
}
#endregion
}
///
/// 4 - "@D" - "TRY_LOGIN"
///
private void TRY_LOGIN()
{
string Username = mRequest.PopString();
string Password = mRequest.PopString();
DataRow row;
using (DatabaseClient dbClient = Core.DatabaseManager.GetClient())
{
dbClient.AddParamWithValue("username", Username);
row = dbClient.ReadDataRow("SELECT * FROM habbos WHERE name = @username");
}
if (row == null) // User don't exists!
{
mResponse.Init(33); // "@a"
mResponse.Append("login incorrect: Wrong username");
SendResponse();
return;
}
else if (row["password"].ToString() != Password) // Wrong password!
{
mResponse.Init(33); // "@a"
mResponse.Append("login incorrect: Wrong password");
SendResponse();
return;
}
DataRow banRow;
using (DatabaseClient dbClient = Core.DatabaseManager.GetClient())
{
dbClient.AddParamWithValue("id", row["id"]);
banRow = dbClient.ReadDataRow("SELECT * FROM bans WHERE habboid = @id");
}
if (banRow != null) // ban fond
{
int i = DateTime.Compare(DateTime.Parse(banRow["expires"].ToString(), new System.Globalization.CultureInfo("en-GB")), DateTime.Now);
if (i < 0) // Ban expired
using (DatabaseClient dbClient = Core.DatabaseManager.GetClient())
{
dbClient.AddParamWithValue("id", row["id"]);
dbClient.ExecuteQuery("DELETE FROM bans WHERE habboid = @id");
}
else
{
mResponse.Init(35); // "@c"
mResponse.Append(banRow["message"]);
SendResponse();
Thread.Sleep(10000);
Core.ClientManager.RemoveClient(ID);
return;
}
}
mHabbo = Habbo.Parse(row, this);
mResponse.Init(2); // "@B"
mResponse.AppendString("fuse_default");
SendResponse();
mResponse.Init(3); // "@C"
SendResponse();
mResponse.Init(8); // "@H"
mResponse.Append("[100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,176,177,178,180,185,190,195,200,205,206,207,210,215,220,225,230,235,240,245,250,255,260,265,266,267,270,275,280,281,285,290,295,300,305,500,505,510,515,520,525,530,535,540,545,550,555,565,570,575,580,585,590,595,596,600,605,610,615,620,625,626,627,630,635,640,645,650,655,660,665,667,669,670,675,680,685,690,695,696,700,705,710,715,720,725,730,735,740,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873]");
SendResponse();
}
///
/// 7 - "@G" - "GET_INFO"
///
private void GET_INFO()
{
mResponse.Init(5); // "@E"
mResponse.Append(mHabbo.ToFuseString());
SendResponse();
}
///
/// 8 - "@H" - "GET_CREDITS"
///
private void GET_CREDITS()
{
mResponse.Init(6); // "@F"
mResponse.Append(mHabbo.Credits + ".0");
SendResponse();
}
}
}