mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 20:09:41 +01:00
mask lists (ban, except, invite)
This commit is contained in:
parent
5d46e7d7fa
commit
d4093e7f8b
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
flags ChannelModeSet
|
flags ChannelModeSet
|
||||||
lists map[ChannelMode]UserMaskSet
|
lists map[ChannelMode]*UserMaskSet
|
||||||
key string
|
key string
|
||||||
members MemberSet
|
members MemberSet
|
||||||
name string
|
name string
|
||||||
@ -26,10 +26,10 @@ func IsChannel(target string) bool {
|
|||||||
func NewChannel(s *Server, name string) *Channel {
|
func NewChannel(s *Server, name string) *Channel {
|
||||||
channel := &Channel{
|
channel := &Channel{
|
||||||
flags: make(ChannelModeSet),
|
flags: make(ChannelModeSet),
|
||||||
lists: map[ChannelMode]UserMaskSet{
|
lists: map[ChannelMode]*UserMaskSet{
|
||||||
BanMask: make(UserMaskSet),
|
BanMask: NewUserMaskSet(),
|
||||||
ExceptMask: make(UserMaskSet),
|
ExceptMask: NewUserMaskSet(),
|
||||||
InviteMask: make(UserMaskSet),
|
InviteMask: NewUserMaskSet(),
|
||||||
},
|
},
|
||||||
members: make(MemberSet),
|
members: make(MemberSet),
|
||||||
name: strings.ToLower(name),
|
name: strings.ToLower(name),
|
||||||
@ -151,6 +151,19 @@ func (channel *Channel) Join(client *Client, key string) {
|
|||||||
return
|
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)
|
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) {
|
||||||
@ -213,7 +226,7 @@ func (channel *Channel) SetTopic(client *Client, topic string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := channel.Persist(); err != nil {
|
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
|
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 {
|
func (channel *Channel) applyMode(client *Client, change *ChannelModeChange) bool {
|
||||||
switch change.mode {
|
switch change.mode {
|
||||||
case BanMask, ExceptMask, InviteMask:
|
case BanMask, ExceptMask, InviteMask:
|
||||||
// TODO add/remove
|
return channel.applyModeMask(client, change.mode, change.op, change.arg)
|
||||||
|
|
||||||
for mask := range channel.lists[change.mode] {
|
|
||||||
client.RplMaskList(change.mode, channel, mask)
|
|
||||||
}
|
|
||||||
client.RplEndOfMaskList(change.mode, channel)
|
|
||||||
|
|
||||||
case Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
|
case Moderated, NoOutside, OpOnlyTopic, Persistent, Private:
|
||||||
return channel.applyModeFlag(client, change.mode, change.op)
|
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 {
|
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
|
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)
|
inviter.RplInviting(invitee, channel.name)
|
||||||
invitee.Reply(RplInviteMsg(inviter, invitee, channel.name))
|
invitee.Reply(RplInviteMsg(inviter, invitee, channel.name))
|
||||||
if invitee.flags[Away] {
|
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,
|
target.NumericReply(ERR_INVALIDCAPCMD,
|
||||||
"%s :Invalid CAP subcommand", subCommand)
|
"%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
|
// simple types
|
||||||
//
|
//
|
||||||
|
|
||||||
type UserMaskSet map[string]bool
|
|
||||||
|
|
||||||
type CapSubCommand string
|
type CapSubCommand string
|
||||||
|
|
||||||
type Capability string
|
type Capability string
|
||||||
|
Loading…
Reference in New Issue
Block a user