mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-14 07:59:31 +01:00
kick command
This commit is contained in:
parent
af5a05f390
commit
a9d7f64693
@ -145,13 +145,7 @@ func (channel *Channel) Part(client *Client, message string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel.Reply(RplPart(client, channel, message))
|
channel.Reply(RplPart(client, channel, message))
|
||||||
|
channel.Quit(client)
|
||||||
channel.members.Remove(client)
|
|
||||||
client.channels.Remove(channel)
|
|
||||||
|
|
||||||
for member := range channel.members {
|
|
||||||
member.RemoveFriend(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
if channel.IsEmpty() {
|
if channel.IsEmpty() {
|
||||||
channel.server.channels.Remove(channel)
|
channel.server.channels.Remove(channel)
|
||||||
@ -305,4 +299,23 @@ func (channel *Channel) Quit(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel.members.Remove(client)
|
channel.members.Remove(client)
|
||||||
|
client.channels.Remove(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) Kick(client *Client, target *Client, comment string) {
|
||||||
|
if !channel.members.Has(client) {
|
||||||
|
client.Reply(ErrNotOnChannel(channel))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !channel.ClientIsOperator(client) {
|
||||||
|
client.Reply(ErrChanOPrivIsNeeded(channel))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !channel.members.Has(target) {
|
||||||
|
client.Reply(ErrUserNotInChannel(channel, target))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.Reply(RplKick(channel, client, target, comment))
|
||||||
|
channel.Quit(target)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,9 +58,8 @@ func (client *Client) readCommands() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
switch err {
|
||||||
case NotEnoughArgsError:
|
case NotEnoughArgsError:
|
||||||
client.Reply(ErrNeedMoreParams(client.server, line))
|
parts := strings.SplitN(line, " ", 2)
|
||||||
default:
|
client.Reply(ErrNeedMoreParams(client.server, parts[0]))
|
||||||
client.Reply(ErrUnknownCommand(client.server, line))
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
109
irc/commands.go
109
irc/commands.go
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
type editableCommand interface {
|
type editableCommand interface {
|
||||||
Command
|
Command
|
||||||
SetName(string)
|
SetCode(StringCode)
|
||||||
SetClient(*Client)
|
SetClient(*Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,33 +18,34 @@ type parseCommandFunc func([]string) (editableCommand, error)
|
|||||||
var (
|
var (
|
||||||
NotEnoughArgsError = errors.New("not enough arguments")
|
NotEnoughArgsError = errors.New("not enough arguments")
|
||||||
ErrParseCommand = errors.New("failed to parse message")
|
ErrParseCommand = errors.New("failed to parse message")
|
||||||
parseCommandFuncs = map[string]parseCommandFunc{
|
parseCommandFuncs = map[StringCode]parseCommandFunc{
|
||||||
"AWAY": NewAwayCommand,
|
AWAY: NewAwayCommand,
|
||||||
"CAP": NewCapCommand,
|
CAP: NewCapCommand,
|
||||||
"ISON": NewIsOnCommand,
|
ISON: NewIsOnCommand,
|
||||||
"JOIN": NewJoinCommand,
|
JOIN: NewJoinCommand,
|
||||||
"MODE": NewModeCommand,
|
KICK: NewKickCommand,
|
||||||
"MOTD": NewMOTDCommand,
|
MODE: NewModeCommand,
|
||||||
"NICK": NewNickCommand,
|
MOTD: NewMOTDCommand,
|
||||||
"NOTICE": NewNoticeCommand,
|
NICK: NewNickCommand,
|
||||||
"OPER": NewOperCommand,
|
NOTICE: NewNoticeCommand,
|
||||||
"PART": NewPartCommand,
|
OPER: NewOperCommand,
|
||||||
"PASS": NewPassCommand,
|
PART: NewPartCommand,
|
||||||
"PING": NewPingCommand,
|
PASS: NewPassCommand,
|
||||||
"PONG": NewPongCommand,
|
PING: NewPingCommand,
|
||||||
"PRIVMSG": NewPrivMsgCommand,
|
PONG: NewPongCommand,
|
||||||
"PROXY": NewProxyCommand,
|
PRIVMSG: NewPrivMsgCommand,
|
||||||
"QUIT": NewQuitCommand,
|
PROXY: NewProxyCommand,
|
||||||
"TOPIC": NewTopicCommand,
|
QUIT: NewQuitCommand,
|
||||||
"USER": NewUserMsgCommand,
|
TOPIC: NewTopicCommand,
|
||||||
"WHO": NewWhoCommand,
|
USER: NewUserMsgCommand,
|
||||||
"WHOIS": NewWhoisCommand,
|
WHO: NewWhoCommand,
|
||||||
|
WHOIS: NewWhoisCommand,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type BaseCommand struct {
|
type BaseCommand struct {
|
||||||
client *Client
|
client *Client
|
||||||
name string
|
code StringCode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (command *BaseCommand) Client() *Client {
|
func (command *BaseCommand) Client() *Client {
|
||||||
@ -55,12 +56,12 @@ func (command *BaseCommand) SetClient(c *Client) {
|
|||||||
command.client = c
|
command.client = c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (command *BaseCommand) Name() string {
|
func (command *BaseCommand) Code() StringCode {
|
||||||
return command.name
|
return command.code
|
||||||
}
|
}
|
||||||
|
|
||||||
func (command *BaseCommand) SetName(name string) {
|
func (command *BaseCommand) SetCode(code StringCode) {
|
||||||
command.name = name
|
command.code = code
|
||||||
}
|
}
|
||||||
|
|
||||||
func (command *BaseCommand) Source() Identifier {
|
func (command *BaseCommand) Source() Identifier {
|
||||||
@ -72,15 +73,15 @@ func (command *BaseCommand) Reply(reply Reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ParseCommand(line string) (cmd editableCommand, err error) {
|
func ParseCommand(line string) (cmd editableCommand, err error) {
|
||||||
command, args := parseLine(line)
|
code, args := parseLine(line)
|
||||||
constructor := parseCommandFuncs[command]
|
constructor := parseCommandFuncs[code]
|
||||||
if constructor == nil {
|
if constructor == nil {
|
||||||
cmd = NewUnknownCommand(command, args)
|
cmd = NewUnknownCommand(args)
|
||||||
} else {
|
} else {
|
||||||
cmd, err = constructor(args)
|
cmd, err = constructor(args)
|
||||||
}
|
}
|
||||||
if cmd != nil {
|
if cmd != nil {
|
||||||
cmd.SetName(command)
|
cmd.SetCode(code)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -102,13 +103,13 @@ func parseArg(line string) (arg string, rest string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLine(line string) (command string, args []string) {
|
func parseLine(line string) (command StringCode, args []string) {
|
||||||
args = make([]string, 0)
|
args = make([]string, 0)
|
||||||
for arg, rest := parseArg(line); arg != ""; arg, rest = parseArg(rest) {
|
for arg, rest := parseArg(line); arg != ""; arg, rest = parseArg(rest) {
|
||||||
args = append(args, arg)
|
args = append(args, arg)
|
||||||
}
|
}
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
command, args = strings.ToUpper(args[0]), args[1:]
|
command, args = StringCode(strings.ToUpper(args[0])), args[1:]
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -121,10 +122,10 @@ type UnknownCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *UnknownCommand) String() string {
|
func (cmd *UnknownCommand) String() string {
|
||||||
return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Name(), cmd.args)
|
return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.Code(), cmd.args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUnknownCommand(command string, args []string) *UnknownCommand {
|
func NewUnknownCommand(args []string) *UnknownCommand {
|
||||||
return &UnknownCommand{
|
return &UnknownCommand{
|
||||||
args: args,
|
args: args,
|
||||||
}
|
}
|
||||||
@ -739,3 +740,41 @@ func NewNoticeCommand(args []string) (editableCommand, error) {
|
|||||||
message: args[1],
|
message: args[1],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KickCommand struct {
|
||||||
|
BaseCommand
|
||||||
|
kicks map[string]string
|
||||||
|
comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *KickCommand) Comment() string {
|
||||||
|
if msg.comment == "" {
|
||||||
|
return msg.Source().Nick()
|
||||||
|
}
|
||||||
|
return msg.comment
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKickCommand(args []string) (editableCommand, error) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return nil, NotEnoughArgsError
|
||||||
|
}
|
||||||
|
channels := strings.Split(args[0], ",")
|
||||||
|
users := strings.Split(args[1], ",")
|
||||||
|
if (len(channels) != len(users)) && (len(users) != 1) {
|
||||||
|
return nil, NotEnoughArgsError
|
||||||
|
}
|
||||||
|
cmd := &KickCommand{
|
||||||
|
kicks: make(map[string]string),
|
||||||
|
}
|
||||||
|
for index, channel := range channels {
|
||||||
|
if len(users) == 1 {
|
||||||
|
cmd.kicks[channel] = users[0]
|
||||||
|
} else {
|
||||||
|
cmd.kicks[channel] = users[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(args) > 2 {
|
||||||
|
cmd.comment = args[2]
|
||||||
|
}
|
||||||
|
return cmd, nil
|
||||||
|
}
|
||||||
|
@ -24,18 +24,29 @@ const (
|
|||||||
QUIT_TIMEOUT = time.Minute // how long after idle before a client is kicked
|
QUIT_TIMEOUT = time.Minute // how long after idle before a client is kicked
|
||||||
|
|
||||||
// string codes
|
// string codes
|
||||||
PRIVMSG StringCode = "PRIVMSG"
|
AWAY StringCode = "AWAY"
|
||||||
NOTICE StringCode = "NOTICE"
|
CAP StringCode = "CAP"
|
||||||
NICK StringCode = "NICK"
|
|
||||||
JOIN StringCode = "JOIN"
|
|
||||||
PART StringCode = "PART"
|
|
||||||
MODE StringCode = "MODE"
|
|
||||||
TOPIC StringCode = "TOPIC"
|
|
||||||
PING StringCode = "PING"
|
|
||||||
PONG StringCode = "PONG"
|
|
||||||
QUIT StringCode = "QUIT"
|
|
||||||
ERROR StringCode = "ERROR"
|
ERROR StringCode = "ERROR"
|
||||||
INVITE StringCode = "INVITE"
|
INVITE StringCode = "INVITE"
|
||||||
|
ISON StringCode = "ISON"
|
||||||
|
JOIN StringCode = "JOIN"
|
||||||
|
KICK StringCode = "KICK"
|
||||||
|
MODE StringCode = "MODE"
|
||||||
|
MOTD StringCode = "MOTD"
|
||||||
|
NICK StringCode = "NICK"
|
||||||
|
NOTICE StringCode = "NOTICE"
|
||||||
|
OPER StringCode = "OPER"
|
||||||
|
PART StringCode = "PART"
|
||||||
|
PASS StringCode = "PASS"
|
||||||
|
PING StringCode = "PING"
|
||||||
|
PONG StringCode = "PONG"
|
||||||
|
PRIVMSG StringCode = "PRIVMSG"
|
||||||
|
PROXY StringCode = "PROXY"
|
||||||
|
QUIT StringCode = "QUIT"
|
||||||
|
TOPIC StringCode = "TOPIC"
|
||||||
|
USER StringCode = "USER"
|
||||||
|
WHO StringCode = "WHO"
|
||||||
|
WHOIS StringCode = "WHOIS"
|
||||||
|
|
||||||
// numeric codes
|
// numeric codes
|
||||||
RPL_WELCOME NumericCode = 1
|
RPL_WELCOME NumericCode = 1
|
||||||
|
21
irc/reply.go
21
irc/reply.go
@ -183,6 +183,11 @@ func RplInviteMsg(channel *Channel, inviter *Client) Reply {
|
|||||||
return NewStringReply(inviter, INVITE, channel.name)
|
return NewStringReply(inviter, INVITE, channel.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RplKick(channel *Channel, client *Client, target *Client, comment string) Reply {
|
||||||
|
return NewStringReply(client, KICK, "%s %s :%s",
|
||||||
|
channel, target.Nick(), comment)
|
||||||
|
}
|
||||||
|
|
||||||
// numeric replies
|
// numeric replies
|
||||||
|
|
||||||
func RplWelcome(source Identifier, client *Client) Reply {
|
func RplWelcome(source Identifier, client *Client) Reply {
|
||||||
@ -330,9 +335,9 @@ func ErrNickNameInUse(source Identifier, nick string) Reply {
|
|||||||
"%s :Nickname is already in use", nick)
|
"%s :Nickname is already in use", nick)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrUnknownCommand(source Identifier, command string) Reply {
|
func ErrUnknownCommand(source Identifier, code StringCode) Reply {
|
||||||
return NewNumericReply(source, ERR_UNKNOWNCOMMAND,
|
return NewNumericReply(source, ERR_UNKNOWNCOMMAND,
|
||||||
"%s :Unknown command", command)
|
"%s :Unknown command", code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrUsersDontMatch(source Identifier) Reply {
|
func ErrUsersDontMatch(source Identifier) Reply {
|
||||||
@ -381,7 +386,7 @@ func ErrPasswdMismatch(server *Server) Reply {
|
|||||||
|
|
||||||
func ErrNoChanModes(channel *Channel) Reply {
|
func ErrNoChanModes(channel *Channel) Reply {
|
||||||
return NewNumericReply(channel.server, ERR_NOCHANMODES,
|
return NewNumericReply(channel.server, ERR_NOCHANMODES,
|
||||||
"%s :Channel doesn't support modes", channel.name)
|
"%s :Channel doesn't support modes", channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrNoPrivileges(server *Server) Reply {
|
func ErrNoPrivileges(server *Server) Reply {
|
||||||
@ -396,20 +401,20 @@ func ErrNoSuchServer(server *Server, target string) Reply {
|
|||||||
return NewNumericReply(server, ERR_NOSUCHSERVER, "%s :No such server", target)
|
return NewNumericReply(server, ERR_NOSUCHSERVER, "%s :No such server", target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrUserNotInChannel(server *Server, nick string, channel *Channel) Reply {
|
func ErrUserNotInChannel(channel *Channel, client *Client) Reply {
|
||||||
return NewNumericReply(server, ERR_USERNOTINCHANNEL,
|
return NewNumericReply(channel.server, ERR_USERNOTINCHANNEL,
|
||||||
"%s %s :They aren't on that channel", nick, channel.name)
|
"%s %s :They aren't on that channel", client.Nick(), channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrCannotSendToChan(channel *Channel) Reply {
|
func ErrCannotSendToChan(channel *Channel) Reply {
|
||||||
return NewNumericReply(channel.server, ERR_CANNOTSENDTOCHAN,
|
return NewNumericReply(channel.server, ERR_CANNOTSENDTOCHAN,
|
||||||
"%s :Cannot send to channel", channel.name)
|
"%s :Cannot send to channel", channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// <channel> :You're not channel operator
|
// <channel> :You're not channel operator
|
||||||
func ErrChanOPrivIsNeeded(channel *Channel) Reply {
|
func ErrChanOPrivIsNeeded(channel *Channel) Reply {
|
||||||
return NewNumericReply(channel.server, ERR_CHANOPRIVSNEEDED,
|
return NewNumericReply(channel.server, ERR_CHANOPRIVSNEEDED,
|
||||||
"%s :You're not channel operator", channel.name)
|
"%s :You're not channel operator", channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrNoMOTD(server *Server) Reply {
|
func ErrNoMOTD(server *Server) Reply {
|
||||||
|
@ -80,7 +80,7 @@ func (server *Server) ReceiveCommands() {
|
|||||||
default:
|
default:
|
||||||
serverCommand, ok := command.(ServerCommand)
|
serverCommand, ok := command.(ServerCommand)
|
||||||
if !ok {
|
if !ok {
|
||||||
client.Reply(ErrUnknownCommand(server, command.Name()))
|
client.Reply(ErrUnknownCommand(server, command.Code()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client.Touch()
|
client.Touch()
|
||||||
@ -542,3 +542,22 @@ func (msg *NoticeCommand) HandleServer(server *Server) {
|
|||||||
}
|
}
|
||||||
target.Reply(RplNotice(client, target, msg.message))
|
target.Reply(RplNotice(client, target, msg.message))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (msg *KickCommand) HandleServer(server *Server) {
|
||||||
|
client := msg.Client()
|
||||||
|
for chname, nickname := range msg.kicks {
|
||||||
|
channel := server.channels[chname]
|
||||||
|
if channel == nil {
|
||||||
|
client.Reply(ErrNoSuchChannel(server, chname))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
target := server.clients[nickname]
|
||||||
|
if target == nil {
|
||||||
|
client.Reply(ErrNoSuchNick(server, nickname))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.Kick(client, target, msg.Comment())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -171,7 +171,7 @@ type Reply interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Command interface {
|
type Command interface {
|
||||||
Name() string
|
Code() StringCode
|
||||||
Client() *Client
|
Client() *Client
|
||||||
Source() Identifier
|
Source() Identifier
|
||||||
Reply(Reply)
|
Reply(Reply)
|
||||||
|
Loading…
Reference in New Issue
Block a user