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
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
@ -46,6 +46,11 @@ func (c *Channel) Join(client *Client, key string) {
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
c.AddMemberMode(client, ChannelModeOperator)
|
||||
if len(key) != 0 {
|
||||
c.SetKey(key)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var m irc.Message
|
||||
@ -66,6 +75,37 @@ func (c *Channel) Join(client *Client, key string) {
|
||||
}
|
||||
|
||||
//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))
|
||||
i := 0
|
||||
@ -73,36 +113,46 @@ func (c *Channel) Join(client *Client, key string) {
|
||||
allMembers[i] = member
|
||||
i++
|
||||
}
|
||||
|
||||
// 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++ {
|
||||
memberStr := "= " + c.Name + " :"
|
||||
memberStr := ""
|
||||
end := (i + 1) * 20
|
||||
if 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] {
|
||||
mClient, _ := client.Server.GetClientByNick(member)
|
||||
|
||||
if mClient != nil {
|
||||
if c.MemberHasMode(mClient, ChannelModeOperator) {
|
||||
memberStr += "@"
|
||||
} else if c.MemberHasMode(mClient, ChannelModeVoice) {
|
||||
memberStr += "+"
|
||||
}
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
// Part handles when a client leaves a channel
|
||||
@ -134,7 +184,7 @@ func (c *Channel) Quit(client *Client, message string) {
|
||||
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 {
|
||||
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 {
|
||||
c.membersMutex.RLock()
|
||||
defer c.membersMutex.RUnlock()
|
||||
@ -332,3 +383,69 @@ func (c *Channel) TopicCommand(client *Client, topic string) {
|
||||
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}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
@ -134,7 +134,7 @@ func (c *Client) Welcome() {
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
@ -157,10 +157,23 @@ func (c *Client) Welcome() {
|
||||
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)}}
|
||||
|
||||
err = c.Encode(&m)
|
||||
err := c.Encode(&m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
218
commands.go
218
commands.go
@ -2,6 +2,7 @@ package irc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"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
|
||||
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"}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Params: []string{client.Nickname}, Trailing: "Not enough parameters"}
|
||||
client.Encode(&m)
|
||||
return
|
||||
}
|
||||
@ -359,7 +360,7 @@ func TopicHandler(message *irc.Message, client *Client) {
|
||||
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"}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NOSUCHCHANNEL, Params: []string{client.Nickname, channelName}, Trailing: "No such channel"}
|
||||
client.Encode(&m)
|
||||
return
|
||||
}
|
||||
@ -380,7 +381,7 @@ 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"}
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -390,7 +391,7 @@ func AwayHandler(message *irc.Message, client *Client) {
|
||||
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"}
|
||||
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)
|
||||
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
|
||||
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"}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Params: []string{client.Nickname}, Trailing: "Not enough parameters"}
|
||||
client.Encode(&m)
|
||||
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
|
||||
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"}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_NEEDMOREPARAMS, Params: []string{client.Nickname}, 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"}
|
||||
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)
|
||||
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()}}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{client.Nickname, client.UserModeSet.String()}}
|
||||
client.Encode(&m)
|
||||
return
|
||||
}
|
||||
@ -445,7 +446,7 @@ func UserModeHandler(message *irc.Message, client *Client) {
|
||||
case ModeModifierAdd:
|
||||
case ModeModifierRemove:
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -454,7 +455,7 @@ func UserModeHandler(message *irc.Message, client *Client) {
|
||||
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"}
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Params: []string{client.Nickname}, Trailing: "Unknown MODE flag"}
|
||||
client.Encode(&m)
|
||||
return
|
||||
}
|
||||
@ -501,90 +502,173 @@ func ChannelModeHandler(message *irc.Message, client *Client) {
|
||||
}
|
||||
|
||||
if len(message.Params) == 1 { // just channel name is provided
|
||||
// return current settings for this user
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_UMODEIS, Params: []string{channel.GetMemberModes(client).String()}}
|
||||
// return current settings for this channel
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.RPL_CHANNELMODEIS, Params: []string{client.Nickname, channel.Name, channel.ChannelModeSet.String()}}
|
||||
client.Encode(&m)
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
setLimit := false
|
||||
getUsers := false
|
||||
needMask := false
|
||||
currentPlace := 1
|
||||
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
|
||||
*/
|
||||
type fullFlag struct {
|
||||
ModeModifier
|
||||
ChannelMode
|
||||
Param string
|
||||
}
|
||||
|
||||
for _, modeFlag := range modeFlags[1:] {
|
||||
mode := ChannelMode(modeFlag)
|
||||
_, ok := ChannelModes[mode]
|
||||
needsArgs := []fullFlag{}
|
||||
changes := []fullFlag{}
|
||||
argsCount := 0
|
||||
|
||||
if !ok {
|
||||
m := irc.Message{Prefix: client.Server.Prefix, Command: irc.ERR_UMODEUNKNOWNFLAG, Trailing: "Unknown MODE flag"}
|
||||
client.Encode(&m)
|
||||
return
|
||||
for _, param := range message.Params[1:] {
|
||||
if len(needsArgs) != 0 { // This param will be an arg
|
||||
mode := needsArgs[0]
|
||||
needsArgs = needsArgs[1:]
|
||||
argsCount++
|
||||
if argsCount > 3 { //Only allow 3 argument based flags per mode command
|
||||
break
|
||||
}
|
||||
|
||||
if modifier == ModeModifierAdd {
|
||||
|
||||
switch mode {
|
||||
case ChannelModeCreator: // Can't make oneself a creator
|
||||
case ChannelModeLimit:
|
||||
setLimit = true
|
||||
mode.Param = param
|
||||
switch mode.ChannelMode {
|
||||
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 {
|
||||
case ChannelModeCreator: // Can't remove oneself as creator
|
||||
//case ChannelModeBan: // Can't remove oneself from being restricted
|
||||
default:
|
||||
channel.RemoveMemberMode(client, mode)
|
||||
}
|
||||
} else { // This should be a mode flag or series of mode flags
|
||||
modifier := ModeModifierAdd
|
||||
for _, char := range param {
|
||||
mod := ModeModifier(char)
|
||||
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
|
||||
/*
|
||||
limit, err := strconv.Atoi(message.Params[currentPlace])
|
||||
if err != nil {
|
||||
|
||||
changeString := ""
|
||||
paramsChanged := []string{}
|
||||
previousMode := ModeModifier(' ')
|
||||
for _, change := range changes {
|
||||
if len(change.Param) != 0 {
|
||||
paramsChanged = append(paramsChanged, change.Param)
|
||||
}
|
||||
*/
|
||||
}
|
||||
if getUsers { // get users for either creating operators or adding voice
|
||||
|
||||
}
|
||||
if needMask { // Set the ban mask
|
||||
|
||||
if change.ModeModifier != previousMode {
|
||||
changeString += string(change.ModeModifier)
|
||||
}
|
||||
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()}}
|
||||
client.Encode(&m)
|
||||
params := []string{channel.Name, changeString}
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// UserMode - RFC 1459 Section 4.2.3.2 and RFC 2812 Section 3.1.5
|
||||
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
|
||||
func (c *ChannelModeSet) RemoveMode(mode ChannelMode) {
|
||||
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
|
||||
func (c *ChannelModeSet) String() string {
|
||||
s := ""
|
||||
if len(c.modes) > 0 {
|
||||
s = "+"
|
||||
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)
|
||||
params = append(params, param)
|
||||
}
|
||||
for _, param := range params {
|
||||
s += fmt.Sprintf(" %v", param)
|
||||
}
|
||||
|
||||
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) {
|
||||
h, ok := c.commands[message.Command]
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ type Server struct {
|
||||
type ServerConfig struct {
|
||||
Name string
|
||||
MOTD string
|
||||
Welcome string
|
||||
Version string
|
||||
TLSConfig *tls.Config
|
||||
Addr string
|
||||
|
||||
@ -49,6 +49,12 @@ func NewServer(config ServerConfig) *Server {
|
||||
s.clientsByNick = map[string]*Client{}
|
||||
s.Prefix = &irc.Prefix{Name: config.Name}
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user