diff --git a/irc/channel.go b/irc/channel.go index c18eddc7..b0bb276b 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -515,8 +515,13 @@ func channelUserModeHasPrivsOver(clientMode modes.Mode, targetMode modes.Mode) b func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) bool { channel.stateMutex.RLock() clientModes := channel.members[client] + founder := channel.registeredFounder channel.stateMutex.RUnlock() + if founder != "" && founder == client.Account() { + return true + } + for _, mode := range modes.ChannelUserModes { if clientModes.HasMode(mode) { return true diff --git a/irc/client.go b/irc/client.go index e702aa43..42845108 100644 --- a/irc/client.go +++ b/irc/client.go @@ -326,9 +326,7 @@ func (server *Server) RunClient(conn IRCConn) { session.idletimer.Initialize(session) session.resetFakelag() - for _, defaultMode := range config.Accounts.defaultUserModes { - client.SetMode(defaultMode, true) - } + ApplyUserModeChanges(client, config.Accounts.defaultUserModes, false, nil) if proxiedConn.Secure { client.SetMode(modes.TLS, true) } @@ -374,9 +372,7 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, chnames []string, alwaysOn: true, } - for _, defaultMode := range config.Accounts.defaultUserModes { - client.SetMode(defaultMode, true) - } + ApplyUserModeChanges(client, config.Accounts.defaultUserModes, false, nil) client.SetMode(modes.TLS, true) client.writerSemaphore.Initialize(1) diff --git a/irc/config.go b/irc/config.go index 1b25afc4..982afc3a 100644 --- a/irc/config.go +++ b/irc/config.go @@ -254,7 +254,7 @@ type AccountConfig struct { exemptedNets []net.IPNet } `yaml:"require-sasl"` DefaultUserModes *string `yaml:"default-user-modes"` - defaultUserModes modes.Modes + defaultUserModes modes.ModeChanges LDAP ldap.ServerConfig LoginThrottling ThrottleConfig `yaml:"login-throttling"` SkipServerPassword bool `yaml:"skip-server-password"` diff --git a/irc/modes.go b/irc/modes.go index 86912474..bfbfc271 100644 --- a/irc/modes.go +++ b/irc/modes.go @@ -23,7 +23,7 @@ var ( // DefaultUserModes are set on all users when they login. // this can be overridden in the `accounts` config, with the `default-user-modes` key - DefaultUserModes = modes.Modes{} + DefaultUserModes = modes.ModeChanges{} ) // ApplyUserModeChanges applies the given changes, and returns the applied changes. @@ -106,35 +106,32 @@ func ApplyUserModeChanges(client *Client, changes modes.ModeChanges, force bool, return applied } -// parseDefaultModes uses the provided mode change parser to parse the rawModes. -func parseDefaultModes(rawModes string, parser func(params ...string) (modes.ModeChanges, map[rune]bool)) modes.Modes { - modeChangeStrings := strings.Fields(rawModes) - modeChanges, _ := parser(modeChangeStrings...) - defaultModes := make(modes.Modes, 0) - for _, modeChange := range modeChanges { - if modeChange.Op == modes.Add { - defaultModes = append(defaultModes, modeChange.Mode) - } - } - return defaultModes -} - // ParseDefaultChannelModes parses the `default-modes` line of the config func ParseDefaultChannelModes(rawModes *string) modes.Modes { if rawModes == nil { // not present in config, fall back to compile-time default return DefaultChannelModes } - return parseDefaultModes(*rawModes, modes.ParseChannelModeChanges) + modeChangeStrings := strings.Fields(*rawModes) + modeChanges, _ := modes.ParseChannelModeChanges(modeChangeStrings...) + defaultChannelModes := make(modes.Modes, 0) + for _, modeChange := range modeChanges { + if modeChange.Op == modes.Add { + defaultChannelModes = append(defaultChannelModes, modeChange.Mode) + } + } + return defaultChannelModes } // ParseDefaultUserModes parses the `default-user-modes` line of the config -func ParseDefaultUserModes(rawModes *string) modes.Modes { +func ParseDefaultUserModes(rawModes *string) modes.ModeChanges { if rawModes == nil { // not present in config, fall back to compile-time default return DefaultUserModes } - return parseDefaultModes(*rawModes, modes.ParseUserModeChanges) + modeChangeStrings := strings.Fields(*rawModes) + modeChanges, _ := modes.ParseUserModeChanges(modeChangeStrings...) + return modeChanges } // ApplyChannelModeChanges applies a given set of mode changes. diff --git a/irc/modes_test.go b/irc/modes_test.go index 005d0555..ca7aa6a8 100644 --- a/irc/modes_test.go +++ b/irc/modes_test.go @@ -43,19 +43,19 @@ func TestParseDefaultUserModes(t *testing.T) { var parseTests = []struct { raw *string - expected modes.Modes + expected modes.ModeChanges }{ - {&iR, modes.Modes{modes.Invisible, modes.RegisteredOnly}}, - {&i, modes.Modes{modes.Invisible}}, - {&empty, modes.Modes{}}, - {&rminusi, modes.Modes{modes.RegisteredOnly}}, - {nil, modes.Modes{}}, + {&iR, modes.ModeChanges{{Mode: modes.Invisible, Op: modes.Add}, {Mode: modes.RegisteredOnly, Op: modes.Add}}}, + {&i, modes.ModeChanges{{Mode: modes.Invisible, Op: modes.Add}}}, + {&empty, modes.ModeChanges{}}, + {&rminusi, modes.ModeChanges{{Mode: modes.RegisteredOnly, Op: modes.Add}}}, + {nil, modes.ModeChanges{}}, } for _, testcase := range parseTests { result := ParseDefaultUserModes(testcase.raw) if !reflect.DeepEqual(result, testcase.expected) { - t.Errorf("expected modes %s, got %s", testcase.expected, result) + t.Errorf("expected modes %v, got %v", testcase.expected, result) } } }