3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

modes: Continue overhauling

This commit is contained in:
Daniel Oaks 2017-03-24 12:23:21 +10:00
parent 657ed644cb
commit 05074e966d
5 changed files with 266 additions and 246 deletions

View File

@ -18,8 +18,8 @@ import (
) )
type Channel struct { type Channel struct {
flags ChannelModeSet flags ModeSet
lists map[ChannelMode]*UserMaskSet lists map[Mode]*UserMaskSet
key string key string
membersMutex sync.RWMutex membersMutex sync.RWMutex
members MemberSet members MemberSet
@ -43,8 +43,8 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
} }
channel := &Channel{ channel := &Channel{
flags: make(ChannelModeSet), flags: make(ModeSet),
lists: map[ChannelMode]*UserMaskSet{ lists: map[Mode]*UserMaskSet{
BanMask: NewUserMaskSet(), BanMask: NewUserMaskSet(),
ExceptMask: NewUserMaskSet(), ExceptMask: NewUserMaskSet(),
InviteMask: NewUserMaskSet(), InviteMask: NewUserMaskSet(),
@ -110,14 +110,14 @@ func (channel *Channel) namesNoMutex(client *Client) {
} }
// ClientIsAtLeast returns whether the client has at least the given channel privilege. // ClientIsAtLeast returns whether the client has at least the given channel privilege.
func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode) bool { func (channel *Channel) ClientIsAtLeast(client *Client, permission Mode) bool {
channel.membersMutex.RLock() channel.membersMutex.RLock()
defer channel.membersMutex.RUnlock() defer channel.membersMutex.RUnlock()
return channel.clientIsAtLeastNoMutex(client, permission) return channel.clientIsAtLeastNoMutex(client, permission)
} }
func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission ChannelMode) bool { func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission Mode) bool {
// requires RLock() // requires RLock()
// get voice, since it's not a part of ChannelPrivModes // get voice, since it's not a part of ChannelPrivModes
@ -140,7 +140,7 @@ func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission Channe
} }
// Prefixes returns a list of prefixes for the given set of channel modes. // Prefixes returns a list of prefixes for the given set of channel modes.
func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string { func (modes ModeSet) Prefixes(isMultiPrefix bool) string {
var prefixes string var prefixes string
// add prefixes in order from highest to lowest privs // add prefixes in order from highest to lowest privs
@ -394,11 +394,11 @@ func (channel *Channel) CanSpeak(client *Client) bool {
} }
// TagMsg sends a tag message to everyone in this channel who can accept them. // TagMsg sends a tag message to everyone in this channel who can accept them.
func (channel *Channel) TagMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) { func (channel *Channel) TagMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client) {
channel.sendMessage(msgid, "TAGMSG", []Capability{MessageTags}, minPrefix, clientOnlyTags, client, nil) channel.sendMessage(msgid, "TAGMSG", []Capability{MessageTags}, minPrefix, clientOnlyTags, client, nil)
} }
func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) { func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *string) {
if !channel.CanSpeak(client) { if !channel.CanSpeak(client) {
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel") client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
return return
@ -408,7 +408,7 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability
defer channel.membersMutex.RUnlock() defer channel.membersMutex.RUnlock()
// for STATUSMSG // for STATUSMSG
var minPrefixMode ChannelMode var minPrefixMode Mode
if minPrefix != nil { if minPrefix != nil {
minPrefixMode = *minPrefix minPrefixMode = *minPrefix
} }
@ -445,16 +445,16 @@ func (channel *Channel) sendMessage(msgid, cmd string, requiredCaps []Capability
} }
// SplitPrivMsg sends a private message to everyone in this channel. // SplitPrivMsg sends a private message to everyone in this channel.
func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) { func (channel *Channel) SplitPrivMsg(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message) channel.sendSplitMessage(msgid, "PRIVMSG", minPrefix, clientOnlyTags, client, &message)
} }
// SplitNotice sends a private message to everyone in this channel. // SplitNotice sends a private message to everyone in this channel.
func (channel *Channel) SplitNotice(msgid string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) { func (channel *Channel) SplitNotice(msgid string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message SplitMessage) {
channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message) channel.sendSplitMessage(msgid, "NOTICE", minPrefix, clientOnlyTags, client, &message)
} }
func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) { func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *Mode, clientOnlyTags *map[string]ircmsg.TagValue, client *Client, message *SplitMessage) {
if !channel.CanSpeak(client) { if !channel.CanSpeak(client) {
client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel") client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
return return
@ -464,7 +464,7 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMo
defer channel.membersMutex.RUnlock() defer channel.membersMutex.RUnlock()
// for STATUSMSG // for STATUSMSG
var minPrefixMode ChannelMode var minPrefixMode Mode
if minPrefix != nil { if minPrefix != nil {
minPrefixMode = *minPrefix minPrefixMode = *minPrefix
} }
@ -489,7 +489,7 @@ func (channel *Channel) sendSplitMessage(msgid, cmd string, minPrefix *ChannelMo
} }
} }
func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode, func (channel *Channel) applyModeFlag(client *Client, mode Mode,
op ModeOp) bool { op ModeOp) bool {
if !channel.ClientIsAtLeast(client, ChannelOperator) { if !channel.ClientIsAtLeast(client, ChannelOperator) {
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator") client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
@ -514,8 +514,8 @@ func (channel *Channel) applyModeFlag(client *Client, mode ChannelMode,
return false return false
} }
func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode, func (channel *Channel) applyModeMemberNoMutex(client *Client, mode Mode,
op ModeOp, nick string) *ChannelModeChange { op ModeOp, nick string) *ModeChange {
// requires Lock() // requires Lock()
if nick == "" { if nick == "" {
@ -542,7 +542,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
return nil return nil
} }
channel.members[target][mode] = true channel.members[target][mode] = true
return &ChannelModeChange{ return &ModeChange{
op: Add, op: Add,
mode: mode, mode: mode,
arg: nick, arg: nick,
@ -553,7 +553,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
return nil return nil
} }
channel.members[target][mode] = false channel.members[target][mode] = false
return &ChannelModeChange{ return &ModeChange{
op: Remove, op: Remove,
mode: mode, mode: mode,
arg: nick, arg: nick,
@ -562,7 +562,7 @@ func (channel *Channel) applyModeMemberNoMutex(client *Client, mode ChannelMode,
return nil return nil
} }
func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) { func (channel *Channel) ShowMaskList(client *Client, mode Mode) {
//TODO(dan): WE NEED TO fiX this PROPERLY //TODO(dan): WE NEED TO fiX this PROPERLY
log.Fatal("Implement ShowMaskList") log.Fatal("Implement ShowMaskList")
/* /*
@ -572,7 +572,7 @@ func (channel *Channel) ShowMaskList(client *Client, mode ChannelMode) {
client.RplEndOfMaskList(mode, channel)*/ client.RplEndOfMaskList(mode, channel)*/
} }
func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeOp, mask string) bool { func (channel *Channel) applyModeMask(client *Client, mode Mode, op ModeOp, mask string) bool {
list := channel.lists[mode] list := channel.lists[mode]
if list == nil { if list == nil {
// This should never happen, but better safe than panicky. // This should never happen, but better safe than panicky.

View File

@ -43,7 +43,7 @@ type Client struct {
channels ChannelSet channels ChannelSet
class *OperClass class *OperClass
ctime time.Time ctime time.Time
flags map[UserMode]bool flags map[Mode]bool
isDestroyed bool isDestroyed bool
isQuitting bool isQuitting bool
hasQuit bool hasQuit bool
@ -83,7 +83,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
capVersion: Cap301, capVersion: Cap301,
channels: make(ChannelSet), channels: make(ChannelSet),
ctime: now, ctime: now,
flags: make(map[UserMode]bool), flags: make(map[Mode]bool),
monitoring: make(map[string]bool), monitoring: make(map[string]bool),
server: server, server: server,
socket: &socket, socket: &socket,

View File

@ -178,8 +178,8 @@ func SplitChannelMembershipPrefixes(target string) (prefixes string, name string
} }
// GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes. // GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
func GetLowestChannelModePrefix(prefixes string) *ChannelMode { func GetLowestChannelModePrefix(prefixes string) *Mode {
var lowest *ChannelMode var lowest *Mode
if strings.Contains(prefixes, "+") { if strings.Contains(prefixes, "+") {
lowest = &Voice lowest = &Voice
@ -208,8 +208,8 @@ func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
return umodeHandler(server, client, msg) return umodeHandler(server, client, msg)
} }
// applyModeChanges applies the given changes, and returns the applied changes. // applyUserModeChanges applies the given changes, and returns the applied changes.
func (client *Client) applyModeChanges(ModeChanges) ModeChanges { func (client *Client) applyUserModeChanges(changes ModeChanges) ModeChanges {
applied := make(ModeChanges, 0) applied := make(ModeChanges, 0)
for _, change := range changes { for _, change := range changes {
@ -289,13 +289,13 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
op = ModeOp(mode) op = ModeOp(mode)
continue continue
} }
changes = append(changes, &ModeChange{ changes = append(changes, ModeChange{
mode: Mode(mode), mode: Mode(mode),
op: op, op: op,
}) })
} }
applied := target.applyModeChanges(changes) applied = target.applyUserModeChanges(changes)
} }
if len(applied) > 0 { if len(applied) > 0 {
@ -306,15 +306,219 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
return false return false
} }
////// // ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
////// func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
////// changes := make(ModeChanges, 0)
////// unknown := make(map[rune]bool)
//////
////// if len(params) > 1 {
////// modeArg := params[0]
////// op := ModeOp(modeArg[0])
////// if (op == Add) || (op == Remove) {
modeArg = modeArg[1:]
} else {
unknown[rune(modeArg[0])] = true
return changes, unknown
}
skipArgs := 1
for _, mode := range modeArg {
if mode == '-' || mode == '+' {
op = ModeOp(mode)
continue
}
change := ModeChange{
mode: Mode(mode),
op: op,
}
// put arg into modechange if needed
switch Mode(mode) {
case BanMask, ExceptMask, InviteMask:
if len(params) > skipArgs {
change.arg = params[skipArgs]
skipArgs++
} else {
change.op = List
}
case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
if len(params) > skipArgs {
change.arg = params[skipArgs]
skipArgs++
} else {
continue
}
case Key, UserLimit:
// don't require value when removing
if change.op == Add {
if len(params) > skipArgs {
change.arg = params[skipArgs]
skipArgs++
} else {
continue
}
}
default:
unknown[mode] = true
}
changes = append(changes, change)
}
}
return changes, unknown
}
// ApplyChannelModeChanges applies a given set of mode changes.
func ApplyChannelModeChanges(channel *Channel, client *Client, isSamode bool, changes ModeChanges) ModeChanges {
// so we only output one warning for each list type when full
listFullWarned := make(map[Mode]bool)
clientIsOp := channel.clientIsAtLeastNoMutex(client, ChannelOperator)
var alreadySentPrivError bool
applied := make(ModeChanges, 0)
for _, change := range changes {
// chan priv modes are checked specially so ignore them
// means regular users can't view ban/except lists... but I'm not worried about that
if isSamode && ChannelModePrefixes[change.mode] == "" && !clientIsOp {
if !alreadySentPrivError {
alreadySentPrivError = true
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
}
continue
}
switch change.mode {
case BanMask, ExceptMask, InviteMask:
mask := change.arg
list := channel.lists[change.mode]
if list == nil {
// This should never happen, but better safe than panicky.
client.Send(nil, client.server.name, ERR_UNKNOWNERROR, client.nick, "MODE", "Could not complete MODE command")
return changes
}
if (change.op == List) || (mask == "") {
channel.ShowMaskList(client, change.mode)
continue
}
// confirm mask looks valid
mask, err := Casefold(mask)
if err != nil {
continue
}
switch change.op {
case Add:
if len(list.masks) >= client.server.limits.ChanListModes {
if !listFullWarned[change.mode] {
client.Send(nil, client.server.name, ERR_BANLISTFULL, client.nick, channel.name, change.mode.String(), "Channel list is full")
listFullWarned[change.mode] = true
}
continue
}
list.Add(mask)
applied = append(applied, change)
case Remove:
list.Remove(mask)
applied = append(applied, change)
}
case UserLimit:
switch change.op {
case Add:
val, err := strconv.ParseUint(change.arg, 10, 64)
if err == nil {
channel.userLimit = val
applied = append(applied, change)
}
case Remove:
channel.userLimit = 0
applied = append(applied, change)
}
case Key:
switch change.op {
case Add:
channel.key = change.arg
case Remove:
channel.key = ""
}
applied = append(applied, change)
case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret, ChanRoleplaying:
switch change.op {
case Add:
if channel.flags[change.mode] {
continue
}
channel.flags[change.mode] = true
applied = append(applied, change)
case Remove:
if !channel.flags[change.mode] {
continue
}
delete(channel.flags, change.mode)
applied = append(applied, change)
}
case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
// make sure client has privs to edit the given prefix
hasPrivs := isSamode
if !hasPrivs {
for _, mode := range ChannelPrivModes {
if channel.members[client][mode] {
hasPrivs = true
// Admins can't give other people Admin or remove it from others,
// standard for that channel mode, we worry about this later
if mode == ChannelAdmin && change.mode == ChannelAdmin {
hasPrivs = false
}
break
} else if mode == change.mode {
break
}
}
}
casefoldedName, err := CasefoldName(change.arg)
if err != nil {
continue
}
if !hasPrivs {
if change.op == Remove && casefoldedName == client.nickCasefolded {
// success!
} else {
if !alreadySentPrivError {
alreadySentPrivError = true
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
}
continue
}
}
change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
if change != nil {
applied = append(applied, *change)
}
}
}
return applied
}
// MODE <target> [<modestring> [<mode arguments>...]] // MODE <target> [<modestring> [<mode arguments>...]]
func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
@ -329,208 +533,24 @@ func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
return false return false
} }
// assemble changes // applied mode changes
//TODO(dan): split out assembling changes into func that returns changes, err applied := make(ModeChanges, 0)
changes := make(ChannelModeChanges, 0)
applied := make(ChannelModeChanges, 0)
// TODO(dan): look at separating these into the type A/B/C/D args and using those lists here if 1 < len(msg.Params) {
if len(msg.Params) > 1 { // parse out real mode changes
modeArg := msg.Params[1] params := msg.Params[1:]
op := ModeOp(modeArg[0]) changes, unknown := ParseChannelModeChanges(params...)
if (op == Add) || (op == Remove) {
modeArg = modeArg[1:] // alert for unknown mode changes
} else { for char := range unknown {
client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(modeArg[0]), "is an unknown mode character to me") client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(char), "is an unknown mode character to me")
}
if len(unknown) == 1 && len(changes) == 0 {
return false return false
} }
skipArgs := 2 // apply mode changes
for _, mode := range modeArg { applied = ApplyChannelModeChanges(channel, client, msg.Command == "SAMODE", changes)
if mode == '-' || mode == '+' {
op = ModeOp(mode)
continue
}
change := ChannelModeChange{
mode: ChannelMode(mode),
op: op,
}
// put arg into modechange if needed
switch ChannelMode(mode) {
case BanMask, ExceptMask, InviteMask:
if len(msg.Params) > skipArgs {
change.arg = msg.Params[skipArgs]
skipArgs++
} else {
change.op = List
}
case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
if len(msg.Params) > skipArgs {
change.arg = msg.Params[skipArgs]
skipArgs++
} else {
continue
}
case Key, UserLimit:
// don't require value when removing
if change.op == Add {
if len(msg.Params) > skipArgs {
change.arg = msg.Params[skipArgs]
skipArgs++
} else {
continue
}
}
}
changes = append(changes, &change)
}
// so we only output one warning for each list type when full
listFullWarned := make(map[ChannelMode]bool)
clientIsOp := channel.clientIsAtLeastNoMutex(client, ChannelOperator)
var alreadySentPrivError bool
for _, change := range changes {
// chan priv modes are checked specially so ignore them
// means regular users can't view ban/except lists... but I'm not worried about that
if msg.Command != "SAMODE" && ChannelModePrefixes[change.mode] == "" && !clientIsOp {
if !alreadySentPrivError {
alreadySentPrivError = true
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
}
continue
}
switch change.mode {
case BanMask, ExceptMask, InviteMask:
mask := change.arg
list := channel.lists[change.mode]
if list == nil {
// This should never happen, but better safe than panicky.
client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MODE", "Could not complete MODE command")
return false
}
if (change.op == List) || (mask == "") {
channel.ShowMaskList(client, change.mode)
continue
}
// confirm mask looks valid
mask, err = Casefold(mask)
if err != nil {
continue
}
switch change.op {
case Add:
if len(list.masks) >= server.limits.ChanListModes {
if !listFullWarned[change.mode] {
client.Send(nil, server.name, ERR_BANLISTFULL, client.nick, channel.name, change.mode.String(), "Channel list is full")
listFullWarned[change.mode] = true
}
continue
}
list.Add(mask)
applied = append(applied, change)
case Remove:
list.Remove(mask)
applied = append(applied, change)
}
case UserLimit:
switch change.op {
case Add:
val, err := strconv.ParseUint(change.arg, 10, 64)
if err == nil {
channel.userLimit = val
applied = append(applied, change)
}
case Remove:
channel.userLimit = 0
applied = append(applied, change)
}
case Key:
switch change.op {
case Add:
channel.key = change.arg
case Remove:
channel.key = ""
}
applied = append(applied, change)
case InviteOnly, Moderated, NoOutside, OpOnlyTopic, Secret, ChanRoleplaying:
switch change.op {
case Add:
if channel.flags[change.mode] {
continue
}
channel.flags[change.mode] = true
applied = append(applied, change)
case Remove:
if !channel.flags[change.mode] {
continue
}
delete(channel.flags, change.mode)
applied = append(applied, change)
}
case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
// make sure client has privs to edit the given prefix
var hasPrivs bool
if msg.Command == "SAMODE" {
hasPrivs = true
} else {
for _, mode := range ChannelPrivModes {
if channel.members[client][mode] {
hasPrivs = true
// Admins can't give other people Admin or remove it from others,
// standard for that channel mode, we worry about this later
if mode == ChannelAdmin && change.mode == ChannelAdmin {
hasPrivs = false
}
break
} else if mode == change.mode {
break
}
}
}
casefoldedName, err := CasefoldName(change.arg)
if err != nil {
continue
}
if !hasPrivs {
if change.op == Remove && casefoldedName == client.nickCasefolded {
// success!
} else {
if !alreadySentPrivError {
alreadySentPrivError = true
client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
}
continue
}
}
change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
if change != nil {
applied = append(applied, change)
}
}
}
} }
if len(applied) > 0 { if len(applied) > 0 {

View File

@ -339,7 +339,7 @@ func (server *Server) setISupport() {
server.isupport = NewISupportList() server.isupport = NewISupportList()
server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen)) server.isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
server.isupport.Add("CASEMAPPING", casemappingName) server.isupport.Add("CASEMAPPING", casemappingName)
server.isupport.Add("CHANMODES", strings.Join([]string{ChannelModes{BanMask, ExceptMask, InviteMask}.String(), "", ChannelModes{UserLimit, Key}.String(), ChannelModes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret}.String()}, ",")) server.isupport.Add("CHANMODES", strings.Join([]string{Modes{BanMask, ExceptMask, InviteMask}.String(), "", Modes{UserLimit, Key}.String(), Modes{InviteOnly, Moderated, NoOutside, OpOnlyTopic, ChanRoleplaying, Secret}.String()}, ","))
server.isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen)) server.isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
server.isupport.Add("CHANTYPES", "#") server.isupport.Add("CHANTYPES", "#")
server.isupport.Add("EXCEPTS", "") server.isupport.Add("EXCEPTS", "")
@ -376,7 +376,7 @@ func (server *Server) setISupport() {
server.isupport.RegenerateCachedReply() server.isupport.RegenerateCachedReply()
} }
func loadChannelList(channel *Channel, list string, maskMode ChannelMode) { func loadChannelList(channel *Channel, list string, maskMode Mode) {
if list == "" { if list == "" {
return return
} }
@ -1242,7 +1242,7 @@ func operHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
client.Send(nil, server.name, RPL_YOUREOPER, client.nick, "You are now an IRC operator") client.Send(nil, server.name, RPL_YOUREOPER, client.nick, "You are now an IRC operator")
//TODO(dan): Should this be sent automagically as part of setting the flag/mode? //TODO(dan): Should this be sent automagically as part of setting the flag/mode?
modech := ModeChanges{&ModeChange{ modech := ModeChanges{ModeChange{
mode: Operator, mode: Operator,
op: Add, op: Add,
}} }}
@ -1521,7 +1521,7 @@ func awayHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
client.Send(nil, server.name, RPL_UNAWAY, client.nick, "You are no longer marked as being away") client.Send(nil, server.name, RPL_UNAWAY, client.nick, "You are no longer marked as being away")
} }
//TODO(dan): Should this be sent automagically as part of setting the flag/mode? //TODO(dan): Should this be sent automagically as part of setting the flag/mode?
modech := ModeChanges{&ModeChange{ modech := ModeChanges{ModeChange{
mode: Away, mode: Away,
op: op, op: op,
}} }}

