mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-10 22:19:31 +01:00
privileges: Add founder/admin/halfop (qah), remove owner (O)
channel owner is from 2812 and unused in the real world
This commit is contained in:
parent
5ee0f1c205
commit
3972fc49ed
@ -49,25 +49,33 @@ func (channel *Channel) ClientIsOperator(client *Client) bool {
|
|||||||
return client.flags[Operator] || channel.members.HasMode(client, ChannelOperator)
|
return client.flags[Operator] || channel.members.HasMode(client, ChannelOperator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefixes returns a list of prefixes for the given set of channel modes.
|
||||||
|
func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
|
||||||
|
var prefixes string
|
||||||
|
|
||||||
|
// add prefixes in order from highest to lowest privs
|
||||||
|
for _, mode := range ChannelPrivModes {
|
||||||
|
if modes[mode] {
|
||||||
|
prefixes += ChannelModePrefixes[mode]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if modes[Voice] {
|
||||||
|
prefixes += ChannelModePrefixes[Voice]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isMultiPrefix && len(prefixes) > 1 {
|
||||||
|
prefixes = string(prefixes[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefixes
|
||||||
|
}
|
||||||
|
|
||||||
func (channel *Channel) Nicks(target *Client) []string {
|
func (channel *Channel) Nicks(target *Client) []string {
|
||||||
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
|
isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
|
||||||
nicks := make([]string, len(channel.members))
|
nicks := make([]string, len(channel.members))
|
||||||
i := 0
|
i := 0
|
||||||
for client, modes := range channel.members {
|
for client, modes := range channel.members {
|
||||||
if isMultiPrefix {
|
nicks[i] += modes.Prefixes(isMultiPrefix)
|
||||||
if modes[ChannelOperator] {
|
|
||||||
nicks[i] += "@"
|
|
||||||
}
|
|
||||||
if modes[Voice] {
|
|
||||||
nicks[i] += "+"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if modes[ChannelOperator] {
|
|
||||||
nicks[i] += "@"
|
|
||||||
} else if modes[Voice] {
|
|
||||||
nicks[i] += "+"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nicks[i] += client.Nick().String()
|
nicks[i] += client.Nick().String()
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
@ -160,7 +168,7 @@ func (channel *Channel) Join(client *Client, key Text) {
|
|||||||
client.channels.Add(channel)
|
client.channels.Add(channel)
|
||||||
channel.members.Add(client)
|
channel.members.Add(client)
|
||||||
if !channel.flags[Persistent] && (len(channel.members) == 1) {
|
if !channel.flags[Persistent] && (len(channel.members) == 1) {
|
||||||
channel.members[client][ChannelCreator] = true
|
channel.members[client][ChannelFounder] = true
|
||||||
channel.members[client][ChannelOperator] = true
|
channel.members[client][ChannelOperator] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,9 +408,38 @@ func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) boo
|
|||||||
channel.userLimit = limit
|
channel.userLimit = limit
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ChannelOperator, Voice:
|
case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
|
||||||
return channel.applyModeMember(client, change.mode, change.op,
|
var hasPrivs bool
|
||||||
NewName(change.arg))
|
|
||||||
|
// make sure client has privs to edit the given prefix
|
||||||
|
for _, mode := range ChannelPrivModes {
|
||||||
|
if channel.members[client][mode] {
|
||||||
|
hasPrivs = true
|
||||||
|
|
||||||
|
// Admins can't give other people Admin or remove it from others,
|
||||||
|
// standard for that channel mode, we worry about this later
|
||||||
|
if mode == ChannelAdmin && change.mode == ChannelAdmin {
|
||||||
|
hasPrivs = false
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
} else if mode == change.mode {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := NewName(change.arg)
|
||||||
|
|
||||||
|
if !hasPrivs {
|
||||||
|
if change.op == Remove && name.ToLower() == client.nick.ToLower() {
|
||||||
|
// success!
|
||||||
|
} else {
|
||||||
|
client.ErrChanOPrivIsNeeded(channel)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel.applyModeMember(client, change.mode, change.op, name)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
client.ErrUnknownMode(change.mode, channel)
|
client.ErrUnknownMode(change.mode, channel)
|
||||||
|
@ -545,8 +545,9 @@ func ParseChannelModeCommand(channel Name, args []string) (Command, error) {
|
|||||||
op: op,
|
op: op,
|
||||||
}
|
}
|
||||||
switch change.mode {
|
switch change.mode {
|
||||||
|
// TODO(dan): separate this into the type A/B/C/D args and use those lists here
|
||||||
case Key, BanMask, ExceptMask, InviteMask, UserLimit,
|
case Key, BanMask, ExceptMask, InviteMask, UserLimit,
|
||||||
ChannelOperator, ChannelCreator, Voice:
|
ChannelOperator, ChannelFounder, ChannelAdmin, Halfop, Voice:
|
||||||
if len(args) > skipArgs {
|
if len(args) > skipArgs {
|
||||||
change.arg = args[skipArgs]
|
change.arg = args[skipArgs]
|
||||||
skipArgs += 1
|
skipArgs += 1
|
||||||
|
49
irc/modes.go
49
irc/modes.go
@ -67,25 +67,26 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Anonymous ChannelMode = 'a' // flag
|
ChannelFounder ChannelMode = 'q' // arg
|
||||||
BanMask ChannelMode = 'b' // arg
|
ChannelAdmin ChannelMode = 'a' // arg
|
||||||
ChannelCreator ChannelMode = 'O' // flag
|
|
||||||
ChannelOperator ChannelMode = 'o' // arg
|
ChannelOperator ChannelMode = 'o' // arg
|
||||||
ExceptMask ChannelMode = 'e' // arg
|
Halfop ChannelMode = 'h' // arg
|
||||||
InviteMask ChannelMode = 'I' // arg
|
|
||||||
InviteOnly ChannelMode = 'i' // flag
|
|
||||||
Key ChannelMode = 'k' // flag arg
|
|
||||||
Moderated ChannelMode = 'm' // flag
|
|
||||||
NoOutside ChannelMode = 'n' // flag
|
|
||||||
OpOnlyTopic ChannelMode = 't' // flag
|
|
||||||
Persistent ChannelMode = 'P' // flag
|
|
||||||
Private ChannelMode = 'p' // flag
|
|
||||||
Quiet ChannelMode = 'q' // flag
|
|
||||||
ReOp ChannelMode = 'r' // flag
|
|
||||||
Secret ChannelMode = 's' // flag, deprecated
|
|
||||||
Theater ChannelMode = 'T' // flag, nonstandard
|
|
||||||
UserLimit ChannelMode = 'l' // flag arg
|
|
||||||
Voice ChannelMode = 'v' // arg
|
Voice ChannelMode = 'v' // arg
|
||||||
|
|
||||||
|
BanMask ChannelMode = 'b' // arg
|
||||||
|
ExceptMask ChannelMode = 'e' // arg
|
||||||
|
InviteMask ChannelMode = 'I' // arg
|
||||||
|
InviteOnly ChannelMode = 'i' // flag
|
||||||
|
Key ChannelMode = 'k' // flag arg
|
||||||
|
Moderated ChannelMode = 'm' // flag
|
||||||
|
NoOutside ChannelMode = 'n' // flag
|
||||||
|
OpOnlyTopic ChannelMode = 't' // flag
|
||||||
|
Persistent ChannelMode = 'P' // flag
|
||||||
|
Private ChannelMode = 'p' // flag
|
||||||
|
ReOp ChannelMode = 'r' // flag
|
||||||
|
Secret ChannelMode = 's' // flag, deprecated
|
||||||
|
Theater ChannelMode = 'T' // flag, nonstandard
|
||||||
|
UserLimit ChannelMode = 'l' // flag arg
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -93,6 +94,20 @@ var (
|
|||||||
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
|
||||||
OpOnlyTopic, Persistent, Private, Theater, UserLimit,
|
OpOnlyTopic, Persistent, Private, Theater, UserLimit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
ChannelPrivModes = ChannelModes{
|
||||||
|
ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelModePrefixes = map[ChannelMode]string{
|
||||||
|
ChannelFounder: "~",
|
||||||
|
ChannelAdmin: "&",
|
||||||
|
ChannelOperator: "@",
|
||||||
|
Halfop: "%",
|
||||||
|
Voice: "+",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
//
|
||||||
|
17
irc/reply.go
17
irc/reply.go
@ -298,21 +298,8 @@ func (target *Client) RplWhoReply(channel *Channel, client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if channel != nil {
|
if channel != nil {
|
||||||
|
flags += channel.members[client].Prefixes(target.capabilities[MultiPrefix])
|
||||||
channelName = channel.name.String()
|
channelName = channel.name.String()
|
||||||
if target.capabilities[MultiPrefix] {
|
|
||||||
if channel.members[client][ChannelOperator] {
|
|
||||||
flags += "@"
|
|
||||||
}
|
|
||||||
if channel.members[client][Voice] {
|
|
||||||
flags += "+"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if channel.members[client][ChannelOperator] {
|
|
||||||
flags += "@"
|
|
||||||
} else if channel.members[client][Voice] {
|
|
||||||
flags += "+"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
target.NumericReply(RPL_WHOREPLY,
|
target.NumericReply(RPL_WHOREPLY,
|
||||||
"%s %s %s %s %s %s :%d %s", channelName, client.username, client.hostname,
|
"%s %s %s %s %s %s :%d %s", channelName, client.username, client.hostname,
|
||||||
@ -432,7 +419,7 @@ func (target *Client) RplNamReply(channel *Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (target *Client) RplWhoisChannels(client *Client) {
|
func (target *Client) RplWhoisChannels(client *Client) {
|
||||||
target.MultilineReply(client.WhoisChannelsNames(), RPL_WHOISCHANNELS,
|
target.MultilineReply(client.WhoisChannelsNames(target.capabilities[MultiPrefix]), RPL_WHOISCHANNELS,
|
||||||
"%s :%s", client.Nick())
|
"%s :%s", client.Nick())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ func NewServer(config *Config) *Server {
|
|||||||
// server.isupport.Add("MODES", "") //TODO(dan): Support max modes?
|
// server.isupport.Add("MODES", "") //TODO(dan): Support max modes?
|
||||||
server.isupport.Add("NETWORK", config.Network.Name)
|
server.isupport.Add("NETWORK", config.Network.Name)
|
||||||
// server.isupport.Add("NICKLEN", "") //TODO(dan): Support nick length
|
// server.isupport.Add("NICKLEN", "") //TODO(dan): Support nick length
|
||||||
server.isupport.Add("PREFIX", "(ov)@+")
|
server.isupport.Add("PREFIX", "(qaohv)~&@%+")
|
||||||
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Autogenerate based on PREFIXes, support STATUSMSG
|
// server.isupport.Add("STATUSMSG", "@+") //TODO(dan): Autogenerate based on PREFIXes, support STATUSMSG
|
||||||
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
// server.isupport.Add("TARGMAX", "") //TODO(dan): Support this
|
||||||
// server.isupport.Add("TOPICLEN", "") //TODO(dan): Support topic length
|
// server.isupport.Add("TOPICLEN", "") //TODO(dan): Support topic length
|
||||||
@ -504,20 +504,12 @@ func (msg *PrivMsgCommand) HandleServer(server *Server) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) WhoisChannelsNames() []string {
|
func (client *Client) WhoisChannelsNames(isMultiPrefix bool) []string {
|
||||||
chstrs := make([]string, len(client.channels))
|
chstrs := make([]string, len(client.channels))
|
||||||
index := 0
|
index := 0
|
||||||
|
//TODO(dan): handle secret (+s) channels here properly?
|
||||||
for channel := range client.channels {
|
for channel := range client.channels {
|
||||||
switch {
|
chstrs[index] = channel.members[client].Prefixes(isMultiPrefix) + channel.name.String()
|
||||||
case channel.members[client][ChannelOperator]:
|
|
||||||
chstrs[index] = "@" + channel.name.String()
|
|
||||||
|
|
||||||
case channel.members[client][Voice]:
|
|
||||||
chstrs[index] = "+" + channel.name.String()
|
|
||||||
|
|
||||||
default:
|
|
||||||
chstrs[index] = channel.name.String()
|
|
||||||
}
|
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
return chstrs
|
return chstrs
|
||||||
@ -664,7 +656,28 @@ func (msg *KickCommand) HandleServer(server *Server) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Kick(client, target, msg.Comment())
|
// make sure client has privs to kick the given user
|
||||||
|
var hasPrivs bool
|
||||||
|
for _, mode := range ChannelPrivModes {
|
||||||
|
if channel.members[client][mode] {
|
||||||
|
hasPrivs = true
|
||||||
|
|
||||||
|
// admins cannot kick other admins
|
||||||
|
if mode == ChannelAdmin && channel.members[target][ChannelAdmin] {
|
||||||
|
hasPrivs = false
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
} else if channel.members[target][mode] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasPrivs {
|
||||||
|
channel.Kick(client, target, msg.Comment())
|
||||||
|
} else {
|
||||||
|
client.ErrChanOPrivIsNeeded(channel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user