Started adding support for Modes.
Added support for the following commands: * TOPIC * AWAY * MODE (just usermode support for now)
This commit is contained in:
		
							parent
							
								
									db91c5e08b
								
							
						
					
					
						commit
						b354ba7187
					
				
							
								
								
									
										105
									
								
								channel.go
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								channel.go
									
									
									
									
									
								
							@ -10,11 +10,11 @@ import (
 | 
				
			|||||||
// Channel represents an IRC channel or room
 | 
					// Channel represents an IRC channel or room
 | 
				
			||||||
type Channel struct {
 | 
					type Channel struct {
 | 
				
			||||||
	Name string
 | 
						Name string
 | 
				
			||||||
	Modes ChannelModeSet
 | 
						*ChannelModeSet
 | 
				
			||||||
	Topic string
 | 
						Topic string
 | 
				
			||||||
	Key   string
 | 
						Key   string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	members      map[string]ChannelModeSet
 | 
						members      map[string]*ChannelModeSet
 | 
				
			||||||
	membersMutex sync.RWMutex
 | 
						membersMutex sync.RWMutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Server *Server
 | 
						Server *Server
 | 
				
			||||||
@ -23,17 +23,17 @@ type Channel struct {
 | 
				
			|||||||
// NewChannel creates and returns a new Channel
 | 
					// NewChannel creates and returns a new Channel
 | 
				
			||||||
func NewChannel(s *Server, creator *Client) *Channel {
 | 
					func NewChannel(s *Server, creator *Client) *Channel {
 | 
				
			||||||
	c := &Channel{}
 | 
						c := &Channel{}
 | 
				
			||||||
	c.members = map[string]ChannelModeSet{}
 | 
						c.members = map[string]*ChannelModeSet{}
 | 
				
			||||||
	c.Server = s
 | 
						c.Server = s
 | 
				
			||||||
	c.Modes = NewChannelModeSet()
 | 
						c.ChannelModeSet = NewChannelModeSet()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c
 | 
						return c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Join handles a client joining the channel and notifies other channel members
 | 
					// Join handles a client joining the channel and notifies other channel members
 | 
				
			||||||
func (c *Channel) Join(client *Client, key string) {
 | 
					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
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(c.Key) != 0 { //if key is required, verify that client provided matching key
 | 
						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
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operator := len(c.members) == 0
 | 
						creator := c.GetMemberCount() == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.AddMember(client)
 | 
						c.AddMember(client)
 | 
				
			||||||
	client.AddChannel(c)
 | 
						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
 | 
							// Creator should be a channel operator - Maybe check if it is a "safe" channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c.AddMemberMode(client, ChannelModeOperator)
 | 
							c.AddMemberMode(client, ChannelModeOperator)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -85,6 +86,9 @@ func (c *Channel) Join(client *Client, key string) {
 | 
				
			|||||||
			mClient, _ := client.Server.GetClientByNick(member)
 | 
								mClient, _ := client.Server.GetClientByNick(member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if mClient != nil {
 | 
								if mClient != nil {
 | 
				
			||||||
 | 
									if c.MemberHasMode(mClient, ChannelModeOperator) {
 | 
				
			||||||
 | 
										memberStr += "@"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				memberStr += mClient.Nickname + " "
 | 
									memberStr += mClient.Nickname + " "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				mClient.Encode(&m)
 | 
									mClient.Encode(&m)
 | 
				
			||||||
@ -104,8 +108,7 @@ func (c *Channel) Join(client *Client, key string) {
 | 
				
			|||||||
// Part handles when a client leaves a channel
 | 
					// Part handles when a client leaves a channel
 | 
				
			||||||
func (c *Channel) Part(client *Client, message string) {
 | 
					func (c *Channel) Part(client *Client, message string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, ok := c.members[client.Nickname]
 | 
						if !c.HasMember(client) { // client is not  in this channel
 | 
				
			||||||
	if !ok { // 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"}
 | 
							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)
 | 
							client.Encode(&m)
 | 
				
			||||||
		return
 | 
							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
 | 
					// Quit is when a client quits the server - at channel level, similar to part
 | 
				
			||||||
func (c *Channel) Quit(client *Client, message string) {
 | 
					func (c *Channel) Quit(client *Client, message string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, ok := c.members[client.Nickname]
 | 
						if !c.HasMember(client) { // client is not  in this channel
 | 
				
			||||||
	if !ok { // 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"}
 | 
							//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)
 | 
							//client.Encode(&m)
 | 
				
			||||||
		return
 | 
							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
 | 
					// AddMemberMode adds a mode for the member of the channel
 | 
				
			||||||
func (c *Channel) AddMemberMode(client *Client, mode ChannelMode) {
 | 
					func (c *Channel) AddMemberMode(client *Client, mode ChannelMode) {
 | 
				
			||||||
	c.membersMutex.Lock()
 | 
						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() {
 | 
					func (c *Channel) delete() {
 | 
				
			||||||
	if len(c.members) != 0 {
 | 
						if len(c.members) != 0 {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@ -234,7 +268,7 @@ func (c *Channel) delete() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var channelStarters = map[uint8]interface{}{'&': nil, '#': nil, '+': nil, '!': nil}
 | 
					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 {
 | 
					func (c *Channel) validName() bool {
 | 
				
			||||||
	_, ok := channelStarters[c.Name[0]]
 | 
						_, ok := channelStarters[c.Name[0]]
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
@ -253,3 +287,48 @@ func (c *Channel) validName() bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								client.go
									
									
									
									
									
								
							@ -33,6 +33,8 @@ type Client struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	channels     map[string]*Channel
 | 
						channels     map[string]*Channel
 | 
				
			||||||
	channelMutex sync.Mutex
 | 
						channelMutex sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*UserModeSet
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *Server) newClient(ircConn *irc.Conn, conn net.Conn) *Client {
 | 
					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.authorized = len(s.Config.Password) == 0
 | 
				
			||||||
	client.idleTimer = time.AfterFunc(time.Minute, client.idle)
 | 
						client.idleTimer = time.AfterFunc(time.Minute, client.idle)
 | 
				
			||||||
	client.channels = map[string]*Channel{}
 | 
						client.channels = map[string]*Channel{}
 | 
				
			||||||
 | 
						client.UserModeSet = NewUserModeSet()
 | 
				
			||||||
	return client
 | 
						return client
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,13 +56,13 @@ func (c *Client) Close() error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Ping sends an IRC PING command to a client
 | 
					// Ping sends an IRC PING command to a client
 | 
				
			||||||
func (c *Client) Ping() {
 | 
					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)
 | 
						c.Encode(&m)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pong sends an IRC PONG command to the client
 | 
					// Pong sends an IRC PONG command to the client
 | 
				
			||||||
func (c *Client) Pong() {
 | 
					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)
 | 
						c.Encode(&m)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -101,7 +104,7 @@ func (c *Client) idle() {
 | 
				
			|||||||
func (c *Client) quit() {
 | 
					func (c *Client) quit() {
 | 
				
			||||||
	// Have client leave/part each channel
 | 
						// Have client leave/part each channel
 | 
				
			||||||
	for _, channel := range c.GetChannels() {
 | 
						for _, channel := range c.GetChannels() {
 | 
				
			||||||
		channel.Quit(c, "")
 | 
							channel.Quit(c, "Disconnected")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.Quit()
 | 
						c.Quit()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -120,7 +123,7 @@ func (c *Client) Quit() {
 | 
				
			|||||||
func (c *Client) Welcome() {
 | 
					func (c *Client) Welcome() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Have all client info now
 | 
						// 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,
 | 
						m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_WELCOME,
 | 
				
			||||||
		Params: []string{c.Nickname, c.Server.Config.Welcome}}
 | 
							Params: []string{c.Nickname, c.Server.Config.Welcome}}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										209
									
								
								commands.go
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								commands.go
									
									
									
									
									
								
							@ -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
 | 
					// 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) {
 | 
					func PingHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	client.Pong()
 | 
						client.Pong()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PongHandler is a CommandHandler to respond to IRC PONG commands from a client
 | 
					// 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) {
 | 
					func PongHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	//client.Ping()
 | 
						//client.Ping()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// QuitHandler is a CommandHandler to respond to IRC QUIT commands from a client
 | 
					// 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) {
 | 
					func QuitHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var leavingMessage string
 | 
						var leavingMessage string
 | 
				
			||||||
	if len(message.Params) != 0 {
 | 
						if len(message.Params) != 0 {
 | 
				
			||||||
		leavingMessage = 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() {
 | 
						for _, channel := range client.GetChannels() {
 | 
				
			||||||
		channel.Quit(client, leavingMessage)
 | 
							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
 | 
					// 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) {
 | 
					func NickHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var m irc.Message
 | 
						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
 | 
					// 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) {
 | 
					func UserHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	var m irc.Message
 | 
						var m irc.Message
 | 
				
			||||||
	serverName := client.Server.Config.Name
 | 
						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
 | 
					// 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) {
 | 
					func JoinHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	channelNames := message.Params[0]
 | 
						channelNames := message.Params[0]
 | 
				
			||||||
	if channelNames == "0" { // Leave all channels
 | 
						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
 | 
					// 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) {
 | 
					func PartHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	if len(message.Params) == 0 {
 | 
						if len(message.Params) == 0 {
 | 
				
			||||||
		m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Trailing: "Not enough parameters"}
 | 
							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
 | 
					// 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) {
 | 
					func PrivMsgHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	if len(message.Params) == 0 {
 | 
						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)"}
 | 
							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 {
 | 
						if ok {
 | 
				
			||||||
		m := irc.Message{Prefix: client.Prefix, Command: irc.PRIVMSG, Params: []string{cl.Nickname}, Trailing: message.Trailing}
 | 
							m := irc.Message{Prefix: client.Prefix, Command: irc.PRIVMSG, Params: []string{cl.Nickname}, Trailing: message.Trailing}
 | 
				
			||||||
		cl.Encode(&m)
 | 
							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
 | 
							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
 | 
					// 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) {
 | 
					func NoticeHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	if len(message.Params) == 0 {
 | 
						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)"}
 | 
							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
 | 
					// 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) {
 | 
					func WhoHandler(message *irc.Message, client *Client) {
 | 
				
			||||||
	if len(message.Params) == 0 {
 | 
						if len(message.Params) == 0 {
 | 
				
			||||||
		//return listing of all users
 | 
							//return listing of all users
 | 
				
			||||||
@ -292,13 +302,188 @@ func WhoHandler(message *irc.Message, client *Client) {
 | 
				
			|||||||
			cl, found := client.Server.GetClientByNick(clientName)
 | 
								cl, found := client.Server.GetClientByNick(clientName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if found {
 | 
								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)}
 | 
									m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_WHOREPLY, Params: strings.Fields(msg)}
 | 
				
			||||||
				client.Encode(&m)
 | 
									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)
 | 
						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) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										93
									
								
								modes.go
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								modes.go
									
									
									
									
									
								
							@ -2,7 +2,7 @@ package irc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "sync"
 | 
					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
 | 
					type UserMode rune
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@ -15,6 +15,7 @@ const (
 | 
				
			|||||||
	UserModeServerNotice  UserMode = 's' //obsolete
 | 
						UserModeServerNotice  UserMode = 's' //obsolete
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UserModes contains the supported User UserMode types
 | 
				
			||||||
var UserModes = map[UserMode]interface{}{
 | 
					var UserModes = map[UserMode]interface{}{
 | 
				
			||||||
	UserModeAway:          nil,
 | 
						UserModeAway:          nil,
 | 
				
			||||||
	UserModeInvisible:     nil,
 | 
						UserModeInvisible:     nil,
 | 
				
			||||||
@ -25,17 +26,20 @@ var UserModes = map[UserMode]interface{}{
 | 
				
			|||||||
	UserModeServerNotice:  nil,
 | 
						UserModeServerNotice:  nil,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UserModeSet provides means for storing and checking UserModes
 | 
				
			||||||
type UserModeSet struct {
 | 
					type UserModeSet struct {
 | 
				
			||||||
	userModes map[UserMode]interface{}
 | 
						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 := UserModeSet{}
 | 
				
			||||||
	u.userModes = map[UserMode]interface{}{}
 | 
						u.userModes = map[UserMode]interface{}{}
 | 
				
			||||||
	return u
 | 
						return &u
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddMode adds a mode to the UserModeSet
 | 
				
			||||||
func (u *UserModeSet) AddMode(mode UserMode) {
 | 
					func (u *UserModeSet) AddMode(mode UserMode) {
 | 
				
			||||||
	u.mutex.Lock()
 | 
						u.mutex.Lock()
 | 
				
			||||||
	defer u.mutex.Unlock()
 | 
						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) {
 | 
					func (u *UserModeSet) RemoveMode(mode UserMode) {
 | 
				
			||||||
	u.mutex.Lock()
 | 
						u.mutex.Lock()
 | 
				
			||||||
	defer u.mutex.Unlock()
 | 
						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 {
 | 
					func (u *UserModeSet) String() string {
 | 
				
			||||||
	s := ""
 | 
						s := ""
 | 
				
			||||||
	for m, _ := range u.userModes {
 | 
						if len(u.userModes) > 0 {
 | 
				
			||||||
 | 
							s = "+"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for m := range u.userModes {
 | 
				
			||||||
		s += string(m)
 | 
							s += string(m)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return s
 | 
						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
 | 
					type ModeModifier rune
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@ -67,7 +84,7 @@ const (
 | 
				
			|||||||
	ModeModifierRemove ModeModifier = '-'
 | 
						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
 | 
					type ChannelMode rune
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@ -93,27 +110,75 @@ const (
 | 
				
			|||||||
	ChannelModeInvitationMask ChannelMode = 'I'
 | 
						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 {
 | 
					type ChannelModeSet struct {
 | 
				
			||||||
	Modes map[ChannelMode]interface{}
 | 
						modes map[ChannelMode]interface{}
 | 
				
			||||||
	mutex sync.Mutex
 | 
						mutex sync.RWMutex
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewChannelModeSet() ChannelModeSet {
 | 
					// NewChannelModeSet creates and returns a new ChannelModeSet
 | 
				
			||||||
 | 
					func NewChannelModeSet() *ChannelModeSet {
 | 
				
			||||||
	c := ChannelModeSet{}
 | 
						c := ChannelModeSet{}
 | 
				
			||||||
	c.Modes = map[ChannelMode]interface{}{}
 | 
						c.modes = map[ChannelMode]interface{}{}
 | 
				
			||||||
	return c
 | 
						return &c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AddMode adds a ChannelMode as active
 | 
				
			||||||
func (c *ChannelModeSet) AddMode(mode ChannelMode) {
 | 
					func (c *ChannelModeSet) AddMode(mode ChannelMode) {
 | 
				
			||||||
	c.mutex.Lock()
 | 
						c.mutex.Lock()
 | 
				
			||||||
	defer c.mutex.Unlock()
 | 
						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) {
 | 
					func (c *ChannelModeSet) RemoveMode(mode ChannelMode) {
 | 
				
			||||||
	c.mutex.Lock()
 | 
						c.mutex.Lock()
 | 
				
			||||||
	defer c.mutex.Unlock()
 | 
						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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user