Add +M (only registered/voice can speak) chanmode.

Add chanmode preventing speech to error message.

Fixes #1182.
This commit is contained in:
Alex Jaspersen 2020-09-19 11:01:58 -07:00
parent f9ca93118f
commit 504659abb5
7 changed files with 34 additions and 17 deletions

View File

@ -654,6 +654,18 @@ To unset this mode:
/MODE #test -R
### +M - Only Registered Users Can Speak
If this mode is set, only users that have logged into an account will be able to speak on the channel. If this is set and a regular, un-logged-in user tries to speak, they will be rejected. Users who have been voiced (+v) are excepted from this restriction.
To set this mode:
/MODE #test +M
To unset this mode:
/MODE #test -M
### +s - Secret
If this mode is set, it means that your channel should be marked as 'secret'. Your channel won't show up in `/LIST` or `/WHOIS`, and non-members won't be able to see its members with `/NAMES` or `/WHO`.

View File

@ -1188,22 +1188,25 @@ func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffe
channel.MarkDirty(IncludeTopic)
}
// CanSpeak returns true if the client can speak on this channel.
func (channel *Channel) CanSpeak(client *Client) bool {
// CanSpeak returns true if the client can speak on this channel, otherwise it returns false along with the channel mode preventing the client from speaking.
func (channel *Channel) CanSpeak(client *Client) (bool, modes.Mode) {
channel.stateMutex.RLock()
defer channel.stateMutex.RUnlock()
_, hasClient := channel.members[client]
if channel.flags.HasMode(modes.NoOutside) && !hasClient {
return false
return false, modes.NoOutside
}
if channel.flags.HasMode(modes.Moderated) && !channel.ClientIsAtLeast(client, modes.Voice) {
return false
return false, modes.Moderated
}
if channel.flags.HasMode(modes.RegisteredOnly) && client.Account() == "" {
return false
return false, modes.RegisteredOnly
}
return true
if channel.flags.HasMode(modes.RegisteredOnlySpeak) && client.Account() == "" && !channel.ClientIsAtLeast(client, modes.Voice) {
return false, modes.RegisteredOnlySpeak
}
return true, modes.Mode('?')
}
func msgCommandToHistType(command string) (history.ItemType, error) {
@ -1225,9 +1228,9 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
return
}
if !channel.CanSpeak(client) {
if canSpeak, mode := channel.CanSpeak(client); !canSpeak {
if histType != history.Notice {
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, client.Nick(), channel.Name(), client.t("Cannot send to channel"))
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, client.Nick(), channel.Name(), fmt.Sprintf(client.t("Cannot send to channel (+%s)"), mode))
}
return
}

View File

@ -1250,7 +1250,7 @@ func (config *Config) generateISupport() (err error) {
isupport.Add("BOT", "B")
isupport.Add("CASEMAPPING", "ascii")
isupport.Add("CHANLIMIT", fmt.Sprintf("%s:%d", chanTypes, config.Channels.MaxChannelsPerClient))
isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), modes.Modes{modes.Key}.String(), modes.Modes{modes.UserLimit}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret, modes.NoCTCP, modes.RegisteredOnly}.String()}, ","))
isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), modes.Modes{modes.Key}.String(), modes.Modes{modes.UserLimit}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret, modes.NoCTCP, modes.RegisteredOnly, modes.RegisteredOnlySpeak}.String()}, ","))
if config.History.Enabled && config.History.ChathistoryMax > 0 {
isupport.Add("draft/CHATHISTORY", strconv.Itoa(config.History.ChathistoryMax))
}

View File

@ -49,6 +49,7 @@ Oragono supports the following channel modes:
+n | No-outside-messages mode, only users that are on the channel can send
| messages to it.
+R | Only registered users can join the channel.
+M | Only registered or voiced users can speak in the channel.
+s | Secret mode, channel won't show up in /LIST or whois replies.
+t | Only channel opers can modify the topic.
+E | Roleplaying commands are enabled in the channel.

View File

@ -271,7 +271,7 @@ func (channel *Channel) ApplyChannelModeChanges(client *Client, isSamode bool, c
applied = append(applied, change)
}
case modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.RegisteredOnly, modes.Secret, modes.ChanRoleplaying, modes.NoCTCP:
case modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.RegisteredOnly, modes.Secret, modes.ChanRoleplaying, modes.NoCTCP, modes.RegisteredOnlySpeak:
if change.Op == modes.List {
continue
}

View File

@ -21,8 +21,8 @@ var (
// SupportedChannelModes are the channel modes that we support.
SupportedChannelModes = Modes{
BanMask, ChanRoleplaying, ExceptMask, InviteMask, InviteOnly, Key,
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, UserLimit,
NoCTCP,
Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, RegisteredOnlySpeak,
Secret, UserLimit, NoCTCP,
}
)
@ -122,6 +122,7 @@ const (
NoOutside Mode = 'n' // flag
OpOnlyTopic Mode = 't' // flag
// RegisteredOnly mode is reused here from umode definition
RegisteredOnlySpeak Mode = 'M' // flag
Secret Mode = 's' // flag
UserLimit Mode = 'l' // flag arg
NoCTCP Mode = 'C' // flag

View File

@ -74,8 +74,8 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
}
targetString = channel.Name()
if !channel.CanSpeak(client) {
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, targetString, client.t("Cannot send to channel"))
if canSpeak, mode := channel.CanSpeak(client); !canSpeak {
rb.Add(nil, client.server.name, ERR_CANNOTSENDTOCHAN, targetString, fmt.Sprintf(client.t("Cannot send to channel (+%s)"), mode))
return
}