static void ClientRead(Server s, Client c, byte[] e) { try { //Anti-flood measures. if (c.Value.IsFlooding()) { c.Disconnect(); return; } object[] values = Packer.Deserialize(e); if (values == null) return; ClientPacket packet = (ClientPacket)values[0]; if (c.Value.Authenticated && c.Value.Verified) { switch (packet) { case ClientPacket.Channel: HandleWakeup(c, true); //Supress the packet send here since we are changing rooms anyways. HandleChannelPacket(c, (byte)values[1]); break; case ClientPacket.ChatMessage: HandleWakeup(c); HandleChatPacket(c, (string)values[1]); break; case ClientPacket.PM: HandleWakeup(c); HandlePMPacket(c, (string)values[1], (string)values[2], (string)values[3], values.Length == 5 ? (ushort)values[4] : default(ushort)); break; case ClientPacket.KeepAlive: HandleKeepAlivePacket(c); break; case ClientPacket.News: HandleNewsPacket(c); break; case ClientPacket.ViewProfile: HandleViewProfilePacket(c, (string)values[1]); break; case ClientPacket.EditProfile: HandleEditProfilePacket(c, (string)values[1], (string)values[2], (string)values[3]); break; case ClientPacket.AuthCode: HandleAuthCodePacket(c, (string) values[1]); break; } } else { switch (packet) { case ClientPacket.SignIn: HandleSignInPacket(c, (string)values[1], (string)values[2]); break; case ClientPacket.Register: HandleRegisterPacket(c, (string)values[1], (string)values[2], (string)values[3]); break; case ClientPacket.ResendVerification: HandleResendVerificationPacket(c); break; case ClientPacket.AuthCode: HandleAuthCodePacket(c, (string) values[1]); break; } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); c.Disconnect(); } }
private void OnClient_Read(Client c, byte[] e) { if (Client_Read != null) { Client_Read(this, c, e); } }
private void OnClient_Write(Client c) { if (Client_Write != null) { Client_Write(this, c); } }
static void SendLoginBarrage(Client c) { SendChannelList(c); SendUserListUpdates(c, c.Value.Channel); string MOTD = GetMOTD(); if (!string.IsNullOrEmpty(MOTD)) { byte[] data = Packer.Serialize((byte)ServerPacket.MOTD, MOTD); c.Send(data); } }
static void Client_Read(Server s, Client c, byte[] e) { try { object[] values = Packer.Deserialize(e); ClientPacket packet = (ClientPacket)values[0]; if (c.Value.Authenticated) { switch (packet) { case ClientPacket.Channel: HandleChannelPacket(c, (byte)values[1]); break; case ClientPacket.ChatMessage: HandleChatPacket(c, (string)values[1]); break; } } else { switch (packet) { case ClientPacket.SignIn: HandleSignInPacket(c, (string)values[1], (string)values[2]); break; case ClientPacket.Register: HandleRegisterPacket(c, (string)values[1], (string)values[2]); break; } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); c.Disconnect(); } }
static void HandleChatPacket(Client c, string message) { if (GetUserLevel(c.Value.Username) & message.Contains("~")) { Console.WriteLine(c.Value.Username + " executed admin command. Command: " + message); ProcessCommand(message); } else { byte[] data = Packer.Serialize((byte)ServerPacket.Chatter, c.Value.UserID, message); BroadcastExclusive(c.Value.UserID, c.Value.Channel, data); } }
//TODO: Don't disconnect people, instead return an error code. static void HandleSignInPacket(Client c, string name, string pass) { if (name.Length == 0 || name.Length > 16 || pass.Length != 40) { c.Disconnect(); return; } //Don't let them join if they were banned. GetBanList(); if (BanList.Contains(name.ToLower(), StringComparer.OrdinalIgnoreCase)) { c.Disconnect(); return; } MySqlCommand q = new MySqlCommand(string.Empty, SQL); q.CommandText = "SELECT Count(*) FROM users WHERE Username=@Username AND Password=@Password;"; q.Parameters.AddWithValue("@Username", name); q.Parameters.AddWithValue("@Password", pass); MySqlDataReader r = q.ExecuteReader(); bool success = r.Read() && (r.GetInt16("Count(*)") != 0); r.Close(); byte[] data = Packer.Serialize((byte)ServerPacket.SignIn, success); c.Send(data); if (success) { //If this user is already logged in from somewhere else then disconnect them. Client existing = ClientFromUsername(name); if (existing != null) { existing.Disconnect(); } c.Value.UserID = RunningID++; c.Value.Username = name; c.Value.Authenticated = true; SendLoginBarrage(c); } }
static void HandleKeepAlivePacket(Client c) { byte[] data = Packer.Serialize((byte)ServerPacket.KeepAlive); c.Send(data); }
static void HandleNewsPacket(Client c) { byte[] data = Packer.Serialize((byte)ServerPacket.News, GetNews()); c.Send(data); }
static void HandleChatPacket(Client c, string message) { if (!IsValidData(message)) { c.Disconnect(); return; } if (CheckCommand(c, message)) { //byte[] confirmCommand = Packer.Serialize((byte)ServerPacket.) return; } c.Value.AddPoints(5); //AWARD 5 POINTS FOR ACTIVITY*** if (RecentMessages.Count == 10) RecentMessages.RemoveAt(0); ChatMessage msg = new ChatMessage(DateTime.Now.ToLocalTime().ToString(), message, c.Value.Username, c.Value.Rank); RecentMessages.Add(msg); byte[] data = Packer.Serialize((byte)ServerPacket.Chatter, c.Value.UserId, message); BroadcastExclusive(c.Value.UserId, c.Value.Channel, data, c); }
static void HandleEditProfilePacket(Client c, string avatar, string bio, string profile) { if (!(avatar.Contains("http://") || avatar.Contains("https://"))) avatar = avatar.Insert(0, "http://"); if (!(profile.Contains("http://") || profile.Contains("https://"))) profile = profile.Insert(0, "http://"); bool validProfile = Regex.IsMatch(profile, @"^(http:\/\/|https:\/\/)*(www\.)*hackforums\.net\/member\.php\?action=profile&uid=\d{1,7}$"); MySqlCommand q = new MySqlCommand("UPDATE users SET Avatar=@Avatar, Bio=@Bio, ProfileLink=@ProfileLink WHERE Username=@Username;", SQL); q.Parameters.AddWithValue("@Username", c.Value.Username); q.Parameters.AddWithValue("@Bio", bio); q.Parameters.AddWithValue("@Avatar", avatar); q.Parameters.AddWithValue("@ProfileLink", validProfile ? profile : ""); bool success = q.ExecuteNonQuery() == 0; byte[] data = Packer.Serialize((byte)ServerPacket.EditProfile, success); c.Send(data); }
static void HandleChannelPacket(Client c, byte channel) { if (channel < Channels.Length) { //Let everyone in the old channel know this guy left. byte[] data = Packer.Serialize((byte)ServerPacket.UserLeave, c.Value.UserId); Broadcast(c.Value.Channel, data); c.Value.Channel = channel; SendUserListUpdates(c); } else { c.Disconnect(); return; } }
static void HandleAuthCodePacket(Client c, string authCode) { MySqlCommand q = new MySqlCommand("SELECT AuthType, Value FROM authcodes WHERE (User=@Username) AND Value=@Value;", SQL); q.Parameters.AddWithValue("@Username", c.Value.Username); q.Parameters.AddWithValue("@Value", authCode); MySqlDataReader r = q.ExecuteReader(); bool read = r.Read() && r.HasRows; if (read) { AuthType authType = (AuthType) r.GetByte("AuthType"); r.Close(); q.CommandText = "DELETE FROM `authcodes` WHERE `Value`=@Value AND `User`=@Username LIMIT 1;"; bool success = q.ExecuteNonQuery() != 0; byte[] data = Packer.Serialize((byte) ServerPacket.AuthResponse,(byte)authType, success); c.Send(data); } else { byte[] data = Packer.Serialize((byte) ServerPacket.AuthResponse, (byte)AuthType.Unknown, false); c.Send(data); } }
static void ClientState(Server s, Client c, bool open) { if (open) { c.Value = new UserState(); if (!string.IsNullOrEmpty(MOTD)) { byte[] data = Packer.Serialize((byte)ServerPacket.MOTD, MOTD); c.Send(data); } } else { if (c.Value.Authenticated) { byte[] data = Packer.Serialize((byte)ServerPacket.UserLeave, c.Value.UserId); Broadcast(c.Value.Channel, data); AwardPoints(c); //Let's save the users data. MySqlCommand q = new MySqlCommand(string.Empty, SQL); q.CommandText = "UPDATE users SET Points=@Points,Rank=@Rank,Mute=@Mute WHERE Username=@Username;"; q.Parameters.AddWithValue("@Points", c.Value.Points); q.Parameters.AddWithValue("@Rank", c.Value.Rank); q.Parameters.AddWithValue("@Mute", c.Value.Mute); q.Parameters.AddWithValue("@Username", c.Value.Username); //If it fails there isn't much we can do about it. q.ExecuteNonQuery(); } } }
static void Client_State(Server s, Client c, bool open) { if (open) { c.Value = new UserState(); } else { if (c.Value.Authenticated) { byte[] data = Packer.Serialize((byte)ServerPacket.UserLeave, c.Value.UserID, c.Value.Username); Broadcast(c.Value.Channel, data); } } }
static void HandlePMPacket(Client c, string recipient, string message, string subject, ushort id = default(ushort)) { if (!(IsValidName(recipient) && IsValidData(message) && IsValidData(subject))) { c.Disconnect(); return; } Client u = ClientFromUsername(recipient); if (u == null) return; PrivateMessage pm = null; if (id == default(ushort) && !privateMessages.Exists(x => x.Id == id)) { pm = new PrivateMessage(id = (ushort)_random.Next(ushort.MinValue, ushort.MaxValue), subject, c.Value.Username, DateTime.Now, message); privateMessages.Add(pm); byte[] confirm = Packer.Serialize((byte)ServerPacket.PMConfirm, id, u.Value.Username, message, subject, DateTime.Now); c.Send(confirm); } else { pm = privateMessages.Find(x => x.Id == id); pm.Message.Add(message); } byte[] data = Packer.Serialize((byte)ServerPacket.PM, id, c.Value.Username, u.Value.Username, message, subject, DateTime.Now); u.Send(data); }
static void HandleChannelPacket(Client c, byte channel) { if (channel < Channels.Length) { byte oldChannel = c.Value.Channel; c.Value.Channel = channel; SendUserListUpdates(c, oldChannel); } else { c.Disconnect(); return; } }
static void HandleRegisterPacket(Client c, string name, string pass, string email) { string n = name.Trim(); if (n.Length == 0 || n.Length > 16 || pass.Length != 40 || !IsValidName(n) || email.Length == 0 || email.Length > 256) { byte[] fail = Packer.Serialize((byte)ServerPacket.Register, false); c.Send(fail); return; } MySqlCommand q = new MySqlCommand("SELECT Count(*) FROM users WHERE Username=@Username", SQL); q.Parameters.AddWithValue("@Username", n); MySqlDataReader r = q.ExecuteReader(); bool available = r.Read() && (r.GetInt16(0) == 0); r.Close(); if (available) { MySqlCommand q2 = new MySqlCommand(string.Empty, SQL); q2.CommandText = "INSERT INTO users VALUES (@Username,@Password,@Email,0,0,0,0,\"\",\"\",\"\");"; q2.Parameters.AddWithValue("@Username", n); q2.Parameters.AddWithValue("@Password", pass); q2.Parameters.AddWithValue("@Email", email); //If registration fails, this will return false. bool success = (q2.ExecuteNonQuery() != 0); if (success) { c.Value.Username = name; c.Value.Email = email; SendEmail(email, n); } byte[] data = Packer.Serialize((byte)ServerPacket.Register, success); c.Send(data); } else { byte[] data = Packer.Serialize((byte)ServerPacket.Register, false); c.Send(data); } }
static void HandleRegisterPacket(Client c, string name, string pass) { if (name.Length == 0 || name.Length > 16 || pass.Length != 40) { c.Disconnect(); return; } MySqlCommand q = new MySqlCommand(string.Empty, SQL); q.CommandText = "INSERT INTO users VALUES (@Username,@Password);"; q.Parameters.AddWithValue("@Username", name); q.Parameters.AddWithValue("@Password", pass); bool success = (q.ExecuteNonQuery() != 0); byte[] data = Packer.Serialize((byte)ServerPacket.Register, success); c.Send(data); }
static void HandleResendVerificationPacket(Client c) { MySqlCommand q = new MySqlCommand("SELECT * FROM authcodes WHERE User=@User AND AuthType=1", SQL); q.Parameters.AddWithValue("@User", c.Value.Username); MySqlDataReader r = q.ExecuteReader(); bool available = r.Read(); if (!available) return; string authCode = r.GetString("Value"); SendEmail(c.Value.Email, c.Value.Username, authCode); }
static void SendChannelList(Client c) { List<object> values = new List<object>(); values.Add((byte)ServerPacket.ChannelList); values.AddRange(Channels); byte[] data = Packer.Serialize(values.ToArray()); c.Send(data); }
//TODO: Don't disconnect people, instead return an error code. static void HandleSignInPacket(Client c, string name, string pass) { string n = name.Trim(); if (n.Length == 0 || n.Length > 16 || pass.Length != 40 || !IsValidName(n)) { byte[] fail = Packer.Serialize((byte)ServerPacket.SignIn, false, false); c.Send(fail); return; } MySqlCommand q = new MySqlCommand("SELECT Points, Username, Rank, Ban, Mute, Email FROM users WHERE (Username=@Username OR Email=@Username) AND Password=@Password;", SQL); q.Parameters.AddWithValue("@Username", n); q.Parameters.AddWithValue("@Password", pass); MySqlDataReader r = q.ExecuteReader(); bool success = r.Read(); if (success) { int points = r.GetInt32("Points"); byte rank = r.GetByte("Rank"); bool ban = r.GetBoolean("Ban"); string email = r.GetString("Email"); string username = r.GetString("Username"); r.Close(); //TODO: Restructure this. r.Dispose(); if (ban) { c.Disconnect(); return; } //Second ban check, checks ip table. q = new MySqlCommand(string.Empty, SQL) {CommandText = "SELECT * FROM ipbans WHERE ip=@ip;"}; q.Parameters.AddWithValue("@ip", c.EndPoint.Address.ToString()); r = q.ExecuteReader(); bool sCheck = r.Read(); r.Close(); if (sCheck) { c.Disconnect(); return; } q = new MySqlCommand("SELECT * FROM authcodes WHERE User=@User;", SQL); q.Parameters.AddWithValue("@User", username); r = q.ExecuteReader(); //Pending email verification bool unverified = r.Read() && r.GetByte("AuthType") == (byte)AuthType.AccountVerification; r.Close(); if (unverified) { byte[] notVerified = Packer.Serialize((byte)ServerPacket.NotVerified); c.Send(notVerified); } byte[] data = Packer.Serialize((byte)ServerPacket.SignIn, true, !unverified); c.Send(data); //If this user is already logged in from somewhere else then disconnect them. Client existing = ClientFromUsername(n); if (existing != null && existing != c) { existing.Disconnect(); } c.Value.UserId = RunningID++; c.Value.Username = username; c.Value.Points = points; c.Value.Rank = rank; c.Value.Mute = new List<Client>(); c.Value.LastPayout = DateTime.Now; c.Value.LastAction = DateTime.Now; c.Value.Email = email; c.Value.Authenticated = true; c.Value.Verified = !unverified; if (!unverified) { SendProfile(c); SendLoginBarrage(c); } } else { r.Close();//TODO: Restructure this. byte[] data1 = Packer.Serialize((byte)ServerPacket.SignIn, false, false); c.Send(data1); } }
static void SendUserListUpdates(Client c, byte oldChannel) { try { byte[] data1 = Packer.Serialize((byte)ServerPacket.UserJoin, c.Value.UserID, c.Value.Username); BroadcastExclusive(c.Value.UserID, c.Value.Channel, data1); List<object> cValues = new List<object>(); cValues.Add((byte)ServerPacket.UserList); //Send updates to old channel. List<object> oldValues = new List<object>(); oldValues.Add((byte)ServerPacket.UserList); foreach (Client u in Listener.Clients) { if (u.Value.Authenticated && u.Value.Channel == c.Value.Channel) { cValues.Add(u.Value.UserID); cValues.Add(u.Value.Username); } else { oldValues.Add(u.Value.UserID); oldValues.Add(u.Value.Username); } } byte[] data2 = Packer.Serialize(cValues.ToArray()); c.Send(data2); if (oldValues.Count > 1) { byte[] data3 = Packer.Serialize(oldValues.ToArray()); Broadcast(oldChannel, data3); } } catch { } }
static void HandleViewProfilePacket(Client c, string username) { Client to = ClientFromUsername(username); if (to != null) SendProfileTo(c, to); }
private void HandleState(Client s, bool open) { lock (_Clients) { _Clients.Remove(s); if (Client_State != null) { Client_State(this, s, false); } } }
static void HandleWakeup(Client c, bool suppress = false) { c.Value.LastAction = DateTime.Now; if (!c.Value.Idle) return; c.Value.Idle = false; if (suppress) return; byte[] data = Packer.Serialize((byte)ServerPacket.WakeUp, c.Value.UserId); Broadcast(c.Value.Channel, data); }
private void OnClient_State(Client c, bool open) { if (Client_State != null) { Client_State(this, c, open); } }
static void MuteUser(Client c, string name, bool global) { Client muted = ClientFromUsername(name); if (muted != null) { if (global) { foreach (Client x in Listener.Clients) { if (x != muted) x.Value.Mute.Add(muted); return; } } c.Value.Mute.Add(muted); Console.WriteLine(name + " has been muted by " + c.Value.Username); } }
private void Process(object s, SocketAsyncEventArgs e) { try { if (e.SocketError == SocketError.Success) { Client T = new Client(e.AcceptSocket, Size); lock (_Clients ){ if (_Clients.Count < MaxConnections) { _Clients.Add(T); T.Client_State += (Client x, bool y) => HandleState(x, y); T.Client_Read += (Client x, byte[] y) => OnClient_Read(x, y); T.Client_Write += (Client x) => OnClient_Write(x); if (Client_State != null) { Client_State(this, T, true); } } else { T.Disconnect(); } } e.AcceptSocket = null; if (!Handle.AcceptAsync(e)) Process(null, e); } else { Disconnect(); } } catch { Disconnect(); } }
static bool CheckCommand(Client c, string query) { string[] args = ParseArguments(query); string command = args[0].ToLower(); if (command[0] == '/') { command = command.Substring(1, command.Length - 1); if (AdminCommands.Contains(command) && (c == null /*This is only null if typed directly into the console.*/ || c.Value.Rank == (byte)SpecialRank.Admin)) { //TODO: Find a better way to do this. switch (command) { case "kick": if (args.Length == 2) { if (KickUser(args[1])) return true; } break; case "ban": if (BanUser(args[1], args.Length == 3 && args[2] == 1.ToString() ? 1 : 0)) return true; break; case "unban": if (args.Length == 2) { if (UnbanUser(args[1])) return true; } break; case "globalmsg": if (args.Length == 2) { byte[] data = Packer.Serialize((byte)ServerPacket.GlobalMsg, args[1]); GlobalBroadcast(data); return true; } break; case "setlevel": if (args.Length == 3) { if (SetUserRank(args[1], args[2])) return true; } break; case "globalmute": if (args.Length == 2 && args[1] != c.Value.Username) { MuteUser(c, args[1], true); return true; } break; case "globalunmute": if (args.Length == 2 && args[1] != c.Value.Username) { UnmuteUser(c, args[1], true); return true; } break; case "updatemotd": MOTD = GetMOTD(); return true; case "shutdown": UpdateAndSaveUsers(true); Environment.Exit(0); break; case "cls": ClearChat(); break; } } if (UserCommands.Contains(command)) { switch (command) { case "mute": if (args.Length == 2 && args[1] != c.Value.Username) { MuteUser(c, args[1], false); return true; } break; case "unmute": if (args.Length == 2 && args[1] != c.Value.Username) { UnmuteUser(c, args[1], false); return true; } break; } } } return false; }