Started adding support for Modes.

Added support for the following commands:
*  TOPIC
*  AWAY
*  MODE (just usermode support for now)
This commit is contained in:
justin 2015-08-05 11:33:06 -04:00
parent db91c5e08b
commit b354ba7187
4 changed files with 377 additions and 45 deletions

View File

@ -10,11 +10,11 @@ import (
// Channel represents an IRC channel or room
type Channel struct {
Name string
Modes ChannelModeSet
*ChannelModeSet
Topic string
Key string
members map[string]ChannelModeSet
members map[string]*ChannelModeSet
membersMutex sync.RWMutex
Server *Server
@ -23,17 +23,17 @@ type Channel struct {
// NewChannel creates and returns a new Channel
func NewChannel(s *Server, creator *Client) *Channel {
c := &Channel{}
c.members = map[string]ChannelModeSet{}
c.members = map[string]*ChannelModeSet{}
c.Server = s
c.Modes = NewChannelModeSet()
c.ChannelModeSet = NewChannelModeSet()
return c
}
// Join handles a client joining the channel and notifies other channel members
func (c *Channel) Join(client *Client, key string) {
_, ok := c.members[client.Nickname]
if ok { // client is already in this channel
if c.HasMember(client) { // client is already in this channel
return
}
if len(c.Key) != 0 { //if key is required, verify that client provided matching key
@ -46,13 +46,14 @@ func (c *Channel) Join(client *Client, key string) {
return
}
}
operator := len(c.members) == 0
creator := c.GetMemberCount() == 0
c.AddMember(client)
client.AddChannel(c)
if operator { // Client is creating channel
if creator { // Client is creating channel
// Creator should be a channel operator - Maybe check if it is a "safe" channel
c.AddMemberMode(client, ChannelModeOperator)
}
@ -85,6 +86,9 @@ func (c *Channel) Join(client *Client, key string) {
mClient, _ := client.Server.GetClientByNick(member)
if mClient != nil {
if c.MemberHasMode(mClient, ChannelModeOperator) {
memberStr += "@"
}
memberStr += mClient.Nickname + " "
mClient.Encode(&m)
@ -104,8 +108,7 @@ func (c *Channel) Join(client *Client, key string) {
// Part handles when a client leaves a channel
func (c *Channel) Part(client *Client, message string) {
_, ok := c.members[client.Nickname]
if !ok { // client is not in this channel
if !c.HasMember(client) { // client is not in this channel
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOTONCHANNEL, Params: []string{c.Name}, Trailing: "You're not on that channel"}
client.Encode(&m)
return
@ -125,8 +128,7 @@ func (c *Channel) Part(client *Client, message string) {
// Quit is when a client quits the server - at channel level, similar to part
func (c *Channel) Quit(client *Client, message string) {
_, ok := c.members[client.Nickname]
if !ok { // client is not in this channel
if !c.HasMember(client) { // client is not in this channel
//m := irc.Message{Prefix: &irc.Prefix{Name: client.Server.config.Name}, Command: irc.ERR_NOTONCHANNEL, Params: []string{c.Name}, Trailing: "You're not on that channel"}
//client.Encode(&m)
return
@ -201,6 +203,21 @@ func (c *Channel) RemoveMember(client *Client) {
}
}
// HasMember returns if a client is an existing member of this channel
func (c *Channel) HasMember(client *Client) bool {
c.membersMutex.RLock()
defer c.membersMutex.RUnlock()
_, found := c.members[client.Nickname]
return found
}
// GetMemberCount returns how many users are currently on the channel
func (c *Channel) GetMemberCount() int {
c.membersMutex.RLock()
defer c.membersMutex.RUnlock()
return len(c.members)
}
// AddMemberMode adds a mode for the member of the channel
func (c *Channel) AddMemberMode(client *Client, mode ChannelMode) {
c.membersMutex.Lock()
@ -224,6 +241,23 @@ func (c *Channel) RemoveMemberMode(client *Client, mode ChannelMode) {
}
func (c *Channel) GetMemberModes(client *Client) *ChannelModeSet {
c.membersMutex.RLock()
defer c.membersMutex.RUnlock()
return c.members[client.Nickname]
}
// MemberHasMode returns whether the given client has the requested mode
func (c *Channel) MemberHasMode(client *Client, mode ChannelMode) bool {
c.membersMutex.RLock()
defer c.membersMutex.RUnlock()
member, ok := c.members[client.Nickname]
if !ok { //client is not a member in channel
return false
}
return member.HasMode(mode)
}
func (c *Channel) delete() {
if len(c.members) != 0 {
return
@ -234,7 +268,7 @@ func (c *Channel) delete() {
var channelStarters = map[uint8]interface{}{'&': nil, '#': nil, '+': nil, '!': nil}
// validName checks if it meets parameters found in rfc2812 1.3
// validName checks if it meets parameters found in RFC 2812 Section 1.3
func (c *Channel) validName() bool {
_, ok := channelStarters[c.Name[0]]
if !ok {
@ -253,3 +287,48 @@ func (c *Channel) validName() bool {
return true
}
// TopicCommand handles querying or modifying the channels topic
func (c *Channel) TopicCommand(client *Client, topic string) {
if !c.HasMember(client) { // Client isn't on this channel
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOTONCHANNEL, Params: []string{c.Name}, Trailing: "You're not on that channel"}
client.Encode(&m)
return
}
//Client is trying to get topic
if len(topic) == 0 { //Get channels topic
if len(c.Topic) == 0 { // No topic is not set
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NOTOPIC, Params: []string{c.Name}, Trailing: "No topic is set"}
client.Encode(&m)
return
}
// Return Channel topic
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_TOPIC, Params: []string{c.Name}, Trailing: c.Topic}
client.Encode(&m)
return
}
// Client is trying to set topic
// If client is the operator, he can set the topic always
isOp := c.MemberHasMode(client, ChannelModeOperator)
tMode := c.HasMode(ChannelModeTopic)
if isOp || !tMode { // Has permissions - operator or channel does not have +t mode
c.Topic = topic
//Notify channel members of new topic
m := irc.Message{Prefix: client.Prefix, Command: irc.TOPIC, Params: []string{c.Name}, Trailing: c.Topic}
c.SendMessage(&m)
return
}
// Don't have permissions to set topic
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_CHANOPRIVSNEEDED, Params: []string{c.Name}, Trailing: "You're not channel operator"}
client.Encode(&m)
return
}

View File

@ -33,6 +33,8 @@ type Client struct {
channels map[string]*Channel
channelMutex sync.Mutex
*UserModeSet
}
func (s *Server) newClient(ircConn *irc.Conn, conn net.Conn) *Client {
@ -40,6 +42,7 @@ func (s *Server) newClient(ircConn *irc.Conn, conn net.Conn) *Client {
client.authorized = len(s.Config.Password) == 0
client.idleTimer = time.AfterFunc(time.Minute, client.idle)
client.channels = map[string]*Channel{}
client.UserModeSet = NewUserModeSet()
return client
}
@ -53,13 +56,13 @@ func (c *Client) Close() error {
// Ping sends an IRC PING command to a client
func (c *Client) Ping() {
m := irc.Message{Command: irc.PING, Params: []string{"JuddBot"}, Trailing: "JuddBot"}
m := irc.Message{Command: irc.PING, Trailing: c.Server.Config.Name}
c.Encode(&m)
}
// Pong sends an IRC PONG command to the client
func (c *Client) Pong() {
m := irc.Message{Command: irc.PONG, Params: []string{"JuddBot"}, Trailing: "JuddBot"}
m := irc.Message{Command: irc.PONG, Trailing: c.Server.Config.Name}
c.Encode(&m)
}
@ -101,7 +104,7 @@ func (c *Client) idle() {
func (c *Client) quit() {
// Have client leave/part each channel
for _, channel := range c.GetChannels() {
channel.Quit(c, "")
channel.Quit(c, "Disconnected")
}
c.Quit()
}
@ -120,7 +123,7 @@ func (c *Client) Quit() {
func (c *Client) Welcome() {
// Have all client info now
c.Prefix = &irc.Prefix{Name: c.Nickname, User: c.Username, Host: c.Host}
c.Prefix = &irc.Prefix{Name: c.Nickname, User: c.Name, Host: c.Host}
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_WELCOME,
Params: []string{c.Nickname, c.Server.Config.Welcome}}

View File

@ -21,26 +21,30 @@ func (f CommandHandlerFunc) ServeIRC(message *irc.Message, client *Client) {
}
// PingHandler is a CommandHandler to respond to IRC PING commands from a client
// Implemented according to RFC 1459 4.6.2 and RFC 2812 3.7.2
// Implemented according to RFC 1459 Section 4.6.2 and RFC 2812 Section 3.7.2
func PingHandler(message *irc.Message, client *Client) {
client.Pong()
}
// PongHandler is a CommandHandler to respond to IRC PONG commands from a client
// Implemented according to RFC 1459 4.6.3 and RFC 2812 3.7.3
// Implemented according to RFC 1459 Section 4.6.3 and RFC 2812 Section 3.7.3
func PongHandler(message *irc.Message, client *Client) {
//client.Ping()
}
// QuitHandler is a CommandHandler to respond to IRC QUIT commands from a client
// Implemented according to RFC 1459 4.1.6 and RFC 2812 3.1.7
// Implemented according to RFC 1459 Section 4.1.6 and RFC 2812 Section 3.1.7
func QuitHandler(message *irc.Message, client *Client) {
var leavingMessage string
if len(message.Params) != 0 {
leavingMessage = message.Params[0]
} else if len(message.Trailing) != 0 {
leavingMessage = message.Trailing
} else {
leavingMessage = client.Nickname
}
for _, channel := range client.GetChannels() {
channel.Quit(client, leavingMessage)
@ -53,7 +57,7 @@ func QuitHandler(message *irc.Message, client *Client) {
}
// NickHandler is a CommandHandler to respond to IRC NICK commands from a client
// Implemented according to RFC 1459 4.1.2 and RFC 2812 3.1.2
// Implemented according to RFC 1459 Section 4.1.2 and RFC 2812 Section 3.1.2
func NickHandler(message *irc.Message, client *Client) {
var m irc.Message
@ -97,7 +101,7 @@ func NickHandler(message *irc.Message, client *Client) {
}
// UserHandler is a CommandHandler to respond to IRC USER commands from a client
// Implemented according to RFC 1459 4.1.3 and RFC 2812 3.1.3
// Implemented according to RFC 1459 Section 4.1.3 and RFC 2812 Section 3.1.3
func UserHandler(message *irc.Message, client *Client) {
var m irc.Message
serverName := client.Server.Config.Name
@ -136,7 +140,7 @@ func UserHandler(message *irc.Message, client *Client) {
}
// JoinHandler is a CommandHandler to respond to IRC JOIN commands from a client
// Implemented according to RFC 1459 4.2.1 and RFC 2812 3.2.1
// Implemented according to RFC 1459 Section 4.2.1 and RFC 2812 Section 3.2.1
func JoinHandler(message *irc.Message, client *Client) {
channelNames := message.Params[0]
if channelNames == "0" { // Leave all channels
@ -177,7 +181,7 @@ func JoinHandler(message *irc.Message, client *Client) {
}
// PartHandler is a CommandHandler to respond to IRC PART commands from a client
// Implemented according to RFC 1459 4.2.2 and RFC 2812 3.2.2
// Implemented according to RFC 1459 Section 4.2.2 and RFC 2812 Section 3.2.2
func PartHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Trailing: "Not enough parameters"}
@ -202,7 +206,7 @@ func PartHandler(message *irc.Message, client *Client) {
}
// PrivMsgHandler is a CommandHandler to respond to IRC PRIVMSG commands from a client
// Implemented according to RFC 1459 4.4.1 and RFC 2812 3.3.1
// Implemented according to RFC 1459 Section 4.4.1 and RFC 2812 Section 3.3.1
func PrivMsgHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NORECIPIENT, Params: []string{client.Nickname}, Trailing: "No recipient given (PRIVMSG)"}
@ -232,6 +236,12 @@ func PrivMsgHandler(message *irc.Message, client *Client) {
if ok {
m := irc.Message{Prefix: client.Prefix, Command: irc.PRIVMSG, Params: []string{cl.Nickname}, Trailing: message.Trailing}
cl.Encode(&m)
if cl.HasMode(UserModeAway) {
m := irc.Message{Prefix: cl.Server.Prefix, Command: irc.RPL_AWAY, Params: []string{client.Nickname, cl.Nickname}, Trailing: cl.AwayMessage}
client.Encode(&m)
}
return
}
@ -241,7 +251,7 @@ func PrivMsgHandler(message *irc.Message, client *Client) {
}
// NoticeHandler is a CommandHandler to respond to IRC NOTICE commands from a client
// Implemented according to RFC 1459 4.4.2 and RFC 2812 3.3.2
// Implemented according to RFC 1459 Section 4.4.2 and RFC 2812 Section 3.3.2
func NoticeHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NORECIPIENT, Params: []string{client.Nickname}, Trailing: "No recipient given (PRIVMSG)"}
@ -280,7 +290,7 @@ func NoticeHandler(message *irc.Message, client *Client) {
}
// WhoHandler is a CommandHandler to respond to IRC WHO commands from a client
// Implemented according to RFC 1459 4.5.1 and RFC 2812 3.6.1
// Implemented according to RFC 1459 Section 4.5.1 and RFC 2812 Section 3.6.1
func WhoHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
//return listing of all users
@ -292,13 +302,188 @@ func WhoHandler(message *irc.Message, client *Client) {
cl, found := client.Server.GetClientByNick(clientName)
if found {
msg := fmt.Sprintf("%s %s %s %s %s %s %s%s :%d %s", client.Nickname, ch.Name, cl.Name, cl.Host, client.Server.Config.Name, cl.Nickname, "H", "", 0, cl.RealName)
msg := whoLine(cl, ch, client.Nickname)
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_WHOREPLY, Params: strings.Fields(msg)}
client.Encode(&m)
}
}
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_ENDOFWHO, Params: []string{client.Nickname, ch.Name}, Trailing: "End of WHO list"}
} else {
// Not a channel, maybe a user
cl, ok := client.Server.GetClientByNick(message.Params[0])
if ok {
msg := whoLine(cl, nil, client.Nickname)
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_WHOREPLY, Params: strings.Fields(msg)}
client.Encode(&m)
}
}
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_ENDOFWHO, Params: []string{client.Nickname, message.Params[0]}, Trailing: "End of WHO list"}
client.Encode(&m)
}
func whoLine(client *Client, channel *Channel, recipientClient string) string {
channelName := "*"
here := "H"
if client.UserModeSet.HasMode(UserModeAway) {
here = "G"
}
opStatus := ""
if client.HasMode(UserModeOperator) || client.HasMode(UserModeLocalOperator) {
opStatus += "*"
}
if channel != nil {
channelName = channel.Name
if channel.MemberHasMode(client, ChannelModeOperator) {
opStatus += "@"
}
}
hopCount := 0 //For now only local clients allowed - no federation
return fmt.Sprintf("%s %s %s %s %s %s %s%s :%d %s", recipientClient, channelName, client.Name, client.Host, client.Server.Config.Name, client.Nickname, here, opStatus, hopCount, client.RealName)
}
// TopicHandler is a CommandHandler to respond to IRC TOPIC commands from a client
// Implemented according to RFC 1459 Section 4.2.4 and RFC 2812 Section 3.2.4
func TopicHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Trailing: "Not enough parameters"}
client.Encode(&m)
return
}
channelName := message.Params[0]
channel, ok := client.Server.GetChannel(channelName)
if !ok {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOSUCHCHANNEL, Params: []string{channelName}, Trailing: "No such channel"}
client.Encode(&m)
return
}
m := ""
if len(message.Params) > 1 {
m = message.Params[1]
} else {
m = message.Trailing
}
channel.TopicCommand(client, m)
}
// AwayHandler is a CommandHandler to respond to IRC AWAY commands from a client
// Implemented according to RFC 1459 Section 5.1 and RFC 2812 Section 4.1
func AwayHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 && len(message.Trailing) == 0 {
client.AwayMessage = ""
client.RemoveMode(UserModeAway)
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UNAWAY, Trailing: "You are no longer marked as being away"}
client.Encode(&m)
return
}
if len(message.Trailing) > 0 {
client.AwayMessage = message.Trailing
} else {
client.AwayMessage = strings.Join(message.Params, " ")
}
client.AddMode(UserModeAway)
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NOWAWAY, Trailing: "You have been marked as being away"}
client.Encode(&m)
return
}
// ModeHandler is a CommandHandler to respond to IRC MODE commands from a client
// Implemented according to RFC 1459 Section 4.2.3 and RFC 2812 Section 3.1.5 and RFC 2811
func ModeHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Trailing: "Not enough parameters"}
client.Encode(&m)
return
}
id := message.Params[0]
_, ok := client.Server.GetChannel(id)
if ok {
ChannelModeHandler(message, client)
return
}
UserModeHandler(message, client)
}
// UserModeHandler is a specialized CommandHandler to respond to global or user IRC MODE commands from a client
// Implemented according to RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
func UserModeHandler(message *irc.Message, client *Client) {
if len(message.Params) == 0 {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Trailing: "Not enough parameters"}
client.Encode(&m)
return
}
username := message.Params[0]
if username != client.Nickname {
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_USERSDONTMATCH, Trailing: "Cannot change mode for other users"}
client.Encode(&m)
return
}
if len(message.Params) == 1 { // just nickname is provided
// return current settings for this user
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.UserModeSet.String()}}
client.Encode(&m)
return
}
for _, modeFlags := range message.Params[1:] {
modifier := ModeModifier(modeFlags[0])
switch modifier {
case ModeModifierAdd:
case ModeModifierRemove:
default:
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
client.Encode(&m)
return
}
for _, modeFlag := range modeFlags[1:] {
mode := UserMode(modeFlag)
_, ok := UserModes[mode]
if !ok || mode == UserModeAway { // Away flag should only be set with AWAY command
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
client.Encode(&m)
return
}
if modifier == ModeModifierAdd {
switch mode {
case UserModeOperator, UserModeLocalOperator: // Can't make oneself an operator
default:
client.AddMode(mode)
}
} else if modifier == ModeModifierRemove {
switch mode {
case UserModeRestricted: // Can't remove oneself from being restricted
default:
client.RemoveMode(mode)
}
}
}
}
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.Nickname, client.UserModeSet.String()}}
client.Encode(&m)
return
}
// ChannelModeHandler is a specialized CommandHandler to respond to channel IRC MODE commands from a client
// Implemented according to RFC 1459 Section 4.2.3.1 and RFC 2811
func ChannelModeHandler(message *irc.Message, client *Client) {
}

View File

@ -2,7 +2,7 @@ package irc
import "sync"
// UserMode - RFC 1459 4.2.3.2 and RFC 2812 3.1.5
// UserMode - RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
type UserMode rune
const (
@ -15,6 +15,7 @@ const (
UserModeServerNotice UserMode = 's' //obsolete
)
// UserModes contains the supported User UserMode types
var UserModes = map[UserMode]interface{}{
UserModeAway: nil,
UserModeInvisible: nil,
@ -25,17 +26,20 @@ var UserModes = map[UserMode]interface{}{
UserModeServerNotice: nil,
}
// UserModeSet provides means for storing and checking UserModes
type UserModeSet struct {
userModes map[UserMode]interface{}
mutex sync.Mutex
mutex sync.RWMutex
}
func NewUserModeSet() UserModeSet {
// NewUserModeSet creates and returns a new UserModeSet
func NewUserModeSet() *UserModeSet {
u := UserModeSet{}
u.userModes = map[UserMode]interface{}{}
return u
return &u
}
// AddMode adds a mode to the UserModeSet
func (u *UserModeSet) AddMode(mode UserMode) {
u.mutex.Lock()
defer u.mutex.Unlock()
@ -43,6 +47,7 @@ func (u *UserModeSet) AddMode(mode UserMode) {
}
// RemoveMode removes a mode from the UserModeSet
func (u *UserModeSet) RemoveMode(mode UserMode) {
u.mutex.Lock()
defer u.mutex.Unlock()
@ -50,16 +55,28 @@ func (u *UserModeSet) RemoveMode(mode UserMode) {
}
// HasMode detects if a UserMode is contained in the UserModeSet
func (u *UserModeSet) HasMode(mode UserMode) bool {
u.mutex.RLock()
defer u.mutex.RUnlock()
_, found := u.userModes[mode]
return found
}
// String formats the UserModeString to be returned for MODE queries
func (u *UserModeSet) String() string {
s := ""
for m, _ := range u.userModes {
if len(u.userModes) > 0 {
s = "+"
}
for m := range u.userModes {
s += string(m)
}
return s
}
// ModeModifier - RFC 1459 4.2.3 and RFC 2812 3.1.5
// ModeModifier - RFC 1459 Section 4.2.3 and RFC 2812 Section 3.1.5
type ModeModifier rune
const (
@ -67,7 +84,7 @@ const (
ModeModifierRemove ModeModifier = '-'
)
// ChannelMode - RFC 1459 4.2.3.1 and RFC 2812 3.2.3 and RFC 2811 4
// ChannelMode - RFC 1459 Section 4.2.3.1 and RFC 2812 Section 3.2.3 and RFC 2811 Section 4
type ChannelMode rune
const (
@ -93,27 +110,75 @@ const (
ChannelModeInvitationMask ChannelMode = 'I'
)
// ChannelModes contains the supported channel modes
// Currently supported modes are just those in RFC 1459
var ChannelModes = map[ChannelMode]interface{}{
//ChannelModeCreator: nil,
ChannelModeOperator: nil,
ChannelModeVoice: nil,
//ChannelModeAnonymous: nil,
ChannelModeInviteOnly: nil,
ChannelModeModerated: nil,
ChannelModeNoOutsideMessages: nil,
//ChannelModeQuiet: nil,
ChannelModePrivate: nil,
ChannelModeSecret: nil,
//ChannelModeReOp: nil,
ChannelModeTopic: nil,
ChannelModeKey: nil,
ChannelModeLimit: nil,
ChannelModeBan: nil,
//ChannelModeExceptionMask: nil,
//ChannelModeInvitationMask: nil,
}
// ChannelModeSet represents a set of active ChannelModes
type ChannelModeSet struct {
Modes map[ChannelMode]interface{}
mutex sync.Mutex
modes map[ChannelMode]interface{}
mutex sync.RWMutex
}
func NewChannelModeSet() ChannelModeSet {
// NewChannelModeSet creates and returns a new ChannelModeSet
func NewChannelModeSet() *ChannelModeSet {
c := ChannelModeSet{}
c.Modes = map[ChannelMode]interface{}{}
return c
c.modes = map[ChannelMode]interface{}{}
return &c
}
// AddMode adds a ChannelMode as active
func (c *ChannelModeSet) AddMode(mode ChannelMode) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.Modes[mode] = nil
c.modes[mode] = nil
}
// RemoveMode removes the given mode from the active set
func (c *ChannelModeSet) RemoveMode(mode ChannelMode) {
c.mutex.Lock()
defer c.mutex.Unlock()
delete(c.Modes, mode)
delete(c.modes, mode)
}
// HasMode determines if the ChannelModeSet contains the given ChannelMode
func (c *ChannelModeSet) HasMode(mode ChannelMode) bool {
c.mutex.RLock()
defer c.mutex.RUnlock()
_, found := c.modes[mode]
return found
}
// String returns the ChannelModeSet formatted for the MODE queries
func (c *ChannelModeSet) String() string {
s := ""
if len(c.modes) > 0 {
s = "+"
}
for m := range c.modes {
s += string(m)
}
return s
}