Added proper parsing of channel modes.
Implemented parsing and storage of Channel Mode flags. Not all flags are currently being utilized.
This commit is contained in:
parent
a6e09ed19f
commit
2ef0464d1d
137
channel.go
137
channel.go
@ -36,9 +36,9 @@ func (c *Channel) Join(client *Client, key string) {
|
|||||||
if c.HasMember(client) { // 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 c.HasMode(ChannelModeKey) { //if key is required, verify that client provided matching key
|
||||||
if c.Key != key {
|
if c.Key != key {
|
||||||
m := irc.Message{Command: irc.ERR_BADCHANNELKEY}
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.ERR_BADCHANNELKEY, Params: []string{client.Nickname, c.Name}, Trailing: "Cannot join channel (+k)"}
|
||||||
err := client.Encode(&m)
|
err := client.Encode(&m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
@ -46,6 +46,11 @@ func (c *Channel) Join(client *Client, key string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.HasMode(ChannelModeLimit) && c.GetMemberCount() >= c.GetLimit() { // Limit flag is set and limit is met
|
||||||
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.ERR_CHANNELISFULL, Params: []string{client.Nickname, c.Name}, Trailing: "Cannot join channel (+l)"}
|
||||||
|
client.Encode(&m)
|
||||||
|
}
|
||||||
|
|
||||||
creator := c.GetMemberCount() == 0
|
creator := c.GetMemberCount() == 0
|
||||||
|
|
||||||
c.AddMember(client)
|
c.AddMember(client)
|
||||||
@ -55,6 +60,10 @@ func (c *Channel) Join(client *Client, key string) {
|
|||||||
// 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)
|
||||||
|
if len(key) != 0 {
|
||||||
|
c.SetKey(key)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var m irc.Message
|
var m irc.Message
|
||||||
@ -66,6 +75,37 @@ func (c *Channel) Join(client *Client, key string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Notify existing members that new member is joining
|
//Notify existing members that new member is joining
|
||||||
|
m = irc.Message{Prefix: client.Prefix, Command: irc.JOIN, Params: []string{c.Name}}
|
||||||
|
c.SendMessage(&m)
|
||||||
|
|
||||||
|
c.Names(client)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKey sets the channel key
|
||||||
|
func (c *Channel) SetKey(key string) {
|
||||||
|
c.AddModeWithValue(ChannelModeKey, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKey gets the key for the channel
|
||||||
|
func (c *Channel) GetKey() string {
|
||||||
|
val := c.GetMode(ChannelModeKey)
|
||||||
|
if val == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return val.(string)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Names responds to to IRC NAMES command for the channel
|
||||||
|
func (c *Channel) Names(client *Client) {
|
||||||
|
|
||||||
|
if c.HasMode(ChannelModeSecret) && !c.HasMember(client) { // If channel is secret and client isn't a member, don't reveal it
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.HasMode(ChannelModePrivate) && !c.HasMember(client) { // If channel is private and client isn't a member, don't reply
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
allMembers := make([]string, len(c.members))
|
allMembers := make([]string, len(c.members))
|
||||||
i := 0
|
i := 0
|
||||||
@ -73,36 +113,46 @@ func (c *Channel) Join(client *Client, key string) {
|
|||||||
allMembers[i] = member
|
allMembers[i] = member
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
// send list of users in channel
|
// send list of users in channel
|
||||||
|
|
||||||
|
//channelPrefix := ""
|
||||||
|
// RFC 2812 defines other channel prefixes
|
||||||
|
channelPrefix := "="
|
||||||
|
if c.HasMode(ChannelModeSecret) {
|
||||||
|
channelPrefix = "@"
|
||||||
|
}
|
||||||
|
if c.HasMode(ChannelModePrivate) {
|
||||||
|
channelPrefix = "*"
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < (len(c.members)/20)+1; i++ {
|
for i := 0; i < (len(c.members)/20)+1; i++ {
|
||||||
memberStr := "= " + c.Name + " :"
|
memberStr := ""
|
||||||
end := (i + 1) * 20
|
end := (i + 1) * 20
|
||||||
if end > len(c.members) {
|
if end > len(c.members) {
|
||||||
end = len(c.members)
|
end = len(c.members)
|
||||||
}
|
}
|
||||||
m := irc.Message{Prefix: client.Prefix, Command: irc.JOIN, Params: []string{c.Name}}
|
|
||||||
for _, member := range allMembers[i*20 : end] {
|
for _, member := range allMembers[i*20 : end] {
|
||||||
mClient, _ := client.Server.GetClientByNick(member)
|
mClient, _ := client.Server.GetClientByNick(member)
|
||||||
|
|
||||||
if mClient != nil {
|
if mClient != nil {
|
||||||
if c.MemberHasMode(mClient, ChannelModeOperator) {
|
if c.MemberHasMode(mClient, ChannelModeOperator) {
|
||||||
memberStr += "@"
|
memberStr += "@"
|
||||||
|
} else if c.MemberHasMode(mClient, ChannelModeVoice) {
|
||||||
|
memberStr += "+"
|
||||||
}
|
}
|
||||||
memberStr += mClient.Nickname + " "
|
memberStr += mClient.Nickname + " "
|
||||||
|
|
||||||
mClient.Encode(&m)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
m = irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_NAMREPLY, Params: []string{client.Nickname, memberStr}}
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_NAMREPLY, Params: []string{client.Nickname, channelPrefix, c.Name}, Trailing: memberStr}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m = irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_ENDOFNAMES, Params: []string{client.Nickname, c.Name}, Trailing: "End of NAMES list"}
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_ENDOFNAMES, Params: []string{client.Nickname, c.Name}, Trailing: "End of NAMES list"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part handles when a client leaves a channel
|
// Part handles when a client leaves a channel
|
||||||
@ -134,7 +184,7 @@ func (c *Channel) Quit(client *Client, message string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m := irc.Message{Prefix: client.Prefix, Command: irc.QUIT}
|
m := irc.Message{Prefix: client.Prefix, Command: irc.QUIT, Params: []string{c.Name}}
|
||||||
if len(message) != 0 {
|
if len(message) != 0 {
|
||||||
m.Trailing = message
|
m.Trailing = message
|
||||||
}
|
}
|
||||||
@ -241,6 +291,7 @@ func (c *Channel) RemoveMemberMode(client *Client, mode ChannelMode) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMemberModes returns the Channel Modes active for a member
|
||||||
func (c *Channel) GetMemberModes(client *Client) *ChannelModeSet {
|
func (c *Channel) GetMemberModes(client *Client) *ChannelModeSet {
|
||||||
c.membersMutex.RLock()
|
c.membersMutex.RLock()
|
||||||
defer c.membersMutex.RUnlock()
|
defer c.membersMutex.RUnlock()
|
||||||
@ -332,3 +383,69 @@ func (c *Channel) TopicCommand(client *Client, topic string) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddBanMask sets the channel ban mask
|
||||||
|
func (c *Channel) AddBanMask(mask string) {
|
||||||
|
masks := c.GetBanMasks()
|
||||||
|
masks[mask] = nil
|
||||||
|
c.AddModeWithValue(ChannelModeBan, masks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBanMasks gets the ban masks for the channel
|
||||||
|
func (c *Channel) GetBanMasks() map[string]interface{} {
|
||||||
|
val := c.GetMode(ChannelModeBan)
|
||||||
|
if val == nil {
|
||||||
|
return make(map[string]interface{}, 0)
|
||||||
|
}
|
||||||
|
return val.(map[string]interface{})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddExceptionMask sets the channel exception mask
|
||||||
|
func (c *Channel) AddExceptionMask(mask string) {
|
||||||
|
masks := c.GetExceptionMasks()
|
||||||
|
masks[mask] = nil
|
||||||
|
c.AddModeWithValue(ChannelModeExceptionMask, masks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExceptionMasks gets the exception masks for the channel
|
||||||
|
func (c *Channel) GetExceptionMasks() map[string]interface{} {
|
||||||
|
val := c.GetMode(ChannelModeExceptionMask)
|
||||||
|
if val == nil {
|
||||||
|
return make(map[string]interface{}, 0)
|
||||||
|
}
|
||||||
|
return val.(map[string]interface{})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInvitationMask sets the channel invitation mask
|
||||||
|
func (c *Channel) AddInvitationMask(mask string) {
|
||||||
|
masks := c.GetInvitationMasks()
|
||||||
|
masks[mask] = nil
|
||||||
|
c.AddModeWithValue(ChannelModeInvitationMask, masks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInvitationMasks gets the invitation masks for the channel
|
||||||
|
func (c *Channel) GetInvitationMasks() map[string]interface{} {
|
||||||
|
val := c.GetMode(ChannelModeInvitationMask)
|
||||||
|
if val == nil {
|
||||||
|
return make(map[string]interface{}, 0)
|
||||||
|
}
|
||||||
|
return val.(map[string]interface{})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLimit sets the channel member limit
|
||||||
|
func (c *Channel) SetLimit(limit int) {
|
||||||
|
c.AddModeWithValue(ChannelModeLimit, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLimit gets the member limit for the channel
|
||||||
|
func (c *Channel) GetLimit() int {
|
||||||
|
val := c.GetMode(ChannelModeLimit)
|
||||||
|
if val == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return val.(int)
|
||||||
|
|
||||||
|
}
|
||||||
|
21
client.go
21
client.go
@ -126,7 +126,7 @@ func (c *Client) Welcome() {
|
|||||||
c.Prefix = &irc.Prefix{Name: c.Nickname, User: c.Name, 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, "Welcome to the Internet Relay Network", c.Prefix.String()}}
|
||||||
|
|
||||||
err := c.Encode(&m)
|
err := c.Encode(&m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -134,7 +134,7 @@ func (c *Client) Welcome() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m = irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_YOURHOST,
|
m = irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_YOURHOST,
|
||||||
Params: []string{c.Nickname, fmt.Sprintf("Your host is %s", c.Server.Config.Name)}}
|
Params: []string{c.Nickname, fmt.Sprintf("Your host is %s, running version %s", c.Server.Config.Name, c.Server.Config.Version)}}
|
||||||
|
|
||||||
err = c.Encode(&m)
|
err = c.Encode(&m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,10 +157,23 @@ func (c *Client) Welcome() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m = irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_MOTDSTART,
|
// Send MOTD
|
||||||
|
c.MOTD()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MOTD returns the Message of the Day of the server to the client
|
||||||
|
func (c *Client) MOTD() {
|
||||||
|
|
||||||
|
if len(c.Server.Config.MOTD) == 0 {
|
||||||
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.ERR_NOMOTD, Params: []string{c.Nickname}, Trailing: "MOTD File is missing"}
|
||||||
|
c.Encode(&m)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := irc.Message{Prefix: c.Server.Prefix, Command: irc.RPL_MOTDSTART,
|
||||||
Params: []string{c.Nickname, fmt.Sprintf("%s - Message of the day", c.Server.Config.Name)}}
|
Params: []string{c.Nickname, fmt.Sprintf("%s - Message of the day", c.Server.Config.Name)}}
|
||||||
|
|
||||||
err = c.Encode(&m)
|
err := c.Encode(&m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
218
commands.go
218
commands.go
@ -2,6 +2,7 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sorcix/irc"
|
"github.com/sorcix/irc"
|
||||||
@ -351,7 +352,7 @@ func whoLine(client *Client, channel *Channel, recipientClient string) string {
|
|||||||
// Implemented according to RFC 1459 Section 4.2.4 and RFC 2812 Section 3.2.4
|
// Implemented according to RFC 1459 Section 4.2.4 and RFC 2812 Section 3.2.4
|
||||||
func TopicHandler(message *irc.Message, client *Client) {
|
func TopicHandler(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, Params: []string{client.Nickname}, Trailing: "Not enough parameters"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -359,7 +360,7 @@ func TopicHandler(message *irc.Message, client *Client) {
|
|||||||
channelName := message.Params[0]
|
channelName := message.Params[0]
|
||||||
channel, ok := client.Server.GetChannel(channelName)
|
channel, ok := client.Server.GetChannel(channelName)
|
||||||
if !ok {
|
if !ok {
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOSUCHCHANNEL, Params: []string{channelName}, Trailing: "No such channel"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOSUCHCHANNEL, Params: []string{client.Nickname, channelName}, Trailing: "No such channel"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -380,7 +381,7 @@ func AwayHandler(message *irc.Message, client *Client) {
|
|||||||
if len(message.Params) == 0 && len(message.Trailing) == 0 {
|
if len(message.Params) == 0 && len(message.Trailing) == 0 {
|
||||||
client.AwayMessage = ""
|
client.AwayMessage = ""
|
||||||
client.RemoveMode(UserModeAway)
|
client.RemoveMode(UserModeAway)
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UNAWAY, Trailing: "You are no longer marked as being away"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UNAWAY, Params: []string{client.Nickname}, Trailing: "You are no longer marked as being away"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -390,7 +391,7 @@ func AwayHandler(message *irc.Message, client *Client) {
|
|||||||
client.AwayMessage = strings.Join(message.Params, " ")
|
client.AwayMessage = strings.Join(message.Params, " ")
|
||||||
}
|
}
|
||||||
client.AddMode(UserModeAway)
|
client.AddMode(UserModeAway)
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NOWAWAY, Trailing: "You have been marked as being away"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_NOWAWAY, Params: []string{client.Nickname}, Trailing: "You have been marked as being away"}
|
||||||
|
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
@ -401,7 +402,7 @@ func AwayHandler(message *irc.Message, client *Client) {
|
|||||||
// Implemented according to RFC 1459 Section 4.2.3 and RFC 2812 Section 3.1.5 and RFC 2811
|
// 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) {
|
func ModeHandler(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, Params: []string{client.Nickname}, Trailing: "Not enough parameters"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -420,21 +421,21 @@ func ModeHandler(message *irc.Message, client *Client) {
|
|||||||
// Implemented according to RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
|
// Implemented according to RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
|
||||||
func UserModeHandler(message *irc.Message, client *Client) {
|
func UserModeHandler(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, Params: []string{client.Nickname}, Trailing: "Not enough parameters"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
username := message.Params[0]
|
username := message.Params[0]
|
||||||
if username != client.Nickname {
|
if username != client.Nickname {
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_USERSDONTMATCH, Trailing: "Cannot change mode for other users"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_USERSDONTMATCH, Params: []string{client.Nickname}, Trailing: "Cannot change mode for other users"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(message.Params) == 1 { // just nickname is provided
|
if len(message.Params) == 1 { // just nickname is provided
|
||||||
// return current settings for this user
|
// return current settings for this user
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.UserModeSet.String()}}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.Nickname, client.UserModeSet.String()}}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -445,7 +446,7 @@ func UserModeHandler(message *irc.Message, client *Client) {
|
|||||||
case ModeModifierAdd:
|
case ModeModifierAdd:
|
||||||
case ModeModifierRemove:
|
case ModeModifierRemove:
|
||||||
default:
|
default:
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Params: []string{client.Nickname}, Trailing: "Unknown MODE flag"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -454,7 +455,7 @@ func UserModeHandler(message *irc.Message, client *Client) {
|
|||||||
mode := UserMode(modeFlag)
|
mode := UserMode(modeFlag)
|
||||||
_, ok := UserModes[mode]
|
_, ok := UserModes[mode]
|
||||||
if !ok || mode == UserModeAway { // Away flag should only be set with AWAY command
|
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"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Params: []string{client.Nickname}, Trailing: "Unknown MODE flag"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -501,90 +502,173 @@ func ChannelModeHandler(message *irc.Message, client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(message.Params) == 1 { // just channel name is provided
|
if len(message.Params) == 1 { // just channel name is provided
|
||||||
// return current settings for this user
|
// return current settings for this channel
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{channel.GetMemberModes(client).String()}}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_CHANNELMODEIS, Params: []string{client.Nickname, channel.Name, channel.ChannelModeSet.String()}}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !channel.MemberHasMode(client, ChannelModeOperator) { // Only channel operators can make these changes
|
if !channel.MemberHasMode(client, ChannelModeOperator) { // Only channel operators can make these changes
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_CHANOPRIVSNEEDED, Params: []string{channel.Name}, Trailing: "You're not channel operator"}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_CHANOPRIVSNEEDED, Params: []string{client.Nickname, channel.Name}, Trailing: "You're not channel operator"}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setLimit := false
|
type fullFlag struct {
|
||||||
getUsers := false
|
ModeModifier
|
||||||
needMask := false
|
ChannelMode
|
||||||
currentPlace := 1
|
Param string
|
||||||
for _, modeFlags := range message.Params[1:] {
|
|
||||||
currentPlace++
|
|
||||||
modifier := ModeModifier(modeFlags[0])
|
|
||||||
switch modifier {
|
|
||||||
case ModeModifierAdd:
|
|
||||||
case ModeModifierRemove:
|
|
||||||
default:
|
|
||||||
//modifier := ModeModifierQuery
|
|
||||||
/*
|
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
|
|
||||||
client.Encode(&m)
|
|
||||||
return
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, modeFlag := range modeFlags[1:] {
|
needsArgs := []fullFlag{}
|
||||||
mode := ChannelMode(modeFlag)
|
changes := []fullFlag{}
|
||||||
_, ok := ChannelModes[mode]
|
argsCount := 0
|
||||||
|
|
||||||
if !ok {
|
for _, param := range message.Params[1:] {
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
|
if len(needsArgs) != 0 { // This param will be an arg
|
||||||
client.Encode(&m)
|
mode := needsArgs[0]
|
||||||
return
|
needsArgs = needsArgs[1:]
|
||||||
|
argsCount++
|
||||||
|
if argsCount > 3 { //Only allow 3 argument based flags per mode command
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
mode.Param = param
|
||||||
if modifier == ModeModifierAdd {
|
switch mode.ChannelMode {
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case ChannelModeCreator: // Can't make oneself a creator
|
|
||||||
case ChannelModeLimit:
|
|
||||||
setLimit = true
|
|
||||||
case ChannelModeOperator, ChannelModeVoice:
|
case ChannelModeOperator, ChannelModeVoice:
|
||||||
getUsers = true
|
n, ok := client.Server.GetClientByNick(param)
|
||||||
|
if ok {
|
||||||
|
found := channel.MemberHasMode(client, mode.ChannelMode)
|
||||||
|
if mode.ModeModifier == ModeModifierAdd {
|
||||||
|
channel.AddMemberMode(n, mode.ChannelMode)
|
||||||
|
if !found {
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channel.RemoveMemberMode(n, mode.ChannelMode)
|
||||||
|
if found {
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
}
|
||||||
channel.AddMemberMode(client, mode)
|
case ChannelModeLimit:
|
||||||
|
l, err := strconv.Atoi(param)
|
||||||
|
if err == nil {
|
||||||
|
channel.SetLimit(l)
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
case ChannelModeKey:
|
||||||
|
channel.SetKey(param)
|
||||||
|
changes = append(changes, mode)
|
||||||
|
case ChannelModeBan, ChannelModeExceptionMask, ChannelModeInvitationMask:
|
||||||
|
|
||||||
|
fillMask := func(mask string) string {
|
||||||
|
p := irc.ParsePrefix(param)
|
||||||
|
if len(p.Name) == 0 {
|
||||||
|
p.Name = "*"
|
||||||
|
}
|
||||||
|
if len(p.User) == 0 {
|
||||||
|
p.User = "*"
|
||||||
|
}
|
||||||
|
if len(p.Host) == 0 {
|
||||||
|
p.Host = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
mask := fillMask(param)
|
||||||
|
switch mode.ChannelMode {
|
||||||
|
case ChannelModeBan:
|
||||||
|
masks := channel.GetBanMasks()
|
||||||
|
_, ok := masks[mask]
|
||||||
|
if !ok {
|
||||||
|
channel.AddBanMask(mask)
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
case ChannelModeExceptionMask:
|
||||||
|
masks := channel.GetExceptionMasks()
|
||||||
|
_, ok := masks[mask]
|
||||||
|
if !ok {
|
||||||
|
channel.AddExceptionMask(mask)
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
case ChannelModeInvitationMask:
|
||||||
|
masks := channel.GetInvitationMasks()
|
||||||
|
_, ok := masks[mask]
|
||||||
|
if !ok {
|
||||||
|
channel.AddInvitationMask(mask)
|
||||||
|
changes = append(changes, mode)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if modifier == ModeModifierRemove {
|
}
|
||||||
switch mode {
|
} else { // This should be a mode flag or series of mode flags
|
||||||
case ChannelModeCreator: // Can't remove oneself as creator
|
modifier := ModeModifierAdd
|
||||||
//case ChannelModeBan: // Can't remove oneself from being restricted
|
for _, char := range param {
|
||||||
default:
|
mod := ModeModifier(char)
|
||||||
channel.RemoveMemberMode(client, mode)
|
switch mod { // Set if flag is adding a removing a mode
|
||||||
|
case ModeModifierAdd:
|
||||||
|
modifier = ModeModifierAdd
|
||||||
|
case ModeModifierRemove:
|
||||||
|
modifier = ModeModifierRemove
|
||||||
|
|
||||||
}
|
}
|
||||||
|
flag := ChannelMode(char)
|
||||||
|
switch flag {
|
||||||
|
case ChannelModeVoice, ChannelModeOperator, ChannelModeExceptionMask, ChannelModeInvitationMask, ChannelModeBan, ChannelModeLimit:
|
||||||
|
needsArgs = append(needsArgs, fullFlag{modifier, flag, ""})
|
||||||
|
case ChannelModeKey:
|
||||||
|
if modifier == ModeModifierAdd {
|
||||||
|
needsArgs = append(needsArgs, fullFlag{modifier, flag, ""})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if setLimit { // Get the number for setting the member limit cap
|
changeString := ""
|
||||||
/*
|
paramsChanged := []string{}
|
||||||
limit, err := strconv.Atoi(message.Params[currentPlace])
|
previousMode := ModeModifier(' ')
|
||||||
if err != nil {
|
for _, change := range changes {
|
||||||
|
if len(change.Param) != 0 {
|
||||||
|
paramsChanged = append(paramsChanged, change.Param)
|
||||||
}
|
}
|
||||||
*/
|
if change.ModeModifier != previousMode {
|
||||||
}
|
changeString += string(change.ModeModifier)
|
||||||
if getUsers { // get users for either creating operators or adding voice
|
|
||||||
|
|
||||||
}
|
|
||||||
if needMask { // Set the ban mask
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
changeString += string(change.ChannelMode)
|
||||||
|
previousMode = change.ModeModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.Nickname, client.UserModeSet.String()}}
|
params := []string{channel.Name, changeString}
|
||||||
client.Encode(&m)
|
params = append(params, paramsChanged...)
|
||||||
|
m := irc.Message{Prefix: client.Prefix, Command: irc.MODE, Params: params}
|
||||||
|
|
||||||
|
// Notify channel members of channel changes
|
||||||
|
channel.SendMessage(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NamesHandler is a specialized CommandHandler to respond to channel IRC NAMES commands from a client
|
||||||
|
// Implemented according to RFC 1459 Section 4.2.5 and RFC 2812 Section 3.2.5
|
||||||
|
func NamesHandler(message *irc.Message, client *Client) {
|
||||||
|
if len(message.Params) == 0 { // Send NAMES response for all channels
|
||||||
|
for _, ch := range client.Server.channels {
|
||||||
|
ch.Names(client)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channelNames := strings.Split(message.Params[0], ",")
|
||||||
|
for _, channelName := range channelNames {
|
||||||
|
ch, ok := client.Server.GetChannel(channelName)
|
||||||
|
if ok {
|
||||||
|
ch.Names(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
36
modes.go
36
modes.go
@ -1,6 +1,9 @@
|
|||||||
package irc
|
package irc
|
||||||
|
|
||||||
import "sync"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
// UserMode - RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
|
// UserMode - RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
|
||||||
type UserMode rune
|
type UserMode rune
|
||||||
@ -153,6 +156,13 @@ func (c *ChannelModeSet) AddMode(mode ChannelMode) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddModeWithValue adds a ChannelMode as active with a value
|
||||||
|
func (c *Channel) AddModeWithValue(mode ChannelMode, value interface{}) {
|
||||||
|
c.mutex.Lock()
|
||||||
|
defer c.mutex.Unlock()
|
||||||
|
c.modes[mode] = value
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveMode removes the given mode from the active set
|
// 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()
|
||||||
@ -170,14 +180,30 @@ func (c *ChannelModeSet) HasMode(mode ChannelMode) bool {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMode determines if the ChannelModeSet contains the given ChannelMode
|
||||||
|
func (c *ChannelModeSet) GetMode(mode ChannelMode) interface{} {
|
||||||
|
c.mutex.RLock()
|
||||||
|
defer c.mutex.RUnlock()
|
||||||
|
return c.modes[mode]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the ChannelModeSet formatted for the MODE queries
|
// String returns the ChannelModeSet formatted for the MODE queries
|
||||||
func (c *ChannelModeSet) String() string {
|
func (c *ChannelModeSet) String() string {
|
||||||
s := ""
|
s := "+"
|
||||||
if len(c.modes) > 0 {
|
|
||||||
s = "+"
|
params := []interface{}{}
|
||||||
|
for m, param := range c.modes {
|
||||||
|
switch m {
|
||||||
|
case ChannelModeKey, ChannelModeLimit, ChannelModeModerated, ChannelModeAnonymous, ChannelModeInviteOnly, ChannelModePrivate, ChannelModeSecret, ChannelModeTopic:
|
||||||
|
default:
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
for m := range c.modes {
|
|
||||||
s += string(m)
|
s += string(m)
|
||||||
|
params = append(params, param)
|
||||||
|
}
|
||||||
|
for _, param := range params {
|
||||||
|
s += fmt.Sprintf(" %v", param)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
2
mux.go
2
mux.go
@ -26,7 +26,7 @@ func (c *CommandsMux) HandleFunc(command string, handler CommandHandlerFunc) {
|
|||||||
func (c *CommandsMux) ServeIRC(message *irc.Message, client *Client) {
|
func (c *CommandsMux) ServeIRC(message *irc.Message, client *Client) {
|
||||||
h, ok := c.commands[message.Command]
|
h, ok := c.commands[message.Command]
|
||||||
if !ok {
|
if !ok {
|
||||||
m := irc.Message{Command: irc.ERR_UNKNOWNCOMMAND}
|
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UNKNOWNCOMMAND, Params: []string{client.Nickname}}
|
||||||
client.Encode(&m)
|
client.Encode(&m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ type Server struct {
|
|||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Name string
|
Name string
|
||||||
MOTD string
|
MOTD string
|
||||||
Welcome string
|
Version string
|
||||||
TLSConfig *tls.Config
|
TLSConfig *tls.Config
|
||||||
Addr string
|
Addr string
|
||||||
|
|
||||||
@ -49,6 +49,12 @@ func NewServer(config ServerConfig) *Server {
|
|||||||
s.clientsByNick = map[string]*Client{}
|
s.clientsByNick = map[string]*Client{}
|
||||||
s.Prefix = &irc.Prefix{Name: config.Name}
|
s.Prefix = &irc.Prefix{Name: config.Name}
|
||||||
s.channels = map[string]*Channel{}
|
s.channels = map[string]*Channel{}
|
||||||
|
if len(s.Config.Name) == 0 {
|
||||||
|
s.Config.Name = "localhost"
|
||||||
|
}
|
||||||
|
if len(s.Config.Version) == 0 {
|
||||||
|
s.Config.Version = "1.0"
|
||||||
|
}
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user