mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
implement CHANSERV AMODE
This commit is contained in:
parent
f142bf065d
commit
1016f86f70
@ -232,13 +232,7 @@ func (channel *Channel) ClientIsAtLeast(client *Client, permission modes.Mode) b
|
|||||||
|
|
||||||
clientModes := channel.members[client]
|
clientModes := channel.members[client]
|
||||||
|
|
||||||
// get voice, since it's not a part of ChannelPrivModes
|
for _, mode := range modes.ChannelUserModes {
|
||||||
if clientModes.HasMode(permission) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// check regular modes
|
|
||||||
for _, mode := range modes.ChannelPrivModes {
|
|
||||||
if clientModes.HasMode(mode) {
|
if clientModes.HasMode(mode) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goshuirc/irc-go/ircfmt"
|
"github.com/goshuirc/irc-go/ircfmt"
|
||||||
@ -42,6 +43,18 @@ remembered.`,
|
|||||||
helpShort: `$bREGISTER$b lets you own a given channel.`,
|
helpShort: `$bREGISTER$b lets you own a given channel.`,
|
||||||
authRequired: true,
|
authRequired: true,
|
||||||
},
|
},
|
||||||
|
"amode": {
|
||||||
|
handler: csAmodeHandler,
|
||||||
|
help: `Syntax: $bAMODE #channel [mode change] [account]$b
|
||||||
|
|
||||||
|
AMODE lists or modifies persistent mode settings that affect channel members.
|
||||||
|
For example, $bAMODE #channel +o dan$b grants the the holder of the "dan"
|
||||||
|
account the +o operator mode every time they join #channel. To list current
|
||||||
|
accounts and modes, use $bAMODE #channel$b. Note that users are always
|
||||||
|
referenced by their registered account names, not their nicknames.`,
|
||||||
|
helpShort: `$bAMODE$b modifies persistent mode settings for channel members.`,
|
||||||
|
authRequired: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +63,71 @@ func csNotice(rb *ResponseBuffer, text string) {
|
|||||||
rb.Add(nil, "ChanServ", "NOTICE", rb.target.Nick(), text)
|
rb.Add(nil, "ChanServ", "NOTICE", rb.target.Nick(), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func csAmodeHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
||||||
|
channelName, modeChange := utils.ExtractParam(params)
|
||||||
|
|
||||||
|
channel := server.channels.Get(channelName)
|
||||||
|
if channel == nil {
|
||||||
|
csNotice(rb, client.t("Channel does not exist"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clientAccount := client.Account()
|
||||||
|
if clientAccount == "" || clientAccount != channel.Founder() {
|
||||||
|
csNotice(rb, client.t("You must be the channel founder to use AMODE"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
modeChanges, unknown := modes.ParseChannelModeChanges(strings.Fields(modeChange)...)
|
||||||
|
|
||||||
|
if len(modeChanges) > 1 || len(unknown) > 0 {
|
||||||
|
csNotice(rb, client.t("Invalid mode change"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(modeChanges) == 0 || modeChanges[0].Op == modes.List {
|
||||||
|
persistentModes := channel.AccountToUmode()
|
||||||
|
// sort the persistent modes in descending order of priority, i.e.,
|
||||||
|
// ascending order of their index in the ChannelUserModes list
|
||||||
|
sort.Slice(persistentModes, func(i, j int) bool {
|
||||||
|
index := func(modeChange modes.ModeChange) int {
|
||||||
|
for idx, mode := range modes.ChannelUserModes {
|
||||||
|
if modeChange.Mode == mode {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(modes.ChannelUserModes)
|
||||||
|
}
|
||||||
|
return index(persistentModes[i]) < index(persistentModes[j])
|
||||||
|
})
|
||||||
|
csNotice(rb, fmt.Sprintf(client.t("Channel %s has %d persistent modes set"), channelName, len(persistentModes)))
|
||||||
|
for _, modeChange := range persistentModes {
|
||||||
|
csNotice(rb, fmt.Sprintf(client.t("Account %s receives mode +%s"), modeChange.Arg, string(modeChange.Mode)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accountIsValid := false
|
||||||
|
change := modeChanges[0]
|
||||||
|
// Arg is the account name, casefold it here
|
||||||
|
change.Arg, _ = CasefoldName(change.Arg)
|
||||||
|
if change.Arg != "" {
|
||||||
|
_, err := server.accounts.LoadAccount(change.Arg)
|
||||||
|
accountIsValid = (err == nil)
|
||||||
|
}
|
||||||
|
if !accountIsValid {
|
||||||
|
csNotice(rb, client.t("Account does not exist"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
applied := channel.ApplyAccountToUmodeChange(change)
|
||||||
|
if applied {
|
||||||
|
csNotice(rb, fmt.Sprintf(client.t("Successfully set mode %s"), change.String()))
|
||||||
|
go server.channelRegistry.StoreChannel(channel, IncludeLists)
|
||||||
|
} else {
|
||||||
|
csNotice(rb, client.t("Change was a no-op"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func csOpHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
func csOpHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
||||||
channelName, clientToOp := utils.ExtractParam(params)
|
channelName, clientToOp := utils.ExtractParam(params)
|
||||||
|
|
||||||
|
@ -303,3 +303,37 @@ func (channel *Channel) Founder() string {
|
|||||||
defer channel.stateMutex.RUnlock()
|
defer channel.stateMutex.RUnlock()
|
||||||
return channel.registeredFounder
|
return channel.registeredFounder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) AccountToUmode() (result []modes.ModeChange) {
|
||||||
|
channel.stateMutex.RLock()
|
||||||
|
defer channel.stateMutex.RUnlock()
|
||||||
|
for account, mode := range channel.accountToUMode {
|
||||||
|
result = append(result, modes.ModeChange{
|
||||||
|
Mode: mode,
|
||||||
|
Arg: account,
|
||||||
|
Op: modes.Add,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) ApplyAccountToUmodeChange(change modes.ModeChange) (applied bool) {
|
||||||
|
channel.stateMutex.Lock()
|
||||||
|
defer channel.stateMutex.Unlock()
|
||||||
|
|
||||||
|
current := channel.accountToUMode[change.Arg]
|
||||||
|
switch change.Op {
|
||||||
|
case modes.Add:
|
||||||
|
applied = (current != change.Mode)
|
||||||
|
if applied {
|
||||||
|
channel.accountToUMode[change.Arg] = change.Mode
|
||||||
|
}
|
||||||
|
case modes.Remove:
|
||||||
|
applied = (current == change.Mode)
|
||||||
|
if applied {
|
||||||
|
delete(channel.accountToUMode, change.Arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -147,6 +147,12 @@ var (
|
|||||||
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
|
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChannelUserModes holds the list of all modes that can be applied to a user in a channel,
|
||||||
|
// including Voice, in descending order of precedence
|
||||||
|
ChannelUserModes = Modes{
|
||||||
|
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice,
|
||||||
|
}
|
||||||
|
|
||||||
ChannelModePrefixes = map[Mode]string{
|
ChannelModePrefixes = map[Mode]string{
|
||||||
ChannelFounder: "~",
|
ChannelFounder: "~",
|
||||||
ChannelAdmin: "&",
|
ChannelAdmin: "&",
|
||||||
@ -176,20 +182,13 @@ 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) *Mode {
|
func GetLowestChannelModePrefix(prefixes string) (lowest *Mode) {
|
||||||
var lowest *Mode
|
for i, mode := range ChannelUserModes {
|
||||||
|
|
||||||
if strings.Contains(prefixes, "+") {
|
|
||||||
lowest = &Voice
|
|
||||||
} else {
|
|
||||||
for i, mode := range ChannelPrivModes {
|
|
||||||
if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
|
if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
|
||||||
lowest = &ChannelPrivModes[i]
|
lowest = &ChannelPrivModes[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return
|
||||||
|
|
||||||
return lowest
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -304,15 +303,12 @@ func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, supportedMode := range ChannelPrivModes {
|
for _, supportedMode := range ChannelUserModes {
|
||||||
if rune(supportedMode) == mode {
|
if rune(supportedMode) == mode {
|
||||||
isKnown = true
|
isKnown = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mode == rune(Voice) {
|
|
||||||
isKnown = true
|
|
||||||
}
|
|
||||||
if !isKnown {
|
if !isKnown {
|
||||||
unknown[mode] = true
|
unknown[mode] = true
|
||||||
continue
|
continue
|
||||||
@ -392,14 +388,11 @@ func (set *ModeSet) Prefixes(isMultiPrefix bool) (prefixes string) {
|
|||||||
defer set.RUnlock()
|
defer set.RUnlock()
|
||||||
|
|
||||||
// add prefixes in order from highest to lowest privs
|
// add prefixes in order from highest to lowest privs
|
||||||
for _, mode := range ChannelPrivModes {
|
for _, mode := range ChannelUserModes {
|
||||||
if set.modes[mode] {
|
if set.modes[mode] {
|
||||||
prefixes += ChannelModePrefixes[mode]
|
prefixes += ChannelModePrefixes[mode]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if set.modes[Voice] {
|
|
||||||
prefixes += ChannelModePrefixes[Voice]
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isMultiPrefix && len(prefixes) > 1 {
|
if !isMultiPrefix && len(prefixes) > 1 {
|
||||||
prefixes = string(prefixes[0])
|
prefixes = string(prefixes[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user