mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-29 07:29:31 +01:00
Refactor chanserv.go to match nickserv.go, unify the two
This commit is contained in:
parent
9af74d367a
commit
6fb4284e32
202
irc/chanserv.go
202
irc/chanserv.go
@ -5,16 +5,62 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goshuirc/irc-go/ircfmt"
|
"github.com/goshuirc/irc-go/ircfmt"
|
||||||
"github.com/oragono/oragono/irc/modes"
|
"github.com/oragono/oragono/irc/modes"
|
||||||
"github.com/oragono/oragono/irc/sno"
|
"github.com/oragono/oragono/irc/sno"
|
||||||
|
"github.com/oragono/oragono/irc/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChanServNotice sends the client a notice from ChanServ.
|
const chanservHelp = `ChanServ lets you register and manage channels.
|
||||||
func (rb *ResponseBuffer) ChanServNotice(text string) {
|
|
||||||
rb.Add(nil, fmt.Sprintf("ChanServ!services@%s", rb.target.server.name), "NOTICE", rb.target.nick, text)
|
To see in-depth help for a specific ChanServ command, try:
|
||||||
|
$b/CS HELP <command>$b
|
||||||
|
|
||||||
|
Here are the commands you can use:
|
||||||
|
%s`
|
||||||
|
|
||||||
|
type csCommand struct {
|
||||||
|
capabs []string // oper capabs the given user has to have to access this command
|
||||||
|
handler func(server *Server, client *Client, command, params string, rb *ResponseBuffer)
|
||||||
|
help string
|
||||||
|
helpShort string
|
||||||
|
oper bool // true if the user has to be an oper to use this command
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
chanservCommands = map[string]*csCommand{
|
||||||
|
"help": {
|
||||||
|
help: `Syntax: $bHELP [command]$b
|
||||||
|
|
||||||
|
HELP returns information on the given command.`,
|
||||||
|
helpShort: `$bHELP$b shows in-depth information about commands.`,
|
||||||
|
},
|
||||||
|
"op": {
|
||||||
|
handler: csOpHandler,
|
||||||
|
help: `Syntax: $bOP #channel [nickname]$b
|
||||||
|
|
||||||
|
OP makes the given nickname, or yourself, a channel admin. You can only use
|
||||||
|
this command if you're the founder of the channel.`,
|
||||||
|
helpShort: `$bOP$b makes the given user (or yourself) a channel admin.`,
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
handler: csRegisterHandler,
|
||||||
|
help: `Syntax: $bREGISTER #channel$b
|
||||||
|
|
||||||
|
REGISTER lets you own the given channel. If you rejoin this channel, you'll be
|
||||||
|
given admin privs on it. Modes set on the channel and the topic will also be
|
||||||
|
remembered.`,
|
||||||
|
helpShort: `$bREGISTER$b lets you own a given channel.`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// csNotice sends the client a notice from ChanServ
|
||||||
|
func csNotice(rb *ResponseBuffer, text string) {
|
||||||
|
rb.Add(nil, "ChanServ", "NOTICE", rb.target.Nick(), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
||||||
@ -24,68 +70,115 @@ func (server *Server) chanservNoticeHandler(client *Client, message string, rb *
|
|||||||
|
|
||||||
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
// chanservReceiveNotice handles NOTICEs that ChanServ receives.
|
||||||
func (server *Server) chanservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
|
func (server *Server) chanservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
|
||||||
var params []string
|
commandName, params := utils.ExtractParam(message)
|
||||||
for _, p := range strings.Split(message, " ") {
|
commandName = strings.ToLower(commandName)
|
||||||
if len(p) > 0 {
|
|
||||||
params = append(params, p)
|
commandInfo := chanservCommands[commandName]
|
||||||
}
|
if commandInfo == nil {
|
||||||
}
|
csNotice(rb, client.t("Unknown command. To see available commands, run /CS HELP"))
|
||||||
if len(params) < 1 {
|
|
||||||
rb.ChanServNotice(client.t("You need to run a command"))
|
|
||||||
//TODO(dan): dump CS help here
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
command := strings.ToLower(params[0])
|
if commandInfo.oper && !client.HasMode(modes.Operator) {
|
||||||
server.logger.Debug("chanserv", fmt.Sprintf("Client %s ran command %s", client.nick, command))
|
csNotice(rb, client.t("Command restricted"))
|
||||||
|
return
|
||||||
if command == "register" {
|
|
||||||
if len(params) < 2 {
|
|
||||||
rb.ChanServNotice(client.t("Syntax: REGISTER <channel>"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
server.chanservRegisterHandler(client, params[1], rb)
|
|
||||||
} else if command == "op" {
|
|
||||||
if len(params) < 2 {
|
|
||||||
rb.ChanServNotice(client.t("Syntax: OP <channel> [<nick>]"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientToOp string
|
|
||||||
if 2 < len(params) {
|
|
||||||
clientToOp = params[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
server.chanservOpHandler(client, params[1], clientToOp, rb)
|
|
||||||
} else {
|
|
||||||
rb.ChanServNotice(client.t("Sorry, I don't know that command"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if 0 < len(commandInfo.capabs) && !client.HasRoleCapabs(commandInfo.capabs...) {
|
||||||
|
csNotice(rb, client.t("Command restricted"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom help handling here to prevent recursive init loop
|
||||||
|
if commandName == "help" {
|
||||||
|
csHelpHandler(server, client, commandName, params, rb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if commandInfo.handler == nil {
|
||||||
|
csNotice(rb, client.t("Command error. Please report this to the developers"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
server.logger.Debug("chanserv", fmt.Sprintf("Client %s ran command %s", client.Nick(), commandName))
|
||||||
|
|
||||||
|
commandInfo.handler(server, client, commandName, params, rb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// chanservOpHandler handles the ChanServ OP subcommand.
|
func csHelpHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
||||||
func (server *Server) chanservOpHandler(client *Client, channelName, clientToOp string, rb *ResponseBuffer) {
|
csNotice(rb, ircfmt.Unescape(client.t("*** $bChanServ HELP$b ***")))
|
||||||
|
|
||||||
|
if params == "" {
|
||||||
|
// show general help
|
||||||
|
var shownHelpLines sort.StringSlice
|
||||||
|
for _, commandInfo := range chanservCommands {
|
||||||
|
// skip commands user can't access
|
||||||
|
if commandInfo.oper && !client.HasMode(modes.Operator) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if 0 < len(commandInfo.capabs) && !client.HasRoleCapabs(commandInfo.capabs...) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
shownHelpLines = append(shownHelpLines, " "+client.t(commandInfo.helpShort))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort help lines
|
||||||
|
sort.Sort(shownHelpLines)
|
||||||
|
|
||||||
|
// assemble help text
|
||||||
|
assembledHelpLines := strings.Join(shownHelpLines, "\n")
|
||||||
|
fullHelp := ircfmt.Unescape(fmt.Sprintf(client.t(chanservHelp), assembledHelpLines))
|
||||||
|
|
||||||
|
// push out help text
|
||||||
|
for _, line := range strings.Split(fullHelp, "\n") {
|
||||||
|
csNotice(rb, line)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
commandInfo := chanservCommands[strings.ToLower(strings.TrimSpace(params))]
|
||||||
|
if commandInfo == nil {
|
||||||
|
csNotice(rb, client.t("Unknown command. To see available commands, run /cs HELP"))
|
||||||
|
} else {
|
||||||
|
for _, line := range strings.Split(ircfmt.Unescape(client.t(commandInfo.help)), "\n") {
|
||||||
|
csNotice(rb, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csNotice(rb, ircfmt.Unescape(client.t("*** $bEnd of ChanServ HELP$b ***")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func csOpHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
||||||
|
channelName, clientToOp := utils.ExtractParam(params)
|
||||||
|
|
||||||
|
if channelName == "" {
|
||||||
|
csNotice(rb, ircfmt.Unescape(client.t("Syntax: $bOP #channel [nickname]$b")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clientToOp = strings.TrimSpace(clientToOp)
|
||||||
|
|
||||||
channelKey, err := CasefoldChannel(channelName)
|
channelKey, err := CasefoldChannel(channelName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rb.ChanServNotice(client.t("Channel name is not valid"))
|
csNotice(rb, client.t("Channel name is not valid"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channelInfo := server.channels.Get(channelKey)
|
channelInfo := server.channels.Get(channelKey)
|
||||||
if channelInfo == nil {
|
if channelInfo == nil {
|
||||||
rb.ChanServNotice(client.t("Channel does not exist"))
|
csNotice(rb, client.t("Channel does not exist"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAccount := client.Account()
|
clientAccount := client.Account()
|
||||||
|
|
||||||
if clientAccount == "" {
|
if clientAccount == "" {
|
||||||
rb.ChanServNotice(client.t("You must be logged in to op on a channel"))
|
csNotice(rb, client.t("You must be logged in to op on a channel"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if clientAccount != channelInfo.Founder() {
|
if clientAccount != channelInfo.Founder() {
|
||||||
rb.ChanServNotice(client.t("You must be the channel founder to op"))
|
csNotice(rb, client.t("You must be the channel founder to op"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +187,7 @@ func (server *Server) chanservOpHandler(client *Client, channelName, clientToOp
|
|||||||
casefoldedNickname, err := CasefoldName(clientToOp)
|
casefoldedNickname, err := CasefoldName(clientToOp)
|
||||||
target = server.clients.Get(casefoldedNickname)
|
target = server.clients.Get(casefoldedNickname)
|
||||||
if err != nil || target == nil {
|
if err != nil || target == nil {
|
||||||
rb.ChanServNotice(client.t("Could not find given client"))
|
csNotice(rb, client.t("Could not find given client"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -116,47 +209,52 @@ func (server *Server) chanservOpHandler(client *Client, channelName, clientToOp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.ChanServNotice(fmt.Sprintf(client.t("Successfully op'd in channel %s"), channelName))
|
csNotice(rb, fmt.Sprintf(client.t("Successfully op'd in channel %s"), channelName))
|
||||||
|
|
||||||
server.logger.Info("chanserv", fmt.Sprintf("Client %s op'd [%s] in channel %s", client.nick, clientToOp, channelName))
|
server.logger.Info("chanserv", fmt.Sprintf("Client %s op'd [%s] in channel %s", client.nick, clientToOp, channelName))
|
||||||
server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Client $c[grey][$r%s$c[grey]] CS OP'd $c[grey][$r%s$c[grey]] in channel $c[grey][$r%s$c[grey]]"), client.nickMaskString, clientToOp, channelName))
|
server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Client $c[grey][$r%s$c[grey]] CS OP'd $c[grey][$r%s$c[grey]] in channel $c[grey][$r%s$c[grey]]"), client.nickMaskString, clientToOp, channelName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// chanservRegisterHandler handles the ChanServ REGISTER subcommand.
|
func csRegisterHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
||||||
func (server *Server) chanservRegisterHandler(client *Client, channelName string, rb *ResponseBuffer) {
|
|
||||||
if !server.channelRegistrationEnabled {
|
if !server.channelRegistrationEnabled {
|
||||||
rb.ChanServNotice(client.t("Channel registration is not enabled"))
|
csNotice(rb, client.t("Channel registration is not enabled"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channelName := strings.TrimSpace(params)
|
||||||
|
if channelName == "" {
|
||||||
|
csNotice(rb, ircfmt.Unescape(client.t("Syntax: $bREGISTER #channel$b")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channelKey, err := CasefoldChannel(channelName)
|
channelKey, err := CasefoldChannel(channelName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rb.ChanServNotice(client.t("Channel name is not valid"))
|
csNotice(rb, client.t("Channel name is not valid"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channelInfo := server.channels.Get(channelKey)
|
channelInfo := server.channels.Get(channelKey)
|
||||||
if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
|
if channelInfo == nil || !channelInfo.ClientIsAtLeast(client, modes.ChannelOperator) {
|
||||||
rb.ChanServNotice(client.t("You must be an oper on the channel to register it"))
|
csNotice(rb, client.t("You must be an oper on the channel to register it"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.Account() == "" {
|
if client.Account() == "" {
|
||||||
rb.ChanServNotice(client.t("You must be logged in to register a channel"))
|
csNotice(rb, client.t("You must be logged in to register a channel"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// this provides the synchronization that allows exactly one registration of the channel:
|
// this provides the synchronization that allows exactly one registration of the channel:
|
||||||
err = channelInfo.SetRegistered(client.Account())
|
err = channelInfo.SetRegistered(client.Account())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rb.ChanServNotice(err.Error())
|
csNotice(rb, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// registration was successful: make the database reflect it
|
// registration was successful: make the database reflect it
|
||||||
go server.channelRegistry.StoreChannel(channelInfo, true)
|
go server.channelRegistry.StoreChannel(channelInfo, true)
|
||||||
|
|
||||||
rb.ChanServNotice(fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
|
csNotice(rb, fmt.Sprintf(client.t("Channel %s successfully registered"), channelName))
|
||||||
|
|
||||||
server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
|
server.logger.Info("chanserv", fmt.Sprintf("Client %s registered channel %s", client.nick, channelName))
|
||||||
server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Channel registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), channelName, client.nickMaskString))
|
server.snomasks.Send(sno.LocalChannels, fmt.Sprintf(ircfmt.Unescape("Channel registered $c[grey][$r%s$c[grey]] by $c[grey][$r%s$c[grey]]"), channelName, client.nickMaskString))
|
||||||
|
@ -120,7 +120,7 @@ or other verification.`,
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// send a notice from the NickServ "nick"
|
// csNotice sends the client a notice from NickServ
|
||||||
func nsNotice(rb *ResponseBuffer, text string) {
|
func nsNotice(rb *ResponseBuffer, text string) {
|
||||||
rb.Add(nil, "NickServ", "NOTICE", rb.target.Nick(), text)
|
rb.Add(nil, "NickServ", "NOTICE", rb.target.Nick(), text)
|
||||||
}
|
}
|
||||||
@ -167,6 +167,8 @@ func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.logger.Debug("nickserv", fmt.Sprintf("Client %s ran command %s", client.Nick(), commandName))
|
||||||
|
|
||||||
commandInfo.handler(server, client, commandName, params, rb)
|
commandInfo.handler(server, client, commandName, params, rb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user