From 1a7f56a9032066e206d8baae97e872b244c4b0f2 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Mon, 17 Feb 2014 17:58:22 -0800 Subject: [PATCH] clean up general command and name handling --- irc/channel.go | 9 +-------- irc/client.go | 13 ++++++++----- irc/constants.go | 8 ++++++++ irc/reply.go | 5 +++++ irc/server.go | 42 ++++++++++++++++++++++++++---------------- 5 files changed, 48 insertions(+), 29 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index a7ae0819..41f7ed14 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -15,14 +15,7 @@ type Channel struct { } func IsChannel(target string) bool { - if target == "" { - return false - } - switch target[0] { - case '&', '#', '+', '!': - return true - } - return false + return ChannelNameExpr.MatchString(target) } // NewChannel creates a new channel from a `Server` and a `name` diff --git a/irc/client.go b/irc/client.go index 7d67690d..ce3bb079 100644 --- a/irc/client.go +++ b/irc/client.go @@ -8,6 +8,10 @@ import ( "time" ) +func IsNickname(nick string) bool { + return NicknameExpr.MatchString(nick) +} + type Client struct { atime time.Time awayMessage string @@ -43,8 +47,7 @@ func NewClient(server *Server, conn net.Conn) *Client { socket: NewSocket(conn), } - client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.ConnectionClosed) - + client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionClosed) go client.readCommands() go client.writeReplies() @@ -94,7 +97,7 @@ func (client *Client) Touch() { func (client *Client) Idle() { if client.quitTimer == nil { - client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.ConnectionTimeout) + client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout) } else { client.quitTimer.Reset(QUIT_TIMEOUT) } @@ -102,7 +105,7 @@ func (client *Client) Idle() { client.Reply(RplPing(client.server, client)) } -func (client *Client) ConnectionTimeout() { +func (client *Client) connectionTimeout() { msg := &QuitCommand{ message: "connection timeout", } @@ -110,7 +113,7 @@ func (client *Client) ConnectionTimeout() { client.server.commands <- msg } -func (client *Client) ConnectionClosed() { +func (client *Client) connectionClosed() { msg := &QuitCommand{ message: "connection closed", } diff --git a/irc/constants.go b/irc/constants.go index df7deca5..10e14221 100644 --- a/irc/constants.go +++ b/irc/constants.go @@ -2,16 +2,24 @@ package irc import ( "errors" + "regexp" "time" ) var ( + // debugging flags DEBUG_NET = false DEBUG_CLIENT = false DEBUG_CHANNEL = false DEBUG_SERVER = false + // errors ErrAlreadyDestroyed = errors.New("already destroyed") + + // regexps + ChannelNameExpr = regexp.MustCompile(`^[&!#+][[:word:]]{1,63}$`) + NicknameExpr = regexp.MustCompile( + "^[[:alpha:]\\[\\]{}^`][[:word:]\\[\\]{}^`]{1,31}$") ) const ( diff --git a/irc/reply.go b/irc/reply.go index 87b73443..2f39291f 100644 --- a/irc/reply.go +++ b/irc/reply.go @@ -433,3 +433,8 @@ func ErrNoMOTD(server *Server) Reply { func ErrNoNicknameGiven(server *Server) Reply { return NewNumericReply(server, ERR_NONICKNAMEGIVEN, ":No nickname given") } + +func ErrErroneusNickname(server *Server, nick string) Reply { + return NewNumericReply(server, ERR_ERRONEUSNICKNAME, + "%s :Erroneous nickname", nick) +} diff --git a/irc/server.go b/irc/server.go index 1dc58cdb..07ac0632 100644 --- a/irc/server.go +++ b/irc/server.go @@ -54,37 +54,37 @@ func (server *Server) ReceiveCommands() { case conn := <-server.conns: NewClient(server, conn) - case command := <-server.commands: + case cmd := <-server.commands: + client := cmd.Client() if DEBUG_SERVER { - log.Printf("%s → %s %+v", command.Client(), server, command) + log.Printf("%s → %s %s", client, server, cmd) } - client := command.Client() switch client.phase { case Authorization: - authCommand, ok := command.(AuthServerCommand) + authCmd, ok := cmd.(AuthServerCommand) if !ok { client.Destroy() continue } - authCommand.HandleAuthServer(server) + authCmd.HandleAuthServer(server) case Registration: - regCommand, ok := command.(RegServerCommand) + regCmd, ok := cmd.(RegServerCommand) if !ok { client.Destroy() continue } - regCommand.HandleRegServer(server) + regCmd.HandleRegServer(server) default: - serverCommand, ok := command.(ServerCommand) + srvCmd, ok := cmd.(ServerCommand) if !ok { - client.Reply(ErrUnknownCommand(server, command.Code())) + client.Reply(ErrUnknownCommand(server, cmd.Code())) continue } client.Touch() - serverCommand.HandleServer(server) + srvCmd.HandleServer(server) } } } @@ -264,11 +264,16 @@ func (m *NickCommand) HandleRegServer(s *Server) { return } - if s.clients[m.nickname] != nil { + if s.clients.Get(m.nickname) != nil { client.Reply(ErrNickNameInUse(s, m.nickname)) return } + if !IsNickname(m.nickname) { + client.Reply(ErrErroneusNickname(s, m.nickname)) + return + } + client.ChangeNickname(m.nickname) s.clients.Add(client) s.tryRegister(client) @@ -304,7 +309,7 @@ func (msg *NickCommand) HandleServer(server *Server) { return } - if server.clients[msg.nickname] != nil { + if server.clients.Get(msg.nickname) != nil { client.Reply(ErrNickNameInUse(server, msg.nickname)) return } @@ -395,7 +400,12 @@ func (msg *PrivMsgCommand) HandleServer(server *Server) { func (m *ModeCommand) HandleServer(s *Server) { client := m.Client() - target := s.clients[m.nickname] + target := s.clients.Get(m.nickname) + + if target == nil { + client.Reply(ErrNoSuchNick(s, m.nickname)) + return + } if client != target && !client.flags[Operator] { client.Reply(ErrUsersDontMatch(s)) @@ -521,8 +531,8 @@ func (msg *IsOnCommand) HandleServer(server *Server) { ison := make([]string, 0) for _, nick := range msg.nicks { - if _, ok := server.clients[nick]; ok { - ison = append(ison, nick) + if iclient := server.clients.Get(nick); iclient != nil { + ison = append(ison, iclient.Nick()) } } @@ -546,7 +556,7 @@ func (msg *NoticeCommand) HandleServer(server *Server) { return } - target := server.clients[msg.target] + target := server.clients.Get(msg.target) if target == nil { client.Reply(ErrNoSuchNick(server, msg.target)) return