From 6267b6a40c226baea699ad515dfbe57fa8d214f1 Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sat, 22 Mar 2014 22:25:24 +0100 Subject: [PATCH 1/3] clean up /theater so that it doesn't need a bunch of pointers and that it reuses channel-scoped-user-modes machinery --- irc/channel.go | 4 ---- irc/client.go | 5 ----- irc/modes.go | 2 +- irc/theater.go | 10 ++++------ irc/types.go | 9 +++++++++ 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index a771b8a0..3308b295 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -14,7 +14,6 @@ type Channel struct { server *Server topic Text userLimit uint64 - theaterUser *Client } // NewChannel creates a new channel from a `Server` and a `name` @@ -406,9 +405,6 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo return channel.applyModeMember(client, change.mode, change.op, NewName(change.arg)) - case Theater: - client.ErrConfiguredMode(change.mode) - default: client.ErrUnknownMode(change.mode, channel) } diff --git a/irc/client.go b/irc/client.go index 26634405..f1f87d27 100644 --- a/irc/client.go +++ b/irc/client.go @@ -34,7 +34,6 @@ type Client struct { server *Server socket *Socket username Name - theaterChannels []*Channel } func NewClient(server *Server, conn net.Conn) *Client { @@ -260,10 +259,6 @@ func (client *Client) Quit(message Text) { return } - for _, channel := range client.theaterChannels { - delete(channel.flags, Theater) - } - client.Reply(RplError("connection closed")) client.hasQuit = true client.server.whoWas.Append(client) diff --git a/irc/modes.go b/irc/modes.go index 44dd1607..717e9c32 100644 --- a/irc/modes.go +++ b/irc/modes.go @@ -83,7 +83,7 @@ const ( Quiet ChannelMode = 'q' // flag ReOp ChannelMode = 'r' // flag Secret ChannelMode = 's' // flag, deprecated - Theater ChannelMode = 'T' // flag arg, nonstandard + Theater ChannelMode = 'T' // flag, nonstandard UserLimit ChannelMode = 'l' // flag arg Voice ChannelMode = 'v' // arg ) diff --git a/irc/theater.go b/irc/theater.go index 43f1d8d0..783c851b 100644 --- a/irc/theater.go +++ b/irc/theater.go @@ -51,10 +51,8 @@ func (m *TheaterIdentifyCommand) HandleServer(s *Server) { return } - if channel.theaterUser == nil { - client.theaterChannels = append(client.theaterChannels, channel) - channel.flags[Theater] = true - channel.theaterUser = client + if !channel.members.AnyHasMode(Theater) { + channel.members[client][Theater] = true } } @@ -82,7 +80,7 @@ func (m *TheaterPrivMsgCommand) HandleServer(s *Server) { return } - if channel.theaterUser == client { + if channel.members.HasMode(client, Theater) { for member := range channel.members { member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message)) } @@ -113,7 +111,7 @@ func (m *TheaterActionCommand) HandleServer(s *Server) { return } - if channel.theaterUser == client { + if channel.members.HasMode(client, Theater) { for member := range channel.members { member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, NewText(fmt.Sprintf("\001ACTION %s\001", m.action)))) } diff --git a/irc/types.go b/irc/types.go index 7c8a5a2f..db698254 100644 --- a/irc/types.go +++ b/irc/types.go @@ -83,6 +83,15 @@ func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool { return modes[mode] } +func (members MemberSet) AnyHasMode(mode ChannelMode) bool { + for _, modes := range members { + if modes[Theater] { + return true + } + } + return false +} + type ChannelSet map[*Channel]bool func (channels ChannelSet) Add(channel *Channel) { From 34b01b115edb059360b526268b783522fd993bd1 Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sun, 23 Mar 2014 06:47:21 +0100 Subject: [PATCH 2/3] add a type for CTCP-encoded strings, and NOTICEs for error cases --- irc/commands.go | 2 +- irc/reply.go | 4 ++++ irc/strings.go | 9 +++++++++ irc/theater.go | 35 +++++++++++++++++++++++------------ irc/types.go | 2 +- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/irc/commands.go b/irc/commands.go index c9a4550c..22153041 100644 --- a/irc/commands.go +++ b/irc/commands.go @@ -966,7 +966,7 @@ func NewTheaterCommand(args []string) (Command, error) { return &TheaterActionCommand{ channel: NewName(args[1]), asNick: NewName(args[2]), - action: NewText(args[3]), + action: NewCTCPText(args[3]), }, nil } else { return nil, ErrParseCommand diff --git a/irc/reply.go b/irc/reply.go index 040aedbf..2c11bea2 100644 --- a/irc/reply.go +++ b/irc/reply.go @@ -99,6 +99,10 @@ func RplPrivMsg(source Identifiable, target Identifiable, message Text) string { return NewStringReply(source, PRIVMSG, "%s :%s", target.Nick(), message) } +func RplCTCPAction(source Identifiable, target Identifiable, action CTCPText) string { + return RplPrivMsg(source, target, NewText(fmt.Sprintf("\x01ACTION %s\x01", action))) +} + func RplNotice(source Identifiable, target Identifiable, message Text) string { return NewStringReply(source, NOTICE, "%s :%s", target.Nick(), message) } diff --git a/irc/strings.go b/irc/strings.go index dfd01fcb..b8cc9227 100644 --- a/irc/strings.go +++ b/irc/strings.go @@ -64,3 +64,12 @@ func NewText(str string) Text { func (text Text) String() string { return string(text) } + +// CTCPText is text suitable escaped for CTCP. +type CTCPText string + +var ctcpEscaper = strings.NewReplacer("\x00", "\x200", "\n", "\x20n", "\r", "\x20r") + +func NewCTCPText(str string) CTCPText { + return CTCPText(ctcpEscaper.Replace(str)) +} diff --git a/irc/theater.go b/irc/theater.go index 783c851b..36525048 100644 --- a/irc/theater.go +++ b/irc/theater.go @@ -51,9 +51,12 @@ func (m *TheaterIdentifyCommand) HandleServer(s *Server) { return } - if !channel.members.AnyHasMode(Theater) { - channel.members[client][Theater] = true + if channel.members.AnyHasMode(Theater) { + client.Reply(RplNotice(s, client, "someone else is +T in this channel")) + return } + + channel.members[client][Theater] = true } type TheaterPrivMsgCommand struct { @@ -69,6 +72,7 @@ func (cmd *TheaterPrivMsgCommand) String() string { } func (m *TheaterPrivMsgCommand) HandleServer(s *Server) { client := m.Client() + if !m.channel.IsChannel() { client.ErrNoSuchChannel(m.channel) return @@ -80,10 +84,13 @@ func (m *TheaterPrivMsgCommand) HandleServer(s *Server) { return } - if channel.members.HasMode(client, Theater) { - for member := range channel.members { - member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message)) - } + if !channel.members.HasMode(client, Theater) { + client.Reply(RplNotice(s, client, "you are not +T")) + return + } + + for member := range channel.members { + member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message)) } } @@ -91,7 +98,7 @@ type TheaterActionCommand struct { BaseCommand channel Name asNick Name - action Text + action CTCPText } func (cmd *TheaterActionCommand) String() string { @@ -100,7 +107,8 @@ func (cmd *TheaterActionCommand) String() string { func (m *TheaterActionCommand) HandleServer(s *Server) { client := m.Client() - if m.channel.IsChannel() { + + if !m.channel.IsChannel() { client.ErrNoSuchChannel(m.channel) return } @@ -111,9 +119,12 @@ func (m *TheaterActionCommand) HandleServer(s *Server) { return } - if channel.members.HasMode(client, Theater) { - for member := range channel.members { - member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, NewText(fmt.Sprintf("\001ACTION %s\001", m.action)))) - } + if !channel.members.HasMode(client, Theater) { + client.Reply(RplNotice(s, client, "you are not +T")) + return + } + + for member := range channel.members { + member.Reply(RplCTCPAction(TheaterClient(m.asNick), channel, m.action)) } } diff --git a/irc/types.go b/irc/types.go index db698254..dabe4c2b 100644 --- a/irc/types.go +++ b/irc/types.go @@ -85,7 +85,7 @@ func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool { func (members MemberSet) AnyHasMode(mode ChannelMode) bool { for _, modes := range members { - if modes[Theater] { + if modes[mode] { return true } } From 2272aae213131ac66b10a83cf86e3a4e03526b32 Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sun, 23 Mar 2014 06:48:53 +0100 Subject: [PATCH 3/3] spelling and gofmt --- irc/channel.go | 16 ++++++++-------- irc/client.go | 42 +++++++++++++++++++++--------------------- irc/strings.go | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/irc/channel.go b/irc/channel.go index 3308b295..05a96459 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -6,14 +6,14 @@ import ( ) type Channel struct { - flags ChannelModeSet - lists map[ChannelMode]*UserMaskSet - key Text - members MemberSet - name Name - server *Server - topic Text - userLimit uint64 + flags ChannelModeSet + lists map[ChannelMode]*UserMaskSet + key Text + members MemberSet + name Name + server *Server + topic Text + userLimit uint64 } // NewChannel creates a new channel from a `Server` and a `name` diff --git a/irc/client.go b/irc/client.go index f1f87d27..4e076b54 100644 --- a/irc/client.go +++ b/irc/client.go @@ -13,27 +13,27 @@ const ( ) type Client struct { - atime time.Time - authorized bool - awayMessage Text - capabilities CapabilitySet - capState CapState - channels ChannelSet - commands chan Command - ctime time.Time - flags map[UserMode]bool - hasQuit bool - hops uint - hostname Name - idleTimer *time.Timer - loginTimer *time.Timer - nick Name - quitTimer *time.Timer - realname Text - registered bool - server *Server - socket *Socket - username Name + atime time.Time + authorized bool + awayMessage Text + capabilities CapabilitySet + capState CapState + channels ChannelSet + commands chan Command + ctime time.Time + flags map[UserMode]bool + hasQuit bool + hops uint + hostname Name + idleTimer *time.Timer + loginTimer *time.Timer + nick Name + quitTimer *time.Timer + realname Text + registered bool + server *Server + socket *Socket + username Name } func NewClient(server *Server, conn net.Conn) *Client { diff --git a/irc/strings.go b/irc/strings.go index b8cc9227..98304b1b 100644 --- a/irc/strings.go +++ b/irc/strings.go @@ -65,7 +65,7 @@ func (text Text) String() string { return string(text) } -// CTCPText is text suitable escaped for CTCP. +// CTCPText is text suitably escaped for CTCP. type CTCPText string var ctcpEscaper = strings.NewReplacer("\x00", "\x200", "\n", "\x20n", "\r", "\x20r")