View File

@ -39,9 +39,9 @@ func (channels ChannelNameMap) Remove(channel *Channel) error {
return nil return nil
} }
type ChannelModeSet map[ChannelMode]bool type ModeSet map[Mode]bool
func (set ChannelModeSet) String() string { func (set ModeSet) String() string {
if len(set) == 0 { if len(set) == 0 {
return "" return ""
} }
@ -68,10 +68,10 @@ func (clients ClientSet) Has(client *Client) bool {
return clients[client] return clients[client]
} }
type MemberSet map[*Client]ChannelModeSet type MemberSet map[*Client]ModeSet
func (members MemberSet) Add(member *Client) { func (members MemberSet) Add(member *Client) {
members[member] = make(ChannelModeSet) members[member] = make(ModeSet)
} }
func (members MemberSet) Remove(member *Client) { func (members MemberSet) Remove(member *Client) {
@ -83,7 +83,7 @@ func (members MemberSet) Has(member *Client) bool {
return ok return ok
} }
func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool { func (members MemberSet) HasMode(member *Client, mode Mode) bool {
modes, ok := members[member] modes, ok := members[member]
if !ok { if !ok {
return false return false
@ -91,7 +91,7 @@ func (members MemberSet) HasMode(member *Client, mode ChannelMode) bool {
return modes[mode] return modes[mode]
} }
func (members MemberSet) AnyHasMode(mode ChannelMode) bool { func (members MemberSet) AnyHasMode(mode Mode) bool {
for _, modes := range members { for _, modes := range members {
if modes[mode] { if modes[mode] {
return true return true