mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-26 05:49:25 +01:00
mask lists (ban, except, invite)
This commit is contained in:
parent
5d46e7d7fa
commit
d4093e7f8b
@ -8,7 +8,7 @@ import (
|
||||
|
||||
type Channel struct {
|
||||
flags ChannelModeSet
|
||||
lists map[ChannelMode]UserMaskSet
|
||||
lists map[ChannelMode]*UserMaskSet
|
||||
key string
|
||||
members MemberSet
|
||||
name string
|
||||
@ -26,10 +26,10 @@ func IsChannel(target string) bool {
|
||||
func NewChannel(s *Server, name string) *Channel {
|
||||
channel := &Channel{
|
||||
flags: make(ChannelModeSet),
|
||||
lists: map[ChannelMode]UserMaskSet{
|
||||
BanMask: make(UserMaskSet),
|
||||
ExceptMask: make(UserMaskSet),
|
||||
InviteMask: make(UserMaskSet),
|
||||
lists: map[ChannelMode]*UserMaskSet{
|
||||
BanMask: NewUserMaskSet(),
|
||||
ExceptMask: NewUserMaskSet(),
|
||||
InviteMask: NewUserMaskSet(),
|
||||
},
|
||||
members: make(MemberSet),
|
||||
name: strings.ToLower(name),
|
||||
@ -151,6 +151,19 @@ func (channel *Channel) Join(client *Client, key string) {
|
||||
return
|
||||
}
|
||||
|
||||
isInvited := channel.lists[InviteMask].Match(client.UserHost())
|
||||
if channel.flags[InviteOnly] && !isInvited {
|
||||
client.ErrInviteOnlyChan(channel)
|
||||
return
|
||||
}
|
||||
|
||||
if channel.lists[BanMask].Match(client.UserHost()) &&
|
||||
!isInvited &&
|
||||
!channel.lists[ExceptMask].Match(client.UserHost()) {
|
||||
client.ErrBannedFromChan(channel)
|
||||
return
|
||||
}
|
||||
|
||||
client.channels.Add(channel)
|
||||
channel.members.Add(client)
|
||||
if !channel.flags[Persistent] && (len(channel.members) == 1) {
|
||||
@ -213,7 +226,7 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
||||
}
|
||||
|
||||
if err := channel.Persist(); err != nil {
|
||||
log.Println(err)
|
||||
log.Println("Channel.Persist:", channel, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,15 +323,35 @@ func (channel *Channel) applyModeMember(client *Client, mode ChannelMode,
|
||||
return false
|
||||
}
|
||||
|
||||
func (channel *Channel) applyModeMask(client *Client, mode ChannelMode, op ModeOp, mask string) bool {
|
||||
if !channel.ClientIsOperator(client) {
|
||||
client.ErrChanOPrivIsNeeded(channel)
|
||||
return false
|
||||
}
|
||||
|
||||
list := channel.lists[mode]
|
||||
if list == nil {
|
||||
// This should never happen, but better safe than panicky.
|
||||
return false
|
||||
}
|
||||
|
||||
if op == Add {
|
||||
list.Add(mask)
|
||||
} else if op == Remove {
|
||||
list.Remove(mask)
|
||||
}
|
||||
|
||||
for lmask := range channel.lists[mode].masks {
|
||||
client.RplMaskList(mode, channel, lmask)
|
||||
}
|
||||
client.RplEndOfMaskList(mode, channel)
|
||||
return true
|
||||
}
|
||||
|
||||
func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
|
||||
switch change.mode {
|
||||
case BanMask, ExceptMask, InviteMask:
|
||||
// TODO add/remove
|
||||
|
||||
for mask := range channel.lists[change.mode] {
|
||||
client.RplMaskList(change.mode, channel, mask)
|
||||
}
|
||||
client.RplEndOfMaskList(change.mode, channel)
|
||||
return channel.applyModeMask(client, change.mode, change.op, change.arg)
|
||||
|
||||
case Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
|
||||
return channel.applyModeFlag(client, change.mode, change.op)
|
||||
@ -390,7 +423,7 @@ func (channel *Channel) Mode(client *Client, changes ChannelModeChanges) {
|
||||
}
|
||||
|
||||
if err := channel.Persist(); err != nil {
|
||||
log.Println(err)
|
||||
log.Println("Channel.Persist:", channel, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -464,6 +497,13 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client) {
|
||||
return
|
||||
}
|
||||
|
||||
if channel.flags[InviteOnly] {
|
||||
channel.lists[InviteMask].Add(invitee.UserHost())
|
||||
if err := channel.Persist(); err != nil {
|
||||
log.Println("Channel.Persist:", channel, err)
|
||||
}
|
||||
}
|
||||
|
||||
inviter.RplInviting(invitee, channel.name)
|
||||
invitee.Reply(RplInviteMsg(inviter, invitee, channel.name))
|
||||
if invitee.flags[Away] {
|
||||
|
@ -178,3 +178,60 @@ func (db *ClientDB) Remove(client *Client) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// usermask to regexp
|
||||
//
|
||||
|
||||
type UserMaskSet struct {
|
||||
masks map[string]bool
|
||||
regexp *regexp.Regexp
|
||||
}
|
||||
|
||||
func NewUserMaskSet() *UserMaskSet {
|
||||
return &UserMaskSet{
|
||||
masks: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (set *UserMaskSet) Add(mask string) {
|
||||
set.masks[mask] = true
|
||||
set.setRegexp()
|
||||
}
|
||||
|
||||
func (set *UserMaskSet) Remove(mask string) {
|
||||
delete(set.masks, mask)
|
||||
set.setRegexp()
|
||||
}
|
||||
|
||||
func (set *UserMaskSet) Match(userhost string) bool {
|
||||
if set.regexp == nil {
|
||||
return false
|
||||
}
|
||||
return set.regexp.MatchString(userhost)
|
||||
}
|
||||
|
||||
func (set *UserMaskSet) setRegexp() {
|
||||
if len(set.masks) == 0 {
|
||||
set.regexp = nil
|
||||
return
|
||||
}
|
||||
|
||||
maskExprs := make([]string, len(set.masks))
|
||||
index := 0
|
||||
for mask := range set.masks {
|
||||
manyParts := strings.Split(mask, "*")
|
||||
manyExprs := make([]string, len(manyParts))
|
||||
for mindex, manyPart := range manyParts {
|
||||
oneParts := strings.Split(manyPart, "?")
|
||||
oneExprs := make([]string, len(oneParts))
|
||||
for oindex, onePart := range oneParts {
|
||||
oneExprs[oindex] = regexp.QuoteMeta(onePart)
|
||||
}
|
||||
manyExprs[mindex] = strings.Join(oneExprs, ".")
|
||||
}
|
||||
maskExprs[index] = strings.Join(manyExprs, ".*")
|
||||
}
|
||||
expr := "^" + strings.Join(maskExprs, "|") + "$"
|
||||
set.regexp, _ = regexp.Compile(expr)
|
||||
}
|
||||
|
10
irc/reply.go
10
irc/reply.go
@ -541,3 +541,13 @@ func (target *Client) ErrInvalidCapCmd(subCommand CapSubCommand) {
|
||||
target.NumericReply(ERR_INVALIDCAPCMD,
|
||||
"%s :Invalid CAP subcommand", subCommand)
|
||||
}
|
||||
|
||||
func (target *Client) ErrBannedFromChan(channel *Channel) {
|
||||
target.NumericReply(ERR_BANNEDFROMCHAN,
|
||||
"%s :Cannot join channel (+b)", channel)
|
||||
}
|
||||
|
||||
func (target *Client) ErrInviteOnlyChan(channel *Channel) {
|
||||
target.NumericReply(ERR_INVITEONLYCHAN,
|
||||
"%s :Cannot join channel (+i)", channel)
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import (
|
||||
// simple types
|
||||
//
|
||||
|
||||
type UserMaskSet map[string]bool
|
||||
|
||||
type CapSubCommand string
|
||||
|
||||
type Capability string
|
||||
|
Loading…
Reference in New Issue
Block a user