channel mode flags and member modes

This commit is contained in:
Jeremy Latt 2014-02-14 21:57:08 -08:00
parent 6983d1930c
commit 0bfa2fb98f
4 changed files with 119 additions and 29 deletions

View File

@ -9,12 +9,11 @@ type Channel struct {
banList []UserMask banList []UserMask
commands chan<- ChannelCommand commands chan<- ChannelCommand
destroyed bool destroyed bool
flags map[ChannelMode]bool
key string key string
members ClientSet members ClientSet
mutex *sync.Mutex mutex *sync.Mutex
name string name string
noOutside bool
password string
replies chan<- Reply replies chan<- Reply
server *Server server *Server
topic string topic string
@ -39,6 +38,7 @@ func NewChannel(s *Server, name string) *Channel {
channel := &Channel{ channel := &Channel{
banList: make([]UserMask, 0), banList: make([]UserMask, 0),
commands: commands, commands: commands,
flags: make(map[ChannelMode]bool),
members: make(ClientSet), members: make(ClientSet),
mutex: &sync.Mutex{}, mutex: &sync.Mutex{},
name: name, name: name,
@ -124,15 +124,21 @@ func (channel *Channel) GetUsers(replier Replier) {
} }
func (channel *Channel) ClientIsOperator(client *Client) bool { func (channel *Channel) ClientIsOperator(client *Client) bool {
// TODO client-channel relations return channel.members.HasMode(client, ChannelOperator)
return false
} }
func (channel *Channel) Nicks() []string { func (channel *Channel) Nicks() []string {
nicks := make([]string, len(channel.members)) nicks := make([]string, len(channel.members))
i := 0 i := 0
for client := range channel.members { for client, modes := range channel.members {
nicks[i] = client.Nick() switch {
case modes[ChannelOperator]:
nicks[i] = "@" + client.Nick()
case modes[Voice]:
nicks[i] = "+" + client.Nick()
default:
nicks[i] = client.Nick()
}
i += 1 i += 1
} }
return nicks return nicks
@ -152,18 +158,32 @@ func (channel *Channel) String() string {
// <mode> <mode params> // <mode> <mode params>
func (channel *Channel) ModeString() (str string) { func (channel *Channel) ModeString() (str string) {
if channel.noOutside { if channel.key != "" {
str += NoOutside.String() str += Key.String()
} }
for mode := range channel.flags {
str += mode.String()
}
if len(str) > 0 { if len(str) > 0 {
str = "+" + str str = "+" + str
} }
if channel.key != "" {
str += " " + channel.key
}
return return
} }
func (channel *Channel) Join(client *Client) { func (channel *Channel) Join(client *Client) {
channel.mutex.Lock() channel.mutex.Lock()
channel.members.Add(client) channel.members.Add(client)
if len(channel.members) == 1 {
channel.members[client][ChannelCreator] = true
channel.members[client][ChannelOperator] = true
}
channel.mutex.Unlock() channel.mutex.Unlock()
client.channels.Add(channel) client.channels.Add(channel)
@ -180,7 +200,7 @@ func (channel *Channel) Join(client *Client) {
func (m *JoinCommand) HandleChannel(channel *Channel) { func (m *JoinCommand) HandleChannel(channel *Channel) {
client := m.Client() client := m.Client()
if channel.key != m.channels[channel.name] { if (channel.key != "") && (channel.key != m.channels[channel.name]) {
client.Reply(ErrBadChannelKey(channel)) client.Reply(ErrBadChannelKey(channel))
return return
} }
@ -218,6 +238,11 @@ func (m *TopicCommand) HandleChannel(channel *Channel) {
} }
if m.setTopic { if m.setTopic {
if channel.flags[OpOnlyTopic] {
client.Reply(ErrChanOPrivIsNeeded(channel))
return
}
channel.topic = m.topic channel.topic = m.topic
channel.GetTopic(client) channel.GetTopic(client)
reply := RplTopicMsg(client, channel) reply := RplTopicMsg(client, channel)
@ -232,7 +257,7 @@ func (m *TopicCommand) HandleChannel(channel *Channel) {
func (m *PrivMsgCommand) HandleChannel(channel *Channel) { func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
client := m.Client() client := m.Client()
if channel.noOutside && !channel.members.Has(client) { if channel.flags[NoOutside] && !channel.members.Has(client) {
client.Reply(ErrCannotSendToChan(channel)) client.Reply(ErrCannotSendToChan(channel))
return return
} }
@ -250,16 +275,70 @@ func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
client.Reply(RplBanList(channel, banMask)) client.Reply(RplBanList(channel, banMask))
} }
client.Reply(RplEndOfBanList(channel)) client.Reply(RplEndOfBanList(channel))
case NoOutside:
if channel.ClientIsOperator(client) { case NoOutside, Private, Secret, OpOnlyTopic:
switch modeOp.op { if !channel.ClientIsOperator(client) {
case Add:
channel.noOutside = true
case Remove:
channel.noOutside = false
}
} else {
client.Reply(ErrChanOPrivIsNeeded(channel)) client.Reply(ErrChanOPrivIsNeeded(channel))
continue
}
switch modeOp.op {
case Add:
channel.flags[modeOp.mode] = true
case Remove:
delete(channel.flags, modeOp.mode)
}
case Key:
if !channel.ClientIsOperator(client) {
client.Reply(ErrChanOPrivIsNeeded(channel))
continue
}
switch modeOp.op {
case Add:
if modeOp.arg == "" {
// TODO err reply
continue
}
channel.key = modeOp.arg
case Remove:
channel.key = ""
}
}
mmode := ChannelMemberMode(modeOp.mode)
switch mmode {
case ChannelOperator, Voice:
if !channel.ClientIsOperator(client) {
client.Reply(ErrChanOPrivIsNeeded(channel))
continue
}
if modeOp.arg == "" {
// TODO err reply
continue
}
target := channel.server.clients[modeOp.arg]
if target == nil {
// TODO err reply
continue
}
if channel.members[target] == nil {
// TODO err reply
continue
}
switch modeOp.op {
case Add:
channel.members[target][mmode] = true
case Remove:
channel.members[target][mmode] = false
} }
} }
} }
@ -269,7 +348,7 @@ func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
func (m *NoticeCommand) HandleChannel(channel *Channel) { func (m *NoticeCommand) HandleChannel(channel *Channel) {
client := m.Client() client := m.Client()
if channel.noOutside && !channel.members.Has(client) { if channel.flags[NoOutside] && !channel.members.Has(client) {
client.Reply(ErrCannotSendToChan(channel)) client.Reply(ErrCannotSendToChan(channel))
return return
} }

View File

@ -188,9 +188,9 @@ const (
Secret ChannelMode = 's' // flag Secret ChannelMode = 's' // flag
UserLimit ChannelMode = 'l' // flag arg UserLimit ChannelMode = 'l' // flag arg
ChannelCreator UserChannelMode = 'O' ChannelCreator ChannelMemberMode = 'O' // flag
ChannelOperator UserChannelMode = 'o' ChannelOperator ChannelMemberMode = 'o' // arg
Voice UserChannelMode = 'v' Voice ChannelMemberMode = 'v' // arg
) )
const ( const (

View File

@ -135,9 +135,9 @@ func (s *Server) listen(config ListenerConfig) {
} }
func (s *Server) GetOrMakeChannel(name string) *Channel { func (s *Server) GetOrMakeChannel(name string) *Channel {
channel := s.channels[name] channel, ok := s.channels[name]
if channel == nil { if !ok {
channel = NewChannel(s, name) channel = NewChannel(s, name)
s.channels[name] = channel s.channels[name] = channel
} }

View File

@ -38,7 +38,7 @@ func (mode ChannelMode) String() string {
} }
// user-channel mode flags // user-channel mode flags
type UserChannelMode rune type ChannelMemberMode rune
type ChannelNameMap map[string]*Channel type ChannelNameMap map[string]*Channel
@ -84,18 +84,29 @@ func (clients ClientNameMap) Remove(client *Client) error {
return nil return nil
} }
type ClientSet map[*Client]bool type ChannelMemberModeSet map[ChannelMemberMode]bool
type ClientSet map[*Client]ChannelMemberModeSet
func (clients ClientSet) Add(client *Client) { func (clients ClientSet) Add(client *Client) {
clients[client] = true clients[client] = make(ChannelMemberModeSet)
} }
func (clients ClientSet) Remove(client *Client) { func (clients ClientSet) Remove(client *Client) {
delete(clients, client) delete(clients, client)
} }
func (clients ClientSet) HasMode(client *Client, mode ChannelMemberMode) bool {
modes, ok := clients[client]
if !ok {
return false
}
return modes[mode]
}
func (clients ClientSet) Has(client *Client) bool { func (clients ClientSet) Has(client *Client) bool {
return clients[client] _, ok := clients[client]
return ok
} }
type ChannelSet map[*Channel]bool type ChannelSet map[*Channel]bool