using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Duck.Managers;
using Duck.Virtual.Rooms;
using Duck.Net.Game;
using Duck.Net.Game.Protocol.Encoding;
using Duck.Net.Game.Protocol.Messages;
namespace Duck.Virtual.Users
{
///
/// Represents a virtual user, with connection and packet handling, access management etc etc.
///
public class virtualUser
{
#region Declares
#region Connection related
///
/// The ID of the connection for this virtual user. Assigned by the info socket server.
///
private int connectionID;
///
/// The socket that connects the client with the emulator. Operates asynchronous.
///
private Socket Socket;
///
/// The byte array (1024 bytes) where the data is saved in while receiving the data asynchronously from the client.
///
private byte[] dataBuffer = new byte[1024];
///
/// Specifies if the client has sent the 'CD' packet on time. Being checked by the user manager every minute.
///
internal bool pingOK;
///
/// Specifies if the client is disconnected already.
///
private bool _isDisconnected;
#endregion
#region User related
#region Personal
///
/// The database ID of this virtual user.
///
internal int userID;
///
/// The username of this virtual user.
///
internal string _Username;
///
/// The figure string of this virtual user. Numeric only.
///
internal string _Figure;
///
/// The sex of this virtual user. 'M' for male and 'F' for female.
///
internal char _Sex;
///
/// The motto of this virtual user. Displayed next to user in virtual rooms etc.
///
internal string _Motto;
///
/// The motto displayed next to this virtual user on console. (messenger)
///
internal string _consoleMotto;
///
/// The current badge of this virtual user. Displayed next to user in virtual rooms etc. If empty, then no badge is shown.
///
internal string _Badge;
///
/// The user rank of this virtual user. 1-6, where 1 is the lowest and 6 the highest.
///
internal byte _Rank;
///
/// The subscriptions where this user is subscribed to.
///
internal string[] _Subscriptions = new string[0];
///
/// The amount of credits/coins (currency) that this virtual user currently has in it's 'purse'.
///
internal int _Credits;
///
/// The amount of game tickets (required to play games) that this virtual user currently has in it's 'purse'.
///
internal int _Tickets;
///
/// The amount of films (to use for making ingame photos with the Camera) that this virtual user currently has in it's 'purse'.
///
internal int _Films;
#endregion
#endregion
#endregion
#region Constructors/destructors
///
/// Initializes a new virtual user and starts up the packet routine.
///
/// The ID of the new connection.
/// The socket of the new connection.
public virtualUser(int connectionID, Socket Socket)
{
this.connectionID = connectionID;
this.Socket = Socket;
try
{
string banReason = "";
//string banReason = ""; userManager.getBanReason(this.connectionRemoteIP);
if (banReason != "") // This virtual user has got an IP address ban
{
sendData("@c" + banReason);
Disconnect();
}
else
{
this.pingOK = true;
sendData("@@");
Socket.BeginReceive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None, new AsyncCallback(dataArrival), null);
}
}
catch { }
}
#endregion
#region Properties
///
/// Returns the IP address of this connection as a string.
///
internal string connectionRemoteIP
{
get
{
return Socket.RemoteEndPoint.ToString().Split(':')[0];
}
}
#endregion
#region Methods
#region Connection & data transfer related
///
/// Immediately completes the current data transfer [if any], disconnects the client and flags the connection slot as free.
///
internal void Disconnect()
{
if (this._isDisconnected == false)
{
this._isDisconnected = true;
try { this.Socket.Close(); }
catch { }
this.Socket = null;
if(userID > 0)
userManager.removeUser(userID);
infoSocketServer.freeConnection(this.connectionID);
}
}
private delegate void timedDisconnector(int ms);
///
/// Disables receiving on the socket, sleeps for a specified amount of time [ms] and disconnects via normal Disconnect() void. Asynchronous.
///
/// The amount of milliseconds to sleep before disconnect.
internal void Disconnect(int ms)
{
new timedDisconnector(delDisconnectTimed).BeginInvoke(ms, null, null);
}
private void delDisconnectTimed(int ms)
{
this.Socket.Shutdown(SocketShutdown.Receive);
Thread.Sleep(ms);
Disconnect();
}
///
/// This void is triggered when a new datapacket arrives at the socket of this user. The packet is separated and processed. On errors, the client is disconnected.
///
/// The IAsyncResult of this BeginReceive asynchronous action.
private void dataArrival(IAsyncResult iAr)
{
try
{
int bytesReceived = this.Socket.EndReceive(iAr);
string Data = System.Text.Encoding.Default.GetString(this.dataBuffer, 0, bytesReceived);
if (Data.Contains("\x01") || Data.Contains("\x02") || Data.Contains("\x05") || Data.Contains("\x10"))
{
IO.WriteLine("Hax alert: " + this._Username + " [" + this.connectionRemoteIP + "] sent an exploited character in a packet. Disconnected.", IO.logFlags.importantAction, ConsoleColor.Magenta, ConsoleColor.DarkMagenta);
this.Disconnect();
return;
}
try
{
while (Data != "")
{
int v = base64Encoding.Decode(Data.Substring(1, 2));
processMessage(new clientMessage(Data.Substring(3, v)));
Data = Data.Substring(v + 3);
}
}
catch { }
Socket.BeginReceive(dataBuffer, 0, dataBuffer.Length, SocketFlags.None, new AsyncCallback(dataArrival), null);
}
catch { this.Disconnect(); return; }
}
///
/// Sends a single serverMessage message to the client via an asynchronous BeginSend action.
///
/// The serverMessage of the message to send.
internal void sendMessage(serverMessage Message)
{
try
{
byte[] Data = System.Text.Encoding.Default.GetBytes(Message.ToString());
this.Socket.BeginSend(Data, 0, Data.Length, 0, new AsyncCallback(sentData), null);
}
catch { this.Disconnect(); }
}
///
/// Sends a single packet as a string to the client via an asynchronous BeginSend action.
///
/// The string of data to send. char[01] is added.
internal void sendData(string Data)
{
try
{
byte[] dataBytes = System.Text.Encoding.Default.GetBytes(Data + Convert.ToChar(1));
Socket.BeginSend(dataBytes, 0, dataBytes.Length, 0, new AsyncCallback(sentData), null);
//IO.WriteSpecialLine(Data.Replace("\r", "{13}"), IO.logFlags.mehAction, ConsoleColor.White, ConsoleColor.DarkYellow, "> [" + connectionID + "]", 2, ConsoleColor.Yellow);
}
catch { Disconnect(); }
}
///
/// Triggered when an asynchronous BeginSend action is completed.
///
/// The IAsyncResult of this BeginSend asynchronous action.
private void sentData(IAsyncResult iAr)
{
try { Socket.EndSend(iAr); }
catch { Disconnect(); }
}
internal void sendLocalError(string Error)
{
serverMessage Message = new serverMessage(33);
Message.Append(Error);
this.sendMessage(Message);
}
#endregion
#region Packet related
///
/// Processes a single client>server message.
///
/// The message to process.
private void processMessage(clientMessage clientMessage)
{
//IO.WriteSpecialLine(currentPacket.Replace("\r", "{13}"), IO.logFlags.mehAction, ConsoleColor.DarkGray, ConsoleColor.DarkYellow, "< [" + connectionID + "]", 2, ConsoleColor.Yellow);
serverMessage serverMessage = null;
if (this.userID == 0)
#region Non-logged in packets
{
switch (clientMessage.ID)
{
case 4: // @D * TRY_LOGIN
{
string[] s = clientMessage.Parameters;
this.Login(DB.Stripslash(s[0]), s[1]);
}
break;
case 5: // @E * VERSIONCHECK
case 202: // CJ * GENERATEKEY
{
serverMessage = new serverMessage(257);
serverMessage.appendValue("RAHIIIKHJIPAIQAdd-MM-yyyy");
this.sendMessage(serverMessage);
serverMessage = new serverMessage(8);
serverMessage.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]");
this.sendMessage(serverMessage);
}
break;
case 41: // @i * FINDUSER
{
serverMessage = new serverMessage(128);
serverMessage.appendValue("MESSENGER");
serverMessage.appendWired(false);
this.sendMessage(serverMessage);
}
break;
case 42: // @j * APPROVENAME
{
serverMessage = new serverMessage(36);
serverMessage.appendWired(Access.getNameCheckError(false, clientMessage.firstParameter));
this.sendMessage(serverMessage);
}
break;
case 43: // @k * REGISTER
{
string Name = clientMessage.getParameter(2);
if (Access.getNameCheckError(false, Name) > 0)
return;
string Password = clientMessage.getParameter(3);
if (Access.passwordOK(Name, Password) == false)
return;
string Figure = clientMessage.getParameter(4);
if (stringManager.isNumeric(Figure) == false || Figure.Length != 25)
return; // MUTANT HAX?! ZOMG NO WAI :[
char Sex = 'M';
if (clientMessage.getParameter(5) == "F")
Sex = 'F';
string Email = clientMessage.getParameter(7); // Always OK, w/e
if (Access.emailOK(Email) == false)
return;
string DOB = clientMessage.getParameter(8);
try
{
string[] s = DOB.Split('.');
DOB = int.Parse(s[0]) + "." + int.Parse(s[1]) + "." + int.Parse(s[2]);
}
catch { return; }
DB.runQuery("INSERT INTO users(username,password,rank,figure,sex,motto,credits,tickets,films,ip_registered,email,created,dob) VALUES ('" + Name + "','" + Password + "','1','" + Figure + "','" + Sex + "','" + Config.Registration_Motto + "','" + Config.Registration_Credits + "','" + Config.Registration_Tickets + "','" + Config.Registration_Films + "','" + this.connectionRemoteIP + "','" + Email + "','" + DateTime.Now.ToShortDateString().Replace("-",".") + "','" + DOB + "')");
this.Login(Name, Password);
}
break;
case 46: // @n * APPROVEDOB
case 197: // CE * APPROVEEMAIL
{
serverMessage = new serverMessage(271);
this.sendMessage(serverMessage);
}
break;
case 49: // @q * GDATE
{
serverMessage = new serverMessage(163);
serverMessage.Append(DateTime.Now.ToShortDateString());
this.sendMessage(serverMessage);
}
break;
case 146: // BR * PARENT_EMAIL_REQUIRED
{
serverMessage = new serverMessage(217);
serverMessage.Append(1);
this.sendMessage(serverMessage);
}
break;
case 196: // CD * PONG
pingOK = true;
break;
case 203: // CK * APPROVE_PASSWORD
{
string[] s = clientMessage.Parameters;
serverMessage = new serverMessage(282);
serverMessage.appendWired(!Access.passwordOK(s[0], s[1]));
this.sendMessage(serverMessage);
}
break;
}
}
#endregion
else
#region Logged in packets
{
switch (clientMessage.ID)
{
case 2: // @B * NAVIGATE
{
}
break;
case 7: // @G * GET_INFO
{
string[] Data = DB.runReadRow("SELECT figure,sex,motto,credits,tickets,films FROM users WHERE id = '" + this.userID + "'");
this._Figure = Data[0];
this._Sex = char.Parse(Data[1]);
this._Motto = Data[2];
this._Credits = int.Parse(Data[3]);
this._Tickets = int.Parse(Data[4]);
this._Films = int.Parse(Data[5]);
serverMessage = new serverMessage(5);
serverMessage.appendPlainParameter("name",this._Username);
serverMessage.appendPlainParameter("figure",this._Figure);
serverMessage.appendPlainParameter("sex",this._Sex.ToString());
serverMessage.appendPlainParameter("customData",this._Motto);
serverMessage.appendPlainParameter("ph_tickets",this._Tickets.ToString());
serverMessage.appendPlainParameter("ph_figure","ch=s02/53,51,44");
serverMessage.appendPlainParameter("photo_film",this._Films.ToString());
serverMessage.appendPlainParameter("directMail","0");
this.sendMessage(serverMessage);
break;
}
break;
case 8: // @H * GET_CREDITS
{
serverMessage = new serverMessage(6);
serverMessage.Append(this._Credits);
serverMessage.Append(".0");
this.sendMessage(serverMessage);
break;
}
case 12: // @L * MESSENGERINIT
{
}
break;
case 16: // @P - SUSERF
{
string[] roomIDs = DB.runReadColumn("SELECT id FROM rooms WHERE owner = '" + this._Username + "' ORDER BY id ASC", 0);
if (roomIDs.Length > 0)
{
serverMessage = new serverMessage(16);
for(int i = 0; i < roomIDs.Length; i++)
{
string[] Data = DB.runReadRow("SELECT name,description,accesslevel,showname,visitors_now,visitors_max FROM rooms WHERE id = '" + roomIDs[i] + "'");
serverMessage.appendFlatValue(roomIDs[i]);
serverMessage.appendFlatValue(Data[0]);
serverMessage.appendFlatValue(this._Username);
serverMessage.appendFlatValue(Access.getRoomAccessFlag(Data[2]).ToString());
serverMessage.appendFlatValue("x");
serverMessage.appendFlatValue(Data[4]);
serverMessage.appendFlatValue(Data[5]);
serverMessage.appendFlatValue("null");
serverMessage.appendFlatValue(Data[1]);
serverMessage.appendChar(13);
}
}
else
serverMessage = new serverMessage(57);
this.sendMessage(serverMessage);
}
break;
case 17: // @Q - SRCHF
{
string Query = DB.Stripslash(clientMessage.Content.Substring(3, clientMessage.Content.Length - 4));
string[] roomIDs = DB.runReadColumn("SELECT id FROM rooms WHERE NOT(owner IS NULL) AND (owner = '" + Query + "' OR name LIKE '%" + Query + "%') ORDER BY id ASC", Config.Rooms_Navigator_searchGuestroom_maxResults);
if (roomIDs.Length > 0)
{
bool seeAllRoomOwners = Access.accessRankHasFUSERight(this._Rank, this._Subscriptions, "fuse_see_all_room_owners");
serverMessage = new serverMessage(55);
for (int i = 0; i < roomIDs.Length; i++)
{
string[] Data = DB.runReadRow("SELECT name,description,accesslevel,showname,visitors_now,visitors_max,owner FROM rooms WHERE id = '" + roomIDs[i] + "'");
if (Data[4] == "0" && Data[1] != _Username && seeAllRoomOwners == false) // The room owner has hidden his name at the guestroom and this user hasn't got the fuseright to see all room owners
Data[1] = "-";
serverMessage.appendFlatValue(roomIDs[i]);
serverMessage.appendFlatValue(Data[0]);
serverMessage.appendFlatValue(Data[6]);
serverMessage.appendFlatValue(Access.getRoomAccessFlag(Data[2]).ToString());
serverMessage.appendFlatValue("x");
serverMessage.appendFlatValue(Data[4]);
serverMessage.appendFlatValue(Data[5]);
serverMessage.appendFlatValue("null");
serverMessage.appendFlatValue(Data[1]);
serverMessage.appendChar(13);
}
}
else
serverMessage = new serverMessage(58);
this.sendMessage(serverMessage);
}
break;
case 18: // @R * GETFVRF
{
int[] roomIDs = DB.runReadColumn("SELECT roomid FROM users_favouriterooms WHERE userid = '" + this.userID + "' ORDER BY roomid DESC", Config.Rooms_Favorites_maxPerUser, null);
if (roomIDs.Length > 0)
{
int deletedAmount = 0;
int guestRoomAmount = 0;
bool seeHiddenRoomOwners = Access.accessRankHasFUSERight(this._Rank, this._Subscriptions, "see_all_room_owners");
StringBuilder Rooms = new StringBuilder();
for (int i = 0; i < roomIDs.Length; i++)
{
string[] roomData = DB.runReadRow("SELECT name,owner,accesslevel,showname,visitors_now,visitors_max,description FROM rooms WHERE id = '" + roomIDs[i] + "'");
if (roomData.Length == 0)
{
if (guestRoomAmount > 0)
deletedAmount++;
DB.runQuery("DELETE FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomIDs[i] + "' LIMIT 1");
}
else
{
Rooms.Append(wireEncoding.Encode(roomIDs[i]));
if(roomData[1] == "")
{
Rooms.Append("I");
Rooms.Append(roomData[0]);
Rooms.Append(Convert.ToChar(2));
Rooms.Append(wireEncoding.Encode(int.Parse(roomData[4])));
Rooms.Append(wireEncoding.Encode(int.Parse(roomData[5])));
Rooms.Append(wireEncoding.Encode(categoryID));
Rooms.Append(roomData[6]);
Rooms.Append(Convert.ToChar(2));
Rooms.Append(wireEncoding.Encode(roomIDs[i]));
Rooms.Append("H");
Rooms.Append(DB.runRead("SELECT casts FROM rooms WHERE id = '" + roomIDs[i] + "'"));
Rooms.Append(Convert.ToChar(2));
Rooms.Append("HI");
}
else
{
if (roomData[3] == "0" && _Username != roomData[1] && seeHiddenRoomOwners == false) // Room owner doesn't wish to show his name, and this user isn't the room owner and this user doesn't has the right to see hidden room owners, change room owner to '-'
roomData[1] = "-";
Rooms.Append(roomData[0]);
Rooms.Append(Convert.ToChar(2));
Rooms.Append(roomData[1]);
Rooms.Append(Convert.ToChar(2));
Rooms.Append(Access.getRoomAccessFlag(roomData[2]).ToString());
Rooms.Append(Convert.ToChar(2));
Rooms.Append(wireEncoding.Encode(int.Parse(roomData[4])));
Rooms.Append(wireEncoding.Encode(int.Parse(roomData[5])));
Rooms.Append(roomData[6]);
Rooms.Append(Convert.ToChar(2));
guestRoomAmount++;
}
}
}
serverMessage = new serverMessage(61);
serverMessage.Append("HHJ");
serverMessage.appendChar(2);
serverMessage.Append("HHH");
serverMessage.appendWired(guestRoomAmount - deletedAmount);
serverMessage.Append(Rooms.ToString());
this.sendMessage(serverMessage);
}
}
break;
case 19:
{
int roomID = wireEncoding.Decode(clientMessage.Content.Substring(1));
if (DB.checkExists("SELECT id FROM rooms WHERE id = '" + roomID + "'") == true && DB.checkExists("SELECT userid FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomID + "'") == false) // The virtual room does exist, and the virtual user hasn't got it in the list already
{
if (DB.runReadUnsafe("SELECT COUNT(userid) FROM users_favouriterooms WHERE userid = '" + this.userID + "'", null) < Config.Rooms_Favorites_maxPerUser)
DB.runQuery("INSERT INTO users_favouriterooms(userid,roomid) VALUES ('" + this.userID + "','" + roomID + "')");
else
sendData("@a" + "nav_error_toomanyfavrooms");
}
break;
}
break;
case "@S": // Navigator - add room to favourite rooms list
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(3));
if (DB.checkExists("SELECT id FROM rooms WHERE id = '" + roomID + "'") == true && DB.checkExists("SELECT userid FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomID + "'") == false) // The virtual room does exist, and the virtual user hasn't got it in the list already
{
if (DB.runReadUnsafe("SELECT COUNT(userid) FROM users_favouriterooms WHERE userid = '" + this.userID + "'", null) < Config.Rooms_Favorites_maxPerUser)
DB.runQuery("INSERT INTO users_favouriterooms(userid,roomid) VALUES ('" + this.userID + "','" + roomID + "')");
else
sendData("@a" + "nav_error_toomanyfavrooms");
}
break;
}
case "@T": // Navigator - remove room from favourite rooms list
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(3));
DB.runQuery("DELETE FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomID + "' LIMIT 1");
break;
case 26: // @Z * SCR_GET_USER_INFO
{
string Subscription = DB.Stripslash(clientMessage.firstParameter);
this.refreshSubscription(Subscription);
}
break;
case 36: // @d * MESSENGER_ASSIGNPERSMSG
{
string Motto = clientMessage.firstParameter;
serverMessage = new serverMessage(147);
serverMessage.appendValue(Motto);
this.sendMessage(serverMessage);
DB.runQuery("UPDATE users SET motto_console = '" + DB.Stripslash(Motto) + "' WHERE id = '" + this.userID + "' LIMIT 1");
break;
}
break;
case 44: // @l * UPDATE
{
string tmp = clientMessage.getParameter(4);
if(tmp != "" && tmp.Length == 25 && stringManager.isNumeric(tmp))
this._Figure = tmp;
tmp = clientMessage.getParameter(5);
if(tmp != "" && (tmp == "M" || tmp == "F"))
this._Sex = char.Parse(tmp);
tmp = clientMessage.getParameter(6);
if(tmp != "")
this._Motto = tmp;
serverMessage = new serverMessage(5);
serverMessage.appendPlainParameter("name",this._Username);
serverMessage.appendPlainParameter("figure",this._Figure);
serverMessage.appendPlainParameter("sex",this._Sex.ToString());
serverMessage.appendPlainParameter("customData",this._Motto);
serverMessage.appendPlainParameter("ph_tickets",this._Tickets.ToString());
serverMessage.appendPlainParameter("ph_figure","ch=s02/53,51,44");
serverMessage.appendPlainParameter("photo_film",this._Films.ToString());
serverMessage.appendPlainParameter("directMail","0");
this.sendMessage(serverMessage);
DB.runQuery("UPDATE users SET figure = '" + this._Figure + "',sex = '" + this._Sex + "',motto = '" + DB.Stripslash(this._Motto) + "' WHERE id = '" + this.userID + "' LIMIT 1");
}
break;
case 127: // A * GETUSERCREDITLOG
{
serverMessage = new serverMessage(209);
if(Config.logTransactions)
{
string[] Dates = DB.runReadColumn("SELECT date FROM users_transactions WHERE userid = '" + this.userID + "' ORDER BY id ASC", 0);
if (Dates.Length > 0)
{
int[] Activities = DB.runReadColumn("SELECT activity FROM users_transactions WHERE userid = '" + this.userID + "' ORDER BY id ASC", 0, null);
string[] Times = DB.runReadColumn("SELECT time FROM users_transactions WHERE userid = '" + this.userID + "' ORDER BY id ASC", 0);
string[] Types = DB.runReadColumn("SELECT type FROM users_transactions WHERE userid = '" + this.userID + "' ORDER BY id ASC", 0);
for (int i = 0; i < Activities.Length; i++)
{
serverMessage.appendFlatValue(Dates[i]);
serverMessage.appendFlatValue(Times[i]);
serverMessage.appendFlatValue(Activities[i].ToString());
serverMessage.Append(0);
serverMessage.Append("\t\t");
serverMessage.Append(Types[i]);
}
}
}
this.sendMessage(serverMessage);
}
break;
case 149: // BU * UPDATE_ACCOUNT
{
serverMessage = new serverMessage(169);
string Password = clientMessage.getParameter(13);
if(Password != DB.runRead("SELECT password FROM users WHERE id = '" + this.userID + "'"))
{
serverMessage.Append(1);
this.sendMessage(serverMessage);
return;
}
string DOB = clientMessage.getParameter(8);
if(DOB != DB.runRead("SELECT dob FROM users WHERE id = '" + this.userID + "'"))
{
serverMessage.Append(2);
this.sendMessage(serverMessage);
return;
}
string New = clientMessage.getParameter(3);
if(New != "") // New password set
{
if(Access.passwordOK(this._Username,New) == false)
return;
DB.runQuery("UPDATE users SET password = '" + New + "' WHERE id = '" + this.userID + "' LIMIT 1");
}
else // New email set
{
New = clientMessage.getParameter(7);
if(Access.emailOK(New) == false)
return;
DB.runQuery("UPDATE users SET email = '" + New + "' WHERE id = '" + this.userID + "' LIMIT 1");
}
serverMessage.Append(0);
this.sendMessage(serverMessage);
}
break;
case 150: // BV * NAVIGATE
{
bool hideFull = wireEncoding.decodeBoolean(clientMessage.Content.Substring(0, 1));
int cataID = wireEncoding.Decode(clientMessage.Content.Substring(1));
string cataName = DB.runRead("SELECT name FROM room_categories WHERE id = '" + cataID + "' AND (access_rank_min <= " + _Rank + " OR access_rank_hideforlower = '0')");
if (cataName == "")
return;
int cataType = DB.runRead("SELECT type FROM room_categories WHERE id = '" + cataID + "'", null);
int parentID = DB.runRead("SELECT parent FROM room_categories WHERE id = '" + cataID + "'", null);
serverMessage = new serverMessage(220);
serverMessage.appendWired(hideFull);
serverMessage.appendWired(cataID);
serverMessage.appendWired(cataType);
serverMessage.appendValue(cataName);
serverMessage.appendWired(0);
serverMessage.appendWired(10000);
serverMessage.appendWired(parentID);
string _DB_ORDERHELPER = "";
if (cataType == 0)
{
if (hideFull)
_DB_ORDERHELPER = "AND visitors_now < visitors_max ORDER BY id ASC";
else
_DB_ORDERHELPER = "ORDER BY id ASC";
}
else
{
if (hideFull)
_DB_ORDERHELPER = "AND visitors_now < visitors_max ORDER BY visitors_now DESC";
else
_DB_ORDERHELPER = "ORDER BY visitors_now DESC";
}
int[] roomIDs = DB.runReadColumn("SELECT id FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, 0, null);
if (cataType == 2) // Guestrooms
serverMessage.appendWired(roomIDs.Length);
if (roomIDs.Length > 0)
{
bool canSeeHiddenNames = false;
int[] showNameFlags = DB.runReadColumn("SELECT showname FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults, null);
int[] nowVisitors = DB.runReadColumn("SELECT visitors_now FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults, null);
int[] maxVisitors = DB.runReadColumn("SELECT visitors_max FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults, null);
int[] roomAccessLevels = DB.runReadColumn("SELECT accesslevel FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults, null);
string[] roomNames = DB.runReadColumn("SELECT name FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults);
string[] roomDescriptions = DB.runReadColumn("SELECT description FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults);
string[] roomOwners = DB.runReadColumn("SELECT owner FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults);
string[] roomCasts = null;
if (cataType == 0) // Publicroom category
roomCasts = DB.runReadColumn("SELECT casts FROM rooms WHERE category = '" + cataID + "' " + _DB_ORDERHELPER, Config.Rooms_Navigator_openCategory_maxResults);
else
canSeeHiddenNames = Access.accessRankHasFUSERight(this._Rank, this._Subscriptions, "fuse_enter_locked_rooms");
for (int i = 0; i < roomIDs.Length; i++)
{
serverMessage.appendWired(roomIDs[i]);
if (cataType == 0) // Publicroom
{
serverMessage.appendWired(true);
serverMessage.appendValue(roomNames[i]);
serverMessage.appendWired(nowVisitors[i]);
serverMessage.appendWired(maxVisitors[i]);
serverMessage.appendWired(cataID);
serverMessage.appendValue(roomDescriptions[i]);
serverMessage.appendWired(roomIDs[i]);
serverMessage.appendWired(false);
serverMessage.appendValue(roomCasts[i]);
serverMessage.appendWired(false);
serverMessage.appendWired(true);
}
else // Guestroom
{
if (showNameFlags[i] == 0 && canSeeHiddenNames == false)
roomNames[i] = "-";
serverMessage.appendValue(roomNames[i]);
serverMessage.appendValue(roomOwners[i]);
serverMessage.appendValue(Access.getRoomAccessFlag(roomAccessLevels[i]).ToString());
serverMessage.appendWired(nowVisitors[i]);
serverMessage.appendWired(maxVisitors[i]);
serverMessage.appendValue(roomDescriptions[i]);
}
}
}
int[] subCataIDs = DB.runReadColumn("SELECT id FROM room_categories WHERE parent = '" + cataID + "' AND (access_rank_min <= " + _Rank + " OR access_rank_hideforlower = '0') ORDER BY id ASC", 0, null);
if (subCataIDs.Length > 0) // Sub categories
{
for (int i = 0; i < subCataIDs.Length; i++)
{
int visitorCount = DB.runReadUnsafe("SELECT SUM(visitors_now) FROM rooms WHERE category = '" + subCataIDs[i] + "'", null);
int visitorMax = DB.runReadUnsafe("SELECT SUM(visitors_max) FROM rooms WHERE category = '" + subCataIDs[i] + "'", null);
if (visitorMax > 0 && hideFull && visitorCount >= visitorMax)
continue;
string subCataName = DB.runRead("SELECT name FROM room_categories WHERE id = '" + subCataIDs[i] + "'");
serverMessage.appendWired(subCataIDs[i]);
serverMessage.appendWired(false);
serverMessage.appendValue(subCataName);
serverMessage.appendWired(visitorCount);
serverMessage.appendWired(visitorMax);
serverMessage.appendWired(cataID);
}
}
this.sendMessage(serverMessage);
}
break;
case 151: // BW * GETUSERFLATCATS
{
serverMessage = new serverMessage(221);
int[] IDs = DB.runReadColumn("SELECT id FROM room_categories WHERE type = '2' AND parent > 0 AND access_rank_min <= " + this._Rank + " ORDER BY id ASC", 0, null);
string[] Names = DB.runReadColumn("SELECT name FROM room_categories WHERE type = '2' AND parent > 0 AND access_rank_min <= " + this._Rank + " ORDER BY id ASC", 0);
serverMessage.appendWired(IDs.Length);
for (int i = 0; i < IDs.Length; i++)
{
serverMessage.appendWired(IDs[i]);
serverMessage.appendValue(Names[i]);
}
this.sendMessage(serverMessage);
}
break;
case 157: // B] * GETAVAILABLEBADGES
this.refreshBadges();
break;
case 190: // B * SCR_BUY
{
string Subscription = DB.Stripslash(clientMessage.firstParameter);
int Choice = wireEncoding.Decode(clientMessage.Content.Substring(Subscription.Length + 2));
int Cost = DB.runRead("SELECT cost FROM duck_subscriptions WHERE subscription = '" + Subscription + "' AND choice = '" + Choice + "'", null);
int Months = DB.runRead("SELECT months FROM duck_subscriptions WHERE subscription = '" + Subscription + "' AND choice = '" + Choice + "'", null);
if (Cost > 0 && Months > 0) // Subscription exists
{
if (Cost > this._Credits)
{
serverMessage = new serverMessage(52);
serverMessage.appendPlainParameter("t","522");
serverMessage.appendPlainParameter("p","0");
this.sendMessage(serverMessage);
}
else
{
this._Credits -= Cost;
DB.runQuery("UPDATE users SET credits = '" + this._Credits + "' WHERE id = '" + this.userID + "' LIMIT 1");
if (Config.logTransactions)
Access.logTransaction(this.userID, Subscription, -Cost);
if (DB.checkExists("SELECT userid FROM users_subscriptions WHERE userid = '" + this.userID + "' AND subscription = '" + Subscription + "'"))
DB.runQuery("UPDATE users_subscriptions SET active = '1',months_left = months_left + " + Months + " WHERE userid = '" + this.userID + "' AND subscription = '" + Subscription + "' LIMIT 1");
else
DB.runQuery("INSERT INTO users_subscriptions (userid,subscription,active,months_expired,months_left,date_monthstarted) VALUES ('" + this.userID + "','" + Subscription + "','1','0','" + Months + "','" + DateTime.Now.ToShortDateString() + "')");
string[] Badges = DB.runReadColumn("SELECT badge FROM duck_subscriptions_badges WHERE subscription = '" + Subscription + "' AND months_passed = '0'", 0);
if (Badges.Length > 0)
{
foreach (string b in Badges)
if (DB.checkExists("SELECT userid FROM users_badges WHERE userid = '" + this.userID + "' AND badge = '" + b + "'") == false)
DB.runQuery("INSERT INTO users_badges(userid,badge,iscurrent,subscription) VALUES ('" + this.userID + "','" + b + "','0','" + Subscription + "')");
this.refreshBadges();
}
string[] itemSprites = DB.runReadColumn("SELECT sprite FROM duck_subscriptions_items WHERE subscription = '" + Subscription + "' AND months_passed = '0'", 0);
{
}
this._Subscriptions = DB.runReadColumn("SELECT subscription FROM users_subscriptions WHERE userid = '" + this.userID + "' AND active = '1'", 0);
serverMessage = new serverMessage(6);
serverMessage.Append(this._Credits);
serverMessage.Append(".0");
this.sendMessage(serverMessage);
serverMessage = new serverMessage(2);
serverMessage.Append(Access.getFUSERights(this._Rank, this._Subscriptions));
this.sendMessage(serverMessage);
this.refreshSubscription(Subscription);
}
}
}
break;
case 192: // BA * REDEEM_VOUCHER
{
string Code = DB.Stripslash(clientMessage.firstParameter);
string[] Data = DB.runReadRow("SELECT type,value FROM duck_vouchers WHERE code = '" + Code + "'");
if (Data.Length > 0)
{
DB.runQuery("DELETE FROM duck_vouchers WHERE code = '" + Code + "' LIMIT 1");
if (Data[0] == "credits")
{
int Amount = int.Parse(Data[1]);
this._Credits += Amount;
serverMessage = new serverMessage(6);
serverMessage.Append(this._Credits);
serverMessage.Append(".0");
this.sendMessage(serverMessage);
serverMessage = new serverMessage(212);
this.sendMessage(serverMessage);
DB.runQuery("UPDATE users SET credits = '" + this._Credits + "' WHERE id = '" + this.userID + "' LIMIT 1");
if (Config.logTransactions)
Access.logTransaction(this.userID, "win_voucher", Amount);
}
else if (Data[0] == "item")
{
}
}
else
{
serverMessage = new serverMessage(213);
serverMessage.Append(1); // [1]: voucher not found
this.sendMessage(serverMessage);
}
}
break;
case 196: // CD * PONG
pingOK = true;
break;
case 203: // CK * APPROVE_PASSWORD
{
string[] s = clientMessage.Parameters;
serverMessage = new serverMessage(282);
serverMessage.appendWired(!Access.passwordOK(s[0], s[1]));
this.sendMessage(serverMessage);
}
break;
//case "@U": // Navigator - get guestroom details
// {
// int roomID = int.Parse(currentPacket.Substring(2));
// string[] roomDetails = DB.runReadRow("SELECT name,owner,description,model,accesslevel,superusers,showname,category,visitors_now,visitors_max FROM rooms WHERE id = '" + roomID + "' AND NOT(owner IS NULL)");
//
// if (roomDetails.Length > 0) // Guestroom does exist
// {
// if (roomDetails[6] == "0" && Access.accessRankHasFUSERight(this._Rank, this._Subscriptions, "fuse_see_all_room_owners") == false) // The room owner has decided to hide his name at this room, and this user hasn't got the fuseright to see all room owners, hide the name
// roomDetails[1] = "-";
///
// sendData("@v"
// + Encoding.encodeVL64(int.Parse(roomDetails[5]))
// + Encoding.encodeVL64(int.Parse(roomDetails[4]))
// + Encoding.encodeVL64(roomID)
// + roomDetails[1] + Convert.ToChar(2)
/// + "model_" + roomDetails[3] + Convert.ToChar(2)
// + roomDetails[0] + Convert.ToChar(2)
// + roomDetails[2] + Convert.ToChar(2)
/// + Encoding.encodeVL64(int.Parse(roomDetails[6]))
/// + Encoding.encodeVL64(DB.checkExists("SELECT id FROM room_categories WHERE id = '" + roomDetails[7] + "' AND trading = '1'"))
// + Encoding.encodeVL64(int.Parse(roomDetails[8])) + Encoding.encodeVL64(int.Parse(roomDetails[9])));
}
break;
}
case "@S": // Navigator - add room to favourite rooms list
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(3));
if (DB.checkExists("SELECT id FROM rooms WHERE id = '" + roomID + "'") == true && DB.checkExists("SELECT userid FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomID + "'") == false) // The virtual room does exist, and the virtual user hasn't got it in the list already
{
if (DB.runReadUnsafe("SELECT COUNT(userid) FROM users_favouriterooms WHERE userid = '" + this.userID + "'", null) < Config.Rooms_Favorites_maxPerUser)
DB.runQuery("INSERT INTO users_favouriterooms(userid,roomid) VALUES ('" + this.userID + "','" + roomID + "')");
else
sendData("@a" + "nav_error_toomanyfavrooms");
}
break;
}
case "@T": // Navigator - remove room from favourite rooms list
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(3));
DB.runQuery("DELETE FROM users_favouriterooms WHERE userid = '" + this.userID + "' AND roomid = '" + roomID + "' LIMIT 1");
break;
}
#endregion
#region Guestroom creating & modifying
case "@]": // Guestrooms - create guestroom
{
string[] roomSettings = currentPacket.Split('/');
if (DB.runRead("SELECT COUNT(id) FROM rooms WHERE owner = '" + this._Username + "'", null) < Config.Rooms_guestRooms_maxPerUser)
{
roomSettings[3] = roomSettings[3].Substring(6, 1); // Model
DB.runQuery("INSERT INTO rooms (name,owner,model,accesslevel,showname) VALUES ('" + DB.Stripslash(roomSettings[2]) + "','" + this._Username + "','" + Access.getRoomAccessFlag(roomSettings[3]) + "','" + roomSettings[4] + "','" + roomSettings[5] + "')");
string roomID = DB.runRead("SELECT MAX(id) FROM rooms WHERE owner = '" + this._Username + "'");
sendData("@{" + roomID + Convert.ToChar(13) + roomSettings[2]);
}
else
sendData("@a" + "Error creating a private room");
break;
}
case "@Y": // Guestrooms - modify guestroom
{
int roomID = 0;
if (currentPacket.Substring(2, 1) == "/")
roomID = int.Parse(currentPacket.Split('/')[1]);
else
roomID = int.Parse(currentPacket.Substring(2).Split('/')[0]);
int superUsers = 0;
int maxVisitors = 25;
string[] Settings = currentPacket.Split(Convert.ToChar(13));
string roomDescription = "";
string roomPassword = "";
for (int i = 1; i < Settings.Length; i++)
{
string updHeader = Settings[i].Split('=')[0];
string updValue = Settings[i].Substring(updHeader.Length + 1);
switch (updHeader)
{
case "description":
roomDescription = DB.Stripslash(updValue);
break;
case "allsuperuser":
if (updValue == "1")
superUsers = 1;
break;
case "maxvisitors":
maxVisitors = int.Parse(updValue);
if (maxVisitors < 10 || maxVisitors > 25)
maxVisitors = 25;
break;
case "password":
roomPassword = DB.Stripslash(updValue);
break;
default:
return;
}
}
DB.runQuery("UPDATE rooms SET description = '" + roomDescription + "',superusers = '" + superUsers + "',visitors_max = '" + maxVisitors + "',password = '" + roomPassword + "' WHERE id = '" + roomID + "' AND owner = '" + this._Username + "' LIMIT 1");
break;
}
case "@X": // Guestrooms - modify guestroom - save name, access level and show/hide ownername
{
string[] Settings = currentPacket.Substring(2).Split('/');
int roomID = int.Parse(Settings[0]);
string roomName = DB.Stripslash(Settings[1]);
char showName = '1';
if (Settings[3] != "1")
showName = '0';
int accessLevel = Access.convertRoomAccessFlag(Settings[2]);
DB.runQuery("UPDATE rooms SET name = '" + roomName + "',accesslevel = '" + accessLevel + "',showname = '" + showName + "' WHERE id = '" + roomID + "' AND owner = '" + _Username + "' LIMIT 1");
break;
}
case "@W": // Guestrooms - delete guestroom
{
sendData("BK" + "Sorry, but you can't delete guestrooms yet!\r\r- Pedobear");
break;
}
case "BX": // Guestrooms - trigger guestroom modify
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(2));
string roomCategory = DB.runRead("SELECT category FROM rooms WHERE id = '" + roomID + "' AND owner = '" + _Username + "'");
if (roomCategory != "")
sendData("C^" + Encoding.encodeVL64(roomID) + Encoding.encodeVL64(int.Parse(roomCategory)));
break;
}
case "BY": // Guestrooms - edit category
{
int roomID = Encoding.decodeVL64(currentPacket.Substring(2));
int cataID = Encoding.decodeVL64(currentPacket.Substring(Encoding.encodeVL64(roomID).Length + 2));
if (DB.checkExists("SELECT id FROM room_categories WHERE id = '" + cataID + "' AND type = '2' AND parent > 0 AND access_rank_min <= " + this._Rank)) // Category is valid for this user
DB.runQuery("UPDATE rooms SET category = '" + cataID + "' WHERE id = '" + roomID + "' AND owner = '" + this._Username + "' LIMIT 1");
break;
}
#endregion
#endregion
}
}
#endregion
}
#endregion
#region Misc
private void Login(string Username, string Password)
{
string[] Data = DB.runReadRow("SELECT id,username,password,rank FROM users WHERE username = '" + Username + "'");
if (Data.Length > 0)
{
if (Data[2] == Password)
{
this.userID = int.Parse(Data[0]);
this._Username = Data[1];
this._Rank = byte.Parse(Data[3]);
this._Subscriptions = DB.runReadColumn("SELECT subscription FROM users_subscriptions WHERE userid = '" + this.userID + "' AND active = '1'", 0);
userManager.addUser(this.userID, this);
sendData("@B" + Access.getFUSERights(this._Rank, this._Subscriptions));
sendData("@C");
return;
}
else
sendData("@a" + "login incorrect: Wrong password");
}
else
sendData("@a" + "login incorrect: Wrong username");
this.Disconnect(1000);
}
///
/// Refreshes the user's badges and resends the packet.
///
private void refreshBadges()
{
int Slot = 0;
int Show = 0;
string[] Badges = DB.runReadColumn("SELECT badge FROM users_badges WHERE userid = '" + this.userID + "'", 0);
StringBuilder List = new StringBuilder();
if (Badges.Length > 0)
{
Show = DB.runRead("SELECT showbadge FROM users WHERE id = '" + this.userID + "'", null);
string Current = DB.runReadUnsafe("SELECT badge FROM users_badges WHERE userid = '" + this.userID + "' AND current = '1'");
for (int i = 0; i < Badges.Length; i++)
{
List.Append(Badges[i] + Convert.ToChar(2));
if (Badges[i] == Current)
Slot = i;
}
if (Show == 1)
this._Badge = Current;
}
sendData("Ce" + Encoding.encodeVL64(Badges.Length) + List.ToString() + Encoding.encodeVL64(Slot) + Encoding.encodeVL64(Show));
}
///
/// Refreshes the status of a certain user subscription.
///
/// The subscription to refresh, eg, 'club_habbo'.
private void refreshSubscription(string Subscription)
{
int restingDays = 0;
int passedMonths = 0;
int restingMonths = 0;
string[] subscrDetails = DB.runReadRow("SELECT months_expired,months_left,date_monthstarted FROM users_subscriptions WHERE userid = '" + userID + "' AND subscription = '" + Subscription + "' AND active = '1'");
if (subscrDetails.Length > 0)
{
passedMonths = int.Parse(subscrDetails[0]);
restingMonths = int.Parse(subscrDetails[1]) - 1;
restingDays = (int)(DateTime.Parse(subscrDetails[2])).Subtract(DateTime.Now).TotalDays + 31;
if (restingDays <= 0) // Month expired
#region Month expiring, badges, presents etc
{
if (restingMonths > 0) // Next month on stack
{
passedMonths++;
restingMonths--;
restingDays = 31;
DB.runQuery("UPDATE users_subscriptions SET months_expired = months_expired + 1,months_left = months_left - 1,date_monthstarted = '" + DateTime.Now.ToShortDateString() + "' WHERE userid = '" + userID + "' AND subscription = '" + Subscription + "' LIMIT 1");
string[] Badges = DB.runReadColumn("SELECT badge FROM duck_subscriptions_badges WHERE subscription = '" + Subscription + "' AND months_passed = '" + passedMonths + "'", 0);
if (Badges.Length > 0)
{
foreach (string b in Badges)
if (DB.checkExists("SELECT userid FROM users_badges WHERE userid = '" + this.userID + "' AND badge = '" + b + "'") == false)
DB.runQuery("INSERT INTO users_badges(userid,badge,iscurrent,subscription) VALUES ('" + this.userID + "','" + b + "','0','" + Subscription + "')");
this.refreshBadges();
}
string[] itemSprites = DB.runReadColumn("SELECT sprite FROM duck_subscriptions_items WHERE subscription = '" + Subscription + "' AND months_passed = '" + passedMonths + "'", 0);
}
else // Subscription ended
{
DB.runQuery("UPDATE users_subscriptions SET active = '0' WHERE userid = '" + this.userID + "' AND subscription = '" + Subscription + "' LIMIT 1"); // Set the status of the subscription to 'inactive'
DB.runQuery("DELETE FROM users_badges WHERE userid = '" + this.userID + "' AND subscription = '" + Subscription + "'"); // Remove this badges subscriptions
this._Subscriptions = DB.runReadColumn("SELECT subscription FROM users_subscriptions WHERE userid = '" + this.userID + "' AND active = '1'",0);
serverMessage Message = new serverMessage(2);
Message.Append(Access.getFUSERights(this._Rank, this._Subscriptions));
}
}
#endregion
}
serverMessage Message = new serverMessage(7);
Message.appendValue(Subscription);
Message.appendWired(restingDays);
Message.appendWired(passedMonths);
Message.appendWired(restingMonths);
Message.appendWired(true); // Hide/show 'days left'
this.sendMessage(Message);
}
#endregion
}
}