public bool DispatchCommand(CommandContext ctx) { string channelName = ctx.Args.ElementAtOrDefault(1); // no error, apparently if (string.IsNullOrWhiteSpace(channelName)) { return(false); } Channels.GetChannelByName(channelName, channel => { // the original server sends ForceChannel before sending the error message, but this order probably makes more sense. // NEW: REVERT THIS ^^^^ WHEN CONVERTING BACK TO NOT EXCEPTIONS // EXCEPTIONS ARE HEAVY, DON'T USE THEM FOR USER ERRORS YOU IDIOT if (channel == null) { Sessions.SwitchChannel(ctx.Session); throw new ChannelNotFoundCommandException(channelName); } ChannelUsers.HasUser(channel, ctx.User, hasUser => { if (hasUser) { Sessions.SwitchChannel(ctx.Session); throw new AlreadyInChannelCommandException(channel); } string password = string.Join(' ', ctx.Args.Skip(2)); if (!ctx.User.Can(UserPermissions.JoinAnyChannel) && channel.OwnerId != ctx.User.UserId) { if (channel.MinimumRank > ctx.User.Rank) { Sessions.SwitchChannel(ctx.Session); throw new ChannelRankCommandException(channel); } // add capacity check Channels.VerifyPassword(channel, password, success => { if (!success) { Sessions.SwitchChannel(ctx.Session); throw new ChannelPasswordCommandException(channel); } ChannelUsers.JoinChannel(channel, ctx.Session); }); } else { ChannelUsers.JoinChannel(channel, ctx.Session); } }); }); return(true); }
public void HandleCommand(ClientCommandContext ctx) { string channelName = ctx.Arguments.ElementAtOrDefault(0); if (string.IsNullOrWhiteSpace(channelName)) { ctx.Connection.SendReply(new NoRecipientReply(NAME)); return; } string text = ctx.Arguments.ElementAtOrDefault(1); if (string.IsNullOrWhiteSpace(text)) { ctx.Connection.SendReply(new NoTextToSendReply()); return; } Func <IChannel, bool> predicate = null; char channelPrefix = channelName.First(); if (channelPrefix == '#') { predicate = new Func <IChannel, bool>(c => channelName.Equals(c.GetIRCName())); } if (predicate == null) { ctx.Connection.SendReply(new NoSuchNickReply(channelName)); return; } Channels.GetChannel(predicate, channel => { if (channel == null) { ctx.Connection.SendReply(new NoSuchNickReply(channelName)); return; } ChannelUsers.HasUser(channel, ctx.User, hasUser => { if (!hasUser) { ctx.Connection.SendReply(new CannotSendToChannelReply(channel)); return; } Messages.Create(ctx.Session, channel, text); }); }); }
public bool DispatchCommand(ICommandContext ctx) { string channelName = ctx.Args.ElementAtOrDefault(1); // no error, apparently if (string.IsNullOrWhiteSpace(channelName)) { return(false); } IChannel channel = Channels.GetChannel(channelName); // the original server sends ForceChannel before sending the error message, but this order probably makes more sense. if (channel == null) { Sessions.SwitchChannel(ctx.Session); throw new ChannelNotFoundCommandException(channelName); } if (ChannelUsers.HasUser(channel, ctx.User)) { Sessions.SwitchChannel(ctx.Session); throw new AlreadyInChannelCommandException(channel); } string password = string.Join(' ', ctx.Args.Skip(2)); if (!ctx.User.Can(UserPermissions.JoinAnyChannel) && channel.Owner != ctx.User) { if (channel.MinimumRank > ctx.User.Rank) { Sessions.SwitchChannel(ctx.Session); throw new ChannelRankCommandException(channel); } if (channel.VerifyPassword(password)) { Sessions.SwitchChannel(ctx.Session); throw new ChannelPasswordCommandException(channel); } } ChannelUsers.JoinChannel(channel, ctx.Session); return(true); }
public void HandlePacket(IPacketHandlerContext ctx) { if (ctx.HasSession) { return; } if (!long.TryParse(ctx.Args.ElementAtOrDefault(1), out long userId) || userId < 1) { return; } string token = ctx.Args.ElementAtOrDefault(2); if (string.IsNullOrEmpty(token)) { return; } Action <Exception> exceptionHandler = new Action <Exception>(ex => { Logger.Debug($@"<{ctx.Connection.RemoteAddress}> Auth fail: {ex.Message}"); ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid)); ctx.Connection.Close(); }); DataProvider.UserAuthClient.AttemptAuth( new UserAuthRequest(userId, token, ctx.Connection.RemoteAddress), res => { DataProvider.BanClient.CheckBan(res.UserId, ctx.Connection.RemoteAddress, ban => { if (ban.IsPermanent || ban.Expires > DateTimeOffset.Now) { ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Banned, ban)); ctx.Connection.Close(); return; } IUser user = Users.Connect(res); // Enforce a maximum amount of connections per user if (Sessions.GetAvailableSessionCount(user) < 1) { ctx.Connection.Send(new AuthFailPacket(AuthFailReason.MaxSessions)); ctx.Connection.Close(); return; } ISession sess = Sessions.Create(ctx.Connection, user); sess.SendPacket(new WelcomeMessagePacket(Sender, $@"Welcome to Flashii Chat, {user.UserName}!")); if (File.Exists(WELCOME)) { IEnumerable <string> lines = File.ReadAllLines(WELCOME).Where(x => !string.IsNullOrWhiteSpace(x)); string line = lines.ElementAtOrDefault(RNG.Next(lines.Count())); if (!string.IsNullOrWhiteSpace(line)) { sess.SendPacket(new WelcomeMessagePacket(Sender, line)); } } IChannel chan = Channels.DefaultChannel; bool shouldJoin = !ChannelUsers.HasUser(chan, user); if (shouldJoin) { // ChannelUsers? //chan.SendPacket(new UserConnectPacket(DateTimeOffset.Now, user)); //ctx.Chat.DispatchEvent(this, new UserConnectEvent(chan, user)); } sess.SendPacket(new AuthSuccessPacket(user, chan, sess, Version, Messages.TextMaxLength)); ChannelUsers.GetUsers(chan, u => sess.SendPacket(new ContextUsersPacket(u.Except(new[] { user }).OrderByDescending(u => u.Rank)))); Messages.GetMessages(chan, m => { foreach (IMessage msg in m) { sess.SendPacket(new ContextMessagePacket(msg)); } }); Channels.GetChannels(user.Rank, c => sess.SendPacket(new ContextChannelsPacket(c))); if (shouldJoin) { ChannelUsers.JoinChannel(chan, sess); } }, exceptionHandler); }, exceptionHandler ); }
public void HandlePacket(IPacketHandlerContext ctx) { if (ctx.Args.Count() < 3 || !ctx.HasUser || !ctx.User.Can(UserPermissions.SendMessage)) { return; } if (!long.TryParse(ctx.Args.ElementAtOrDefault(1), out long userId) || ctx.User.UserId != userId) { return; } // No longer concats everything after index 1 with \t, no previous implementation did that either string text = ctx.Args.ElementAtOrDefault(2); if (string.IsNullOrWhiteSpace(text)) { return; } IChannel channel; string channelName = ctx.Args.ElementAtOrDefault(3)?.ToLowerInvariant(); if (string.IsNullOrWhiteSpace(channelName)) { channel = Channels.DefaultChannel; } else { channel = Channels.GetChannel(channelName); } if (channel == null || !ChannelUsers.HasUser(channel, ctx.User) // || (ctx.User.IsSilenced && !ctx.User.Can(UserPermissions.SilenceUser)) TODO: readd silencing ) { return; } if (ctx.User.Status != UserStatus.Online) { Users.Update(ctx.User, status: UserStatus.Online); // ChannelUsers? //channel.SendPacket(new UserUpdatePacket(ctx.User)); } // there's a very miniscule chance that this will return a different value on second read int maxLength = Messages.TextMaxLength; if (text.Length > maxLength) { text = text.Substring(0, maxLength); } text = text.Trim(); #if DEBUG Logger.Write($@"<{ctx.Session.SessionId} {ctx.User.UserName}> {text}"); #endif bool handled = false; if (text[0] == '/') { try { handled = HandleCommand(text, ctx.User, channel, ctx.Session); } catch (CommandException ex) { ctx.Session.SendPacket(ex.ToPacket(Bot)); handled = true; } } if (!handled) { Messages.Create(ctx.User, channel, text); } }