3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-23 03:02:48 +01:00

implement SAJOIN, allow channel founders to join unconditionally

This commit is contained in:
Shivaram Lingamneni 2018-05-25 02:46:36 -04:00
parent 13aba9e64c
commit 495705f538
6 changed files with 60 additions and 12 deletions

View File

@ -350,32 +350,36 @@ func (channel *Channel) IsEmpty() bool {
} }
// Join joins the given client to this channel (if they can be joined). // Join joins the given client to this channel (if they can be joined).
//TODO(dan): /SAJOIN and maybe a ForceJoin function? func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *ResponseBuffer) {
func (channel *Channel) Join(client *Client, key string, rb *ResponseBuffer) {
if channel.hasClient(client) { if channel.hasClient(client) {
// already joined, no message needs to be sent // already joined, no message needs to be sent
return return
} }
chname := channel.Name() channel.stateMutex.RLock()
chname := channel.name
founder := channel.registeredFounder
channel.stateMutex.RUnlock()
account := client.Account()
hasPrivs := isSajoin || (founder != "" && founder == account)
if channel.IsFull() { if !hasPrivs && channel.IsFull() {
rb.Add(nil, client.server.name, ERR_CHANNELISFULL, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l")) rb.Add(nil, client.server.name, ERR_CHANNELISFULL, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "l"))
return return
} }
if !channel.CheckKey(key) { if !hasPrivs && !channel.CheckKey(key) {
rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k")) rb.Add(nil, client.server.name, ERR_BADCHANNELKEY, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "k"))
return return
} }
isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded) isInvited := channel.lists[modes.InviteMask].Match(client.nickMaskCasefolded)
if channel.flags.HasMode(modes.InviteOnly) && !isInvited { if !hasPrivs && channel.flags.HasMode(modes.InviteOnly) && !isInvited {
rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i")) rb.Add(nil, client.server.name, ERR_INVITEONLYCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "i"))
return return
} }
if channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) && if !hasPrivs && channel.lists[modes.BanMask].Match(client.nickMaskCasefolded) &&
!isInvited && !isInvited &&
!channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) { !channel.lists[modes.ExceptMask].Match(client.nickMaskCasefolded) {
rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b")) rb.Add(nil, client.server.name, ERR_BANNEDFROMCHAN, chname, fmt.Sprintf(client.t("Cannot join channel (+%s)"), "b"))
@ -389,7 +393,6 @@ func (channel *Channel) Join(client *Client, key string, rb *ResponseBuffer) {
defer channel.joinPartMutex.Unlock() defer channel.joinPartMutex.Unlock()
func() { func() {
account := client.Account()
channel.stateMutex.Lock() channel.stateMutex.Lock()
defer channel.stateMutex.Unlock() defer channel.stateMutex.Unlock()
@ -779,7 +782,7 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string, rb
return return
} }
if !channel.ClientHasPrivsOver(client, target) { if !channel.ClientHasPrivsOver(client, target) {
rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You're not a channel operator")) rb.Add(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, client.t("You don't have enough channel privileges"))
return return
} }

View File

@ -45,7 +45,7 @@ func (cm *ChannelManager) Get(name string) *Channel {
} }
// Join causes `client` to join the channel named `name`, creating it if necessary. // Join causes `client` to join the channel named `name`, creating it if necessary.
func (cm *ChannelManager) Join(client *Client, name string, key string, rb *ResponseBuffer) error { func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin bool, rb *ResponseBuffer) error {
server := client.server server := client.server
casefoldedName, err := CasefoldChannel(name) casefoldedName, err := CasefoldChannel(name)
if err != nil || len(casefoldedName) > server.Limits().ChannelLen { if err != nil || len(casefoldedName) > server.Limits().ChannelLen {
@ -74,7 +74,7 @@ func (cm *ChannelManager) Join(client *Client, name string, key string, rb *Resp
entry.pendingJoins += 1 entry.pendingJoins += 1
cm.Unlock() cm.Unlock()
entry.channel.Join(client, key, rb) entry.channel.Join(client, key, isSajoin, rb)
cm.maybeCleanup(entry.channel, true) cm.maybeCleanup(entry.channel, true)

View File

@ -229,6 +229,11 @@ func init() {
usablePreReg: true, usablePreReg: true,
minParams: 1, minParams: 1,
}, },
"SAJOIN": {
handler: sajoinHandler,
minParams: 1,
capabs: []string{"sajoin"},
},
"SANICK": { "SANICK": {
handler: sanickHandler, handler: sanickHandler,
minParams: 2, minParams: 2,

View File

@ -889,7 +889,7 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
if len(keys) > i { if len(keys) > i {
key = keys[i] key = keys[i]
} }
err := server.channels.Join(client, name, key, rb) err := server.channels.Join(client, name, key, false, rb)
if err == errNoSuchChannel { if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), name, client.t("No such channel")) rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), name, client.t("No such channel"))
} }
@ -897,6 +897,38 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp
return false return false
} }
// SAJOIN [nick] #channel{,#channel}
func sajoinHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
var target *Client
var channelString string
if strings.HasPrefix(msg.Params[0], "#") {
target = client
channelString = msg.Params[0]
} else {
if len(msg.Params) == 1 {
rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), "KICK", client.t("Not enough parameters"))
return false
} else {
target = server.clients.Get(msg.Params[0])
if target == nil {
rb.Add(nil, server.name, ERR_NOSUCHNICK, client.Nick(), msg.Params[0], "No such nick")
return false
}
channelString = msg.Params[1]
rb = NewResponseBuffer(target)
}
}
channels := strings.Split(channelString, ",")
for _, chname := range channels {
server.channels.Join(target, chname, "", true, rb)
}
if client != target {
rb.Send()
}
return false
}
// KICK <channel>{,<channel>} <user>{,<user>} [<comment>] // KICK <channel>{,<channel>} <user>{,<user>} [<comment>]
func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
channels := strings.Split(msg.Params[0], ",") channels := strings.Split(msg.Params[0], ",")

View File

@ -400,6 +400,13 @@ Renames the given channel with the given reason, if possible.
For example: For example:
RENAME #ircv2 #ircv3 :Protocol upgrades!`, RENAME #ircv2 #ircv3 :Protocol upgrades!`,
},
"sajoin": {
oper: true,
text: `SAJOIN [nick] #channel{,#channel}
Forcibly joins a user to a channel, ignoring restrictions like bans, user limits
and channel keys. If [nick] is omitted, it defaults to the operator.`,
}, },
"sanick": { "sanick": {
oper: true, oper: true,

View File

@ -281,6 +281,7 @@ oper-classes:
- "oper:rehash" - "oper:rehash"
- "oper:die" - "oper:die"
- "unregister" - "unregister"
- "sajoin"
- "samode" - "samode"
- "vhosts" - "vhosts"