diff --git a/irc/channel.go b/irc/channel.go index 06b73274..aff1bccf 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -17,20 +17,6 @@ type Channel struct { topic string } -type ChannelSet map[*Channel]bool - -func (channels ChannelSet) First() *Channel { - for channel := range channels { - return channel - } - return nil -} - -type ChannelCommand interface { - Command - HandleChannel(channel *Channel) -} - func IsChannel(target string) bool { if target == "" { return false @@ -132,8 +118,8 @@ func (channel *Channel) ModeString() string { } func (channel *Channel) Join(client *Client) { - channel.members[client] = true - client.channels[channel] = true + channel.members.Add(client) + client.channels.Add(channel) reply := RplJoin(client, channel) client.replies <- reply channel.replies <- reply @@ -141,10 +127,6 @@ func (channel *Channel) Join(client *Client) { channel.GetUsers(client) } -func (channel *Channel) HasMember(client *Client) bool { - return channel.members[client] -} - // // commands // @@ -162,7 +144,7 @@ func (m *JoinCommand) HandleChannel(channel *Channel) { func (m *PartCommand) HandleChannel(channel *Channel) { client := m.Client() - if !channel.HasMember(client) { + if !channel.members.Has(client) { client.replies <- ErrNotOnChannel(channel) return } @@ -171,19 +153,19 @@ func (m *PartCommand) HandleChannel(channel *Channel) { client.replies <- reply channel.replies <- reply - delete(channel.members, client) - delete(client.channels, channel) + channel.members.Remove(client) + client.channels.Remove(channel) // TODO persistent channels if channel.IsEmpty() { - channel.server.DeleteChannel(channel) + channel.server.channels.Remove(channel) } } func (m *TopicCommand) HandleChannel(channel *Channel) { client := m.Client() - if !channel.HasMember(client) { + if !channel.members.Has(client) { client.replies <- ErrNotOnChannel(channel) return } diff --git a/irc/client.go b/irc/client.go index 29e1cddb..39f3dfd8 100644 --- a/irc/client.go +++ b/irc/client.go @@ -23,8 +23,6 @@ type Client struct { username string } -type ClientSet map[*Client]bool - func NewClient(server *Server, conn net.Conn) *Client { read := StringReadChan(conn) write := StringWriteChan(conn) @@ -73,6 +71,7 @@ func (c *Client) writeConn(write chan<- string, replies <-chan Reply) { func (client *Client) Destroy() *Client { client.conn.Close() + close(client.replies) return client } diff --git a/irc/constants.go b/irc/constants.go index 8362997e..56c5eede 100644 --- a/irc/constants.go +++ b/irc/constants.go @@ -9,6 +9,7 @@ var ( const ( VERSION = "ergonomadic-1" + CRLF = "\r\n" // numeric codes RPL_WELCOME = 1 @@ -173,7 +174,7 @@ const ( Anonymous ChannelMode = 'a' BanMask ChannelMode = 'b' // arg ExceptionMask ChannelMode = 'e' // arg - InviteMask ChannelMode = 'i' // arg + InviteMask ChannelMode = 'I' // arg InviteOnly ChannelMode = 'i' Key ChannelMode = 'k' // arg Moderated ChannelMode = 'm' diff --git a/irc/net.go b/irc/net.go index 54122f34..e835ab6d 100644 --- a/irc/net.go +++ b/irc/net.go @@ -32,10 +32,6 @@ func StringReadChan(conn net.Conn) <-chan string { return ch } -const ( - CRLF = "\r\n" -) - func maybeLogWriteError(conn net.Conn, err error) bool { if err != nil { if err != io.EOF { diff --git a/irc/reply.go b/irc/reply.go index 013ef65b..e018cda6 100644 --- a/irc/reply.go +++ b/irc/reply.go @@ -188,7 +188,7 @@ func RplCreated(server *Server) Reply { func RplMyInfo(server *Server) Reply { return NewNumericReply(server, RPL_MYINFO, - "%s %s aiwroOs kn", server.name, VERSION) + "%s %s aiOorsw abeIikmntpqrsl", server.name, VERSION) } func RplUModeIs(server *Server, client *Client) Reply { diff --git a/irc/server.go b/irc/server.go index 3961b94d..f78a42eb 100644 --- a/irc/server.go +++ b/irc/server.go @@ -9,9 +9,6 @@ import ( "time" ) -type ChannelNameMap map[string]*Channel -type ClientNameMap map[string]*Client - type Server struct { channels ChannelNameMap commands chan<- Command @@ -125,20 +122,16 @@ func (s *Server) Nick() string { return s.Id() } -func (s *Server) DeleteChannel(channel *Channel) { - delete(s.channels, channel.name) -} - // // commands // func (m *UnknownCommand) HandleServer(s *Server) { - m.Client().Replies() <- ErrUnknownCommand(s, m.command) + m.Client().replies <- ErrUnknownCommand(s, m.command) } func (m *PingCommand) HandleServer(s *Server) { - m.Client().Replies() <- RplPong(s, m.Client()) + m.Client().replies <- RplPong(s, m.Client()) } func (m *PongCommand) HandleServer(s *Server) { @@ -147,8 +140,8 @@ func (m *PongCommand) HandleServer(s *Server) { func (m *PassCommand) HandleServer(s *Server) { if s.password != m.password { - m.Client().Replies() <- ErrPasswdMismatch(s) - // TODO disconnect + m.Client().replies <- ErrPasswdMismatch(s) + m.Client().Destroy() return } @@ -170,9 +163,9 @@ func (m *NickCommand) HandleServer(s *Server) { iclient.replies <- reply } - delete(s.clients, c.nick) - s.clients[m.nickname] = c + s.clients.Remove(c) c.nick = m.nickname + s.clients.Add(c) s.tryRegister(c) } @@ -191,9 +184,9 @@ func (m *UserMsgCommand) HandleServer(s *Server) { func (m *QuitCommand) HandleServer(s *Server) { c := m.Client() - delete(s.clients, c.nick) + s.clients.Remove(c) for channel := range c.channels { - delete(channel.members, c) + channel.members.Remove(c) } c.replies <- RplError(s, c) diff --git a/irc/types.go b/irc/types.go index cdc16f87..01187cac 100644 --- a/irc/types.go +++ b/irc/types.go @@ -23,6 +23,73 @@ type ChannelMode rune // user-channel mode flags type UserChannelMode rune +type ChannelNameMap map[string]*Channel + +func (channels ChannelNameMap) Add(channel *Channel) error { + if channels[channel.name] != nil { + return fmt.Errorf("%s: already set", channel.name) + } + channels[channel.name] = channel + return nil +} + +func (channels ChannelNameMap) Remove(channel *Channel) error { + if channel != channels[channel.name] { + return fmt.Errorf("%s: mismatch", channel.name) + } + delete(channels, channel.name) + return nil +} + +type ClientNameMap map[string]*Client + +func (clients ClientNameMap) Add(client *Client) error { + if clients[client.nick] != nil { + return fmt.Errorf("%s: already set", client.nick) + } + clients[client.nick] = client + return nil +} + +func (clients ClientNameMap) Remove(client *Client) error { + if clients[client.nick] != client { + return fmt.Errorf("%s: mismatch", client.nick) + } + delete(clients, client.nick) + return nil +} + +type ClientSet map[*Client]bool + +func (clients ClientSet) Add(client *Client) { + clients[client] = true +} + +func (clients ClientSet) Remove(client *Client) { + delete(clients, client) +} + +func (clients ClientSet) Has(client *Client) bool { + return clients[client] +} + +type ChannelSet map[*Channel]bool + +func (channels ChannelSet) Add(channel *Channel) { + channels[channel] = true +} + +func (channels ChannelSet) Remove(channel *Channel) { + delete(channels, channel) +} + +func (channels ChannelSet) First() *Channel { + for channel := range channels { + return channel + } + return nil +} + // // interfaces // @@ -36,6 +103,11 @@ type Command interface { HandleServer(*Server) } +type ChannelCommand interface { + Command + HandleChannel(channel *Channel) +} + // // structs //