예제 #1
0
        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);
        }
예제 #2
0
        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);
                });
            });
        }
예제 #3
0
        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);
        }
예제 #4
0
        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
                );
        }
예제 #5
0
        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);
            }
        }