diff --git a/.gitignore b/.gitignore index 42fa04fa..06b9cf19 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,8 @@ Temporary Items # Linux trash folder which might appear on any partition or disk .Trash-* +# vim swapfiles +*.swp ### Go ### # Compiled Object files, Static and Dynamic libs (Shared Objects) diff --git a/irc/channel.go b/irc/channel.go index 5a4ee2c1..89ec2bd1 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -57,7 +57,7 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel { } if addDefaultModes { - for _, mode := range DefaultChannelModes { + for _, mode := range s.defaultChannelModes { channel.flags[mode] = true } } diff --git a/irc/config.go b/irc/config.go index ac840f7e..9712324d 100644 --- a/irc/config.go +++ b/irc/config.go @@ -217,6 +217,7 @@ type Config struct { } Channels struct { + DefaultModes *string `yaml:"default-modes"` Registration ChannelRegistrationConfig } diff --git a/irc/modes.go b/irc/modes.go index f7a23772..457d1ee7 100644 --- a/irc/modes.go +++ b/irc/modes.go @@ -149,6 +149,7 @@ var ( supportedChannelModesString = SupportedChannelModes.String() // DefaultChannelModes are enabled on brand new channels when they're created. + // this can be overridden in the `channels` config, with the `default-modes` key DefaultChannelModes = Modes{ NoOutside, OpOnlyTopic, } @@ -385,6 +386,23 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool { return false } +// ParseDefaultChannelModes parses the `default-modes` line of the config +func ParseDefaultChannelModes(config *Config) Modes { + if config.Channels.DefaultModes == nil { + // not present in config, fall back to compile-time default + return DefaultChannelModes + } + modeChangeStrings := strings.Split(strings.TrimSpace(*config.Channels.DefaultModes), " ") + modeChanges, _ := ParseChannelModeChanges(modeChangeStrings...) + defaultChannelModes := make(Modes, 0) + for _, modeChange := range modeChanges { + if modeChange.op == Add { + defaultChannelModes = append(defaultChannelModes, modeChange.mode) + } + } + return defaultChannelModes +} + // ParseChannelModeChanges returns the valid changes, and the list of unknown chars. func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) { changes := make(ModeChanges, 0) @@ -392,6 +410,9 @@ func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) { if 0 < len(params) { modeArg := params[0] + if len(modeArg) == 0 { + return changes, unknown + } op := ModeOp(modeArg[0]) if (op == Add) || (op == Remove) { modeArg = modeArg[1:] diff --git a/irc/modes_test.go b/irc/modes_test.go new file mode 100644 index 00000000..930e9a56 --- /dev/null +++ b/irc/modes_test.go @@ -0,0 +1,36 @@ +// Copyright (c) 2017 Daniel Oaks +// released under the MIT license + +package irc + +import ( + "reflect" + "testing" +) + +func TestParseDefaultChannelModes(t *testing.T) { + nt := "+nt" + n := "+n" + empty := "" + tminusi := "+t -i" + + var parseTests = []struct { + raw *string + expected Modes + }{ + {&nt, Modes{NoOutside, OpOnlyTopic}}, + {&n, Modes{NoOutside}}, + {&empty, Modes{}}, + {&tminusi, Modes{OpOnlyTopic}}, + {nil, Modes{NoOutside, OpOnlyTopic}}, + } + + var config Config + for _, testcase := range parseTests { + config.Channels.DefaultModes = testcase.raw + result := ParseDefaultChannelModes(&config) + if !reflect.DeepEqual(result, testcase.expected) { + t.Errorf("expected modes %s, got %s", testcase.expected, result) + } + } +} diff --git a/irc/server.go b/irc/server.go index 484021c6..d569258d 100644 --- a/irc/server.go +++ b/irc/server.go @@ -97,6 +97,7 @@ type Server struct { connectionThrottleMutex sync.Mutex // used when affecting the connection limiter, to make sure rehashing doesn't make things go out-of-whack ctime time.Time currentOpers map[*Client]bool + defaultChannelModes Modes dlines *DLineManager isupport *ISupportList klines *KLineManager @@ -205,6 +206,7 @@ func NewServer(configFilename string, config *Config, logger *logger.Manager) (* connectionThrottle: connectionThrottle, ctime: time.Now(), currentOpers: make(map[*Client]bool), + defaultChannelModes: ParseDefaultChannelModes(config), limits: Limits{ AwayLen: int(config.Limits.AwayLen), ChannelLen: int(config.Limits.ChannelLen), @@ -1620,6 +1622,8 @@ func (server *Server) rehash() error { server.accountRegistration = &accountReg server.channelRegistrationEnabled = config.Channels.Registration.Enabled + server.defaultChannelModes = ParseDefaultChannelModes(config) + // set new sendqueue size if config.Server.MaxSendQBytes != server.MaxSendQBytes { server.MaxSendQBytes = config.Server.MaxSendQBytes diff --git a/oragono.yaml b/oragono.yaml index bfb961a8..427f7098 100644 --- a/oragono.yaml +++ b/oragono.yaml @@ -137,6 +137,11 @@ accounts: # channel options channels: + # modes that are set when new channels are created + # +n is no-external-messages and +t is op-only-topic + # see /QUOTE HELP cmodes for more channel modes + default-modes: +nt + # channel registration - requires an account registration: # can users register new channels?