mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
modes: Start overhauling modes
This commit is contained in:
parent
b33b217fab
commit
657ed644cb
264
irc/modes.go
264
irc/modes.go
@ -1,87 +1,45 @@
|
|||||||
// Copyright (c) 2012-2014 Jeremy Latt
|
// Copyright (c) 2012-2014 Jeremy Latt
|
||||||
// Copyright (c) 2014-2015 Edmund Huber
|
// Copyright (c) 2014-2015 Edmund Huber
|
||||||
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
|
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
|
||||||
// released under the MIT license
|
// released under the MIT license
|
||||||
|
|
||||||
package irc
|
package irc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/DanielOaks/girc-go/ircmsg"
|
"github.com/DanielOaks/girc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// user mode flags
|
// ModeOp is an operation performed with modes
|
||||||
type UserMode rune
|
type ModeOp rune
|
||||||
|
|
||||||
func (mode UserMode) String() string {
|
func (op ModeOp) String() string {
|
||||||
|
return string(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Add ModeOp = '+'
|
||||||
|
List ModeOp = '='
|
||||||
|
Remove ModeOp = '-'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mode represents a user/channel/server mode
|
||||||
|
type Mode rune
|
||||||
|
|
||||||
|
func (mode Mode) String() string {
|
||||||
return string(mode)
|
return string(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserModes []UserMode
|
// ModeChange is a single mode changing
|
||||||
|
|
||||||
func (modes UserModes) String() string {
|
|
||||||
strs := make([]string, len(modes))
|
|
||||||
for index, mode := range modes {
|
|
||||||
strs[index] = mode.String()
|
|
||||||
}
|
|
||||||
return strings.Join(strs, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModeChange struct {
|
type ModeChange struct {
|
||||||
mode UserMode
|
mode Mode
|
||||||
op ModeOp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (change *ModeChange) String() string {
|
|
||||||
return fmt.Sprintf("%s%s", change.op, change.mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModeChanges []*ModeChange
|
|
||||||
|
|
||||||
func (changes ModeChanges) String() string {
|
|
||||||
if len(changes) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
op := changes[0].op
|
|
||||||
str := changes[0].op.String()
|
|
||||||
for _, change := range changes {
|
|
||||||
if change.op != op {
|
|
||||||
op = change.op
|
|
||||||
str += change.op.String()
|
|
||||||
}
|
|
||||||
str += change.mode.String()
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// channel mode flags
|
|
||||||
type ChannelMode rune
|
|
||||||
|
|
||||||
func (mode ChannelMode) String() string {
|
|
||||||
return string(mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChannelModes []ChannelMode
|
|
||||||
|
|
||||||
func (modes ChannelModes) String() string {
|
|
||||||
strs := make([]string, len(modes))
|
|
||||||
for index, mode := range modes {
|
|
||||||
strs[index] = mode.String()
|
|
||||||
}
|
|
||||||
return strings.Join(strs, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChannelModeChange struct {
|
|
||||||
mode ChannelMode
|
|
||||||
op ModeOp
|
op ModeOp
|
||||||
arg string
|
arg string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (change *ChannelModeChange) String() (str string) {
|
func (change *ModeChange) String() (str string) {
|
||||||
if (change.op == Add) || (change.op == Remove) {
|
if (change.op == Add) || (change.op == Remove) {
|
||||||
str = change.op.String()
|
str = change.op.String()
|
||||||
}
|
}
|
||||||
@ -92,9 +50,10 @@ func (change *ChannelModeChange) String() (str string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelModeChanges []*ChannelModeChange
|
// ModeChanges are a collection of 'ModeChange's
|
||||||
|
type ModeChanges []ModeChange
|
||||||
|
|
||||||
func (changes ChannelModeChanges) String() string {
|
func (changes ModeChanges) String() string {
|
||||||
if len(changes) == 0 {
|
if len(changes) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -119,82 +78,78 @@ func (changes ChannelModeChanges) String() string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelModeCommand struct {
|
// Modes is just a raw list of modes
|
||||||
channel string
|
type Modes []Mode
|
||||||
changes ChannelModeChanges
|
|
||||||
}
|
func (modes Modes) String() string {
|
||||||
|
strs := make([]string, len(modes))
|
||||||
type ModeOp rune
|
for index, mode := range modes {
|
||||||
|
strs[index] = mode.String()
|
||||||
func (op ModeOp) String() string {
|
}
|
||||||
return string(op)
|
return strings.Join(strs, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User Modes
|
||||||
const (
|
const (
|
||||||
Add ModeOp = '+'
|
Away Mode = 'a'
|
||||||
List ModeOp = '='
|
Invisible Mode = 'i'
|
||||||
Remove ModeOp = '-'
|
LocalOperator Mode = 'O'
|
||||||
)
|
Operator Mode = 'o'
|
||||||
|
Restricted Mode = 'r'
|
||||||
const (
|
ServerNotice Mode = 's' // deprecated
|
||||||
Away UserMode = 'a'
|
TLS Mode = 'Z'
|
||||||
Invisible UserMode = 'i'
|
UserRoleplaying Mode = 'E'
|
||||||
LocalOperator UserMode = 'O'
|
WallOps Mode = 'w'
|
||||||
Operator UserMode = 'o'
|
|
||||||
Restricted UserMode = 'r'
|
|
||||||
ServerNotice UserMode = 's' // deprecated
|
|
||||||
TLS UserMode = 'Z'
|
|
||||||
UserRoleplaying UserMode = 'E'
|
|
||||||
WallOps UserMode = 'w'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SupportedUserModes = UserModes{
|
SupportedUserModes = Modes{
|
||||||
Away, Invisible, Operator, UserRoleplaying,
|
Away, Invisible, Operator, UserRoleplaying,
|
||||||
}
|
}
|
||||||
// supportedUserModesString acts as a cache for when we introduce users
|
// supportedUserModesString acts as a cache for when we introduce users
|
||||||
supportedUserModesString = SupportedUserModes.String()
|
supportedUserModesString = SupportedUserModes.String()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Channel Modes
|
||||||
const (
|
const (
|
||||||
BanMask ChannelMode = 'b' // arg
|
BanMask Mode = 'b' // arg
|
||||||
ChanRoleplaying ChannelMode = 'E' // flag
|
ChanRoleplaying Mode = 'E' // flag
|
||||||
ExceptMask ChannelMode = 'e' // arg
|
ExceptMask Mode = 'e' // arg
|
||||||
InviteMask ChannelMode = 'I' // arg
|
InviteMask Mode = 'I' // arg
|
||||||
InviteOnly ChannelMode = 'i' // flag
|
InviteOnly Mode = 'i' // flag
|
||||||
Key ChannelMode = 'k' // flag arg
|
Key Mode = 'k' // flag arg
|
||||||
Moderated ChannelMode = 'm' // flag
|
Moderated Mode = 'm' // flag
|
||||||
NoOutside ChannelMode = 'n' // flag
|
NoOutside Mode = 'n' // flag
|
||||||
OpOnlyTopic ChannelMode = 't' // flag
|
OpOnlyTopic Mode = 't' // flag
|
||||||
Secret ChannelMode = 's' // flag
|
Secret Mode = 's' // flag
|
||||||
UserLimit ChannelMode = 'l' // flag arg
|
UserLimit Mode = 'l' // flag arg
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ChannelFounder ChannelMode = 'q' // arg
|
ChannelFounder Mode = 'q' // arg
|
||||||
ChannelAdmin ChannelMode = 'a' // arg
|
ChannelAdmin Mode = 'a' // arg
|
||||||
ChannelOperator ChannelMode = 'o' // arg
|
ChannelOperator Mode = 'o' // arg
|
||||||
Halfop ChannelMode = 'h' // arg
|
Halfop Mode = 'h' // arg
|
||||||
Voice ChannelMode = 'v' // arg
|
Voice Mode = 'v' // arg
|
||||||
|
|
||||||
SupportedChannelModes = ChannelModes{
|
SupportedChannelModes = Modes{
|
||||||
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
||||||
OpOnlyTopic, Secret, UserLimit, ChanRoleplaying,
|
OpOnlyTopic, Secret, UserLimit, ChanRoleplaying,
|
||||||
}
|
}
|
||||||
// supportedChannelModesString acts as a cache for when we introduce users
|
// supportedChannelModesString acts as a cache for when we introduce users
|
||||||
supportedChannelModesString = SupportedChannelModes.String()
|
supportedChannelModesString = SupportedChannelModes.String()
|
||||||
|
|
||||||
DefaultChannelModes = ChannelModes{
|
DefaultChannelModes = Modes{
|
||||||
NoOutside, OpOnlyTopic,
|
NoOutside, OpOnlyTopic,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
|
// ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
|
||||||
// voice is not in this list because it cannot perform channel operator actions.
|
// voice is not in this list because it cannot perform channel operator actions.
|
||||||
ChannelPrivModes = ChannelModes{
|
ChannelPrivModes = Modes{
|
||||||
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
|
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelModePrefixes = map[ChannelMode]string{
|
ChannelModePrefixes = map[Mode]string{
|
||||||
ChannelFounder: "~",
|
ChannelFounder: "~",
|
||||||
ChannelAdmin: "&",
|
ChannelAdmin: "&",
|
||||||
ChannelOperator: "@",
|
ChannelOperator: "@",
|
||||||
@ -203,6 +158,10 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// channel membership prefixes
|
||||||
|
//
|
||||||
|
|
||||||
// SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
|
// SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
|
||||||
func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
|
func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
|
||||||
name = target
|
name = target
|
||||||
@ -245,9 +204,48 @@ func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|||||||
|
|
||||||
if errChan == nil {
|
if errChan == nil {
|
||||||
return cmodeHandler(server, client, msg)
|
return cmodeHandler(server, client, msg)
|
||||||
} else {
|
|
||||||
return umodeHandler(server, client, msg)
|
|
||||||
}
|
}
|
||||||
|
return umodeHandler(server, client, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyModeChanges applies the given changes, and returns the applied changes.
|
||||||
|
func (client *Client) applyModeChanges(ModeChanges) ModeChanges {
|
||||||
|
applied := make(ModeChanges, 0)
|
||||||
|
|
||||||
|
for _, change := range changes {
|
||||||
|
switch change.mode {
|
||||||
|
case Invisible, ServerNotice, WallOps, UserRoleplaying:
|
||||||
|
switch change.op {
|
||||||
|
case Add:
|
||||||
|
if client.flags[change.mode] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
client.flags[change.mode] = true
|
||||||
|
applied = append(applied, change)
|
||||||
|
|
||||||
|
case Remove:
|
||||||
|
if !client.flags[change.mode] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(client.flags, change.mode)
|
||||||
|
applied = append(applied, change)
|
||||||
|
}
|
||||||
|
|
||||||
|
case Operator, LocalOperator:
|
||||||
|
if change.op == Remove {
|
||||||
|
if !client.flags[change.mode] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(client.flags, change.mode)
|
||||||
|
applied = append(applied, change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't do anything to TLS mode
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the changes we could actually apply
|
||||||
|
return applied
|
||||||
}
|
}
|
||||||
|
|
||||||
// MODE <target> [<modestring> [<mode arguments>...]]
|
// MODE <target> [<modestring> [<mode arguments>...]]
|
||||||
@ -292,42 +290,12 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
changes = append(changes, &ModeChange{
|
changes = append(changes, &ModeChange{
|
||||||
mode: UserMode(mode),
|
mode: Mode(mode),
|
||||||
op: op,
|
op: op,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, change := range changes {
|
applied := target.applyModeChanges(changes)
|
||||||
switch change.mode {
|
|
||||||
case Invisible, ServerNotice, WallOps, UserRoleplaying:
|
|
||||||
switch change.op {
|
|
||||||
case Add:
|
|
||||||
if target.flags[change.mode] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
target.flags[change.mode] = true
|
|
||||||
applied = append(applied, change)
|
|
||||||
|
|
||||||
case Remove:
|
|
||||||
if !target.flags[change.mode] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
delete(target.flags, change.mode)
|
|
||||||
applied = append(applied, change)
|
|
||||||
}
|
|
||||||
|
|
||||||
case Operator, LocalOperator:
|
|
||||||
if change.op == Remove {
|
|
||||||
if !target.flags[change.mode] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
delete(target.flags, change.mode)
|
|
||||||
applied = append(applied, change)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// can't do anything to TLS mode
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(applied) > 0 {
|
if len(applied) > 0 {
|
||||||
@ -338,6 +306,16 @@ func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
//////
|
||||||
|
|
||||||
// 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 {
|
||||||
channelName, err := CasefoldChannel(msg.Params[0])
|
channelName, err := CasefoldChannel(msg.Params[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user