2016-06-15 13:50:56 +02:00
|
|
|
// Copyright (c) 2012-2014 Jeremy Latt
|
|
|
|
// Copyright (c) 2014-2015 Edmund Huber
|
2017-03-27 14:15:02 +02:00
|
|
|
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
|
2016-06-15 13:50:56 +02:00
|
|
|
// released under the MIT license
|
|
|
|
|
2012-04-18 03:16:57 +02:00
|
|
|
package irc
|
|
|
|
|
2018-02-03 11:21:32 +01:00
|
|
|
import (
|
2021-06-18 08:41:57 +02:00
|
|
|
"github.com/ergochat/irc-go/ircmsg"
|
2018-02-03 11:21:32 +01:00
|
|
|
)
|
2012-12-09 21:51:50 +01:00
|
|
|
|
2016-06-19 04:53:52 +02:00
|
|
|
// Command represents a command accepted from a client.
|
2016-06-17 14:17:42 +02:00
|
|
|
type Command struct {
|
2021-03-11 02:07:43 +01:00
|
|
|
handler func(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool
|
2020-06-29 10:32:39 +02:00
|
|
|
usablePreReg bool
|
|
|
|
allowedInBatch bool // allowed in client-to-server batches
|
|
|
|
minParams int
|
|
|
|
capabs []string
|
2014-03-13 01:52:25 +01:00
|
|
|
}
|
|
|
|
|
2016-06-19 04:53:52 +02:00
|
|
|
// Run runs this command with the given client/message.
|
2021-03-11 02:07:43 +01:00
|
|
|
func (cmd *Command) Run(server *Server, client *Client, session *Session, msg ircmsg.Message) (exiting bool) {
|
2019-04-12 06:08:46 +02:00
|
|
|
rb := NewResponseBuffer(session)
|
2018-01-30 05:20:12 +01:00
|
|
|
rb.Label = GetLabel(msg)
|
2019-12-03 03:13:09 +01:00
|
|
|
|
|
|
|
exiting = func() bool {
|
|
|
|
defer rb.Send(true)
|
|
|
|
|
|
|
|
if !client.registered && !cmd.usablePreReg {
|
|
|
|
rb.Add(nil, server.name, ERR_NOTREGISTERED, "*", client.t("You need to register before you can use that command"))
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(cmd.capabs) > 0 && !client.HasRoleCapabs(cmd.capabs...) {
|
|
|
|
rb.Add(nil, server.name, ERR_NOPRIVILEGES, client.Nick(), client.t("Permission Denied"))
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(msg.Params) < cmd.minParams {
|
|
|
|
rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), msg.Command, rb.target.t("Not enough parameters"))
|
|
|
|
return false
|
|
|
|
}
|
2019-12-23 21:26:37 +01:00
|
|
|
if session.batch.label != "" && !cmd.allowedInBatch {
|
|
|
|
rb.Add(nil, server.name, "FAIL", "BATCH", "MULTILINE_INVALID", client.t("Command not allowed during a multiline batch"))
|
2020-03-27 15:40:19 +01:00
|
|
|
session.EndMultilineBatch("")
|
2019-12-23 21:26:37 +01:00
|
|
|
return false
|
|
|
|
}
|
2019-12-03 03:13:09 +01:00
|
|
|
|
|
|
|
return cmd.handler(server, client, msg, rb)
|
|
|
|
}()
|
|
|
|
|
2020-02-25 19:26:49 +01:00
|
|
|
// after each command, see if we can send registration to the client
|
|
|
|
if !exiting && !client.registered {
|
|
|
|
exiting = server.tryRegister(client, session)
|
|
|
|
}
|
|
|
|
|
2020-02-19 01:38:42 +01:00
|
|
|
if client.registered {
|
2022-03-30 21:35:28 +02:00
|
|
|
client.Touch(session) // even if `exiting`, we bump the lastSeen timestamp
|
2018-02-11 11:30:40 +01:00
|
|
|
}
|
|
|
|
|
2016-06-17 14:17:42 +02:00
|
|
|
return exiting
|
|
|
|
}
|
|
|
|
|
2020-05-08 11:44:40 +02:00
|
|
|
// fake handler for unknown commands (see #994: this ensures the response tags are correct)
|
|
|
|
var unknownCommand = Command{
|
|
|
|
handler: unknownCommandHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
}
|
|
|
|
|
2020-06-22 20:54:43 +02:00
|
|
|
var invalidUtf8Command = Command{
|
|
|
|
handler: invalidUtf8Handler,
|
|
|
|
usablePreReg: true,
|
|
|
|
}
|
|
|
|
|
2016-06-17 14:17:42 +02:00
|
|
|
// Commands holds all commands executable by a client connected to us.
|
2018-01-22 19:50:58 +01:00
|
|
|
var Commands map[string]Command
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
Commands = map[string]Command{
|
2022-05-06 04:34:43 +02:00
|
|
|
"ACCEPT": {
|
|
|
|
handler: acceptHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"AMBIANCE": {
|
|
|
|
handler: sceneHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
|
|
|
"AUTHENTICATE": {
|
|
|
|
handler: authenticateHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"AWAY": {
|
2023-02-05 06:50:14 +01:00
|
|
|
handler: awayHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 0,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
2019-12-23 21:26:37 +01:00
|
|
|
"BATCH": {
|
|
|
|
handler: batchHandler,
|
|
|
|
minParams: 1,
|
|
|
|
allowedInBatch: true,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"CAP": {
|
|
|
|
handler: capHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2019-02-04 11:18:17 +01:00
|
|
|
"CHATHISTORY": {
|
|
|
|
handler: chathistoryHandler,
|
2020-02-19 01:38:42 +01:00
|
|
|
minParams: 4,
|
2019-02-04 11:18:17 +01:00
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"DEBUG": {
|
|
|
|
handler: debugHandler,
|
|
|
|
minParams: 1,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"rehash"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
2020-07-08 11:32:14 +02:00
|
|
|
"DEFCON": {
|
|
|
|
handler: defconHandler,
|
|
|
|
capabs: []string{"defcon"},
|
|
|
|
},
|
2020-02-21 12:10:35 +01:00
|
|
|
"DEOPER": {
|
|
|
|
handler: deoperHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"DLINE": {
|
|
|
|
handler: dlineHandler,
|
|
|
|
minParams: 1,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"ban"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
2020-04-15 10:14:17 +02:00
|
|
|
"EXTJWT": {
|
|
|
|
handler: extjwtHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"HELP": {
|
|
|
|
handler: helpHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"HELPOP": {
|
|
|
|
handler: helpHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
2019-02-04 11:18:17 +01:00
|
|
|
"HISTORY": {
|
|
|
|
handler: historyHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"INFO": {
|
|
|
|
handler: infoHandler,
|
|
|
|
},
|
|
|
|
"INVITE": {
|
|
|
|
handler: inviteHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
|
|
|
"ISON": {
|
2020-06-29 10:32:39 +02:00
|
|
|
handler: isonHandler,
|
|
|
|
minParams: 1,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"JOIN": {
|
|
|
|
handler: joinHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"KICK": {
|
|
|
|
handler: kickHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
|
|
|
"KILL": {
|
|
|
|
handler: killHandler,
|
|
|
|
minParams: 1,
|
2021-01-15 14:24:42 +01:00
|
|
|
capabs: []string{"kill"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"KLINE": {
|
|
|
|
handler: klineHandler,
|
|
|
|
minParams: 1,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"ban"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"LANGUAGE": {
|
|
|
|
handler: languageHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"LIST": {
|
|
|
|
handler: listHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"LUSERS": {
|
|
|
|
handler: lusersHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
2022-03-30 21:35:28 +02:00
|
|
|
"MARKREAD": {
|
|
|
|
handler: markReadHandler,
|
|
|
|
minParams: 0, // send FAIL instead of ERR_NEEDMOREPARAMS
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"MODE": {
|
|
|
|
handler: modeHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"MONITOR": {
|
|
|
|
handler: monitorHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"MOTD": {
|
|
|
|
handler: motdHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"NAMES": {
|
|
|
|
handler: namesHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"NICK": {
|
|
|
|
handler: nickHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"NOTICE": {
|
2019-12-23 21:26:37 +01:00
|
|
|
handler: messageHandler,
|
|
|
|
minParams: 2,
|
|
|
|
allowedInBatch: true,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"NPC": {
|
|
|
|
handler: npcHandler,
|
|
|
|
minParams: 3,
|
|
|
|
},
|
|
|
|
"NPCA": {
|
|
|
|
handler: npcaHandler,
|
|
|
|
minParams: 3,
|
|
|
|
},
|
|
|
|
"OPER": {
|
|
|
|
handler: operHandler,
|
2019-12-18 21:44:06 +01:00
|
|
|
minParams: 1,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"PART": {
|
|
|
|
handler: partHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"PASS": {
|
|
|
|
handler: passHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2022-07-15 06:04:35 +02:00
|
|
|
"PERSISTENCE": {
|
|
|
|
handler: persistenceHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"PING": {
|
2020-06-29 10:32:39 +02:00
|
|
|
handler: pingHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"PONG": {
|
2020-06-29 10:32:39 +02:00
|
|
|
handler: pongHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 1,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"PRIVMSG": {
|
2019-12-23 21:26:37 +01:00
|
|
|
handler: messageHandler,
|
|
|
|
minParams: 2,
|
|
|
|
allowedInBatch: true,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
2020-06-08 02:19:28 +02:00
|
|
|
"RELAYMSG": {
|
|
|
|
handler: relaymsgHandler,
|
|
|
|
minParams: 3,
|
|
|
|
},
|
2020-10-07 00:04:29 +02:00
|
|
|
"REGISTER": {
|
|
|
|
handler: registerHandler,
|
2021-07-07 13:37:46 +02:00
|
|
|
minParams: 3,
|
2020-10-07 00:04:29 +02:00
|
|
|
usablePreReg: true,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"RENAME": {
|
|
|
|
handler: renameHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
2018-05-25 08:46:36 +02:00
|
|
|
"SAJOIN": {
|
|
|
|
handler: sajoinHandler,
|
|
|
|
minParams: 1,
|
|
|
|
capabs: []string{"sajoin"},
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"SANICK": {
|
|
|
|
handler: sanickHandler,
|
|
|
|
minParams: 2,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"samode"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"SAMODE": {
|
|
|
|
handler: modeHandler,
|
|
|
|
minParams: 1,
|
|
|
|
capabs: []string{"samode"},
|
|
|
|
},
|
|
|
|
"SCENE": {
|
|
|
|
handler: sceneHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
2019-02-13 14:22:16 +01:00
|
|
|
"SETNAME": {
|
|
|
|
handler: setnameHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2020-06-02 15:57:51 +02:00
|
|
|
"SUMMON": {
|
|
|
|
handler: summonHandler,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"TAGMSG": {
|
2019-03-19 08:35:49 +01:00
|
|
|
handler: messageHandler,
|
2018-01-22 19:50:58 +01:00
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"QUIT": {
|
|
|
|
handler: quitHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"REHASH": {
|
|
|
|
handler: rehashHandler,
|
|
|
|
minParams: 0,
|
2020-03-18 10:42:52 +01:00
|
|
|
capabs: []string{"rehash"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"TIME": {
|
|
|
|
handler: timeHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"TOPIC": {
|
|
|
|
handler: topicHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2021-01-19 14:49:45 +01:00
|
|
|
"UBAN": {
|
|
|
|
handler: ubanHandler,
|
|
|
|
minParams: 1,
|
|
|
|
capabs: []string{"ban"},
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"UNDLINE": {
|
|
|
|
handler: unDLineHandler,
|
|
|
|
minParams: 1,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"ban"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
2020-10-26 03:16:19 +01:00
|
|
|
"UNINVITE": {
|
|
|
|
handler: inviteHandler,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"UNKLINE": {
|
|
|
|
handler: unKLineHandler,
|
|
|
|
minParams: 1,
|
2021-02-07 04:45:34 +01:00
|
|
|
capabs: []string{"ban"},
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"USER": {
|
|
|
|
handler: userHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 4,
|
|
|
|
},
|
|
|
|
"USERHOST": {
|
|
|
|
handler: userhostHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2020-06-02 15:57:51 +02:00
|
|
|
"USERS": {
|
|
|
|
handler: usersHandler,
|
|
|
|
},
|
2020-10-07 00:04:29 +02:00
|
|
|
"VERIFY": {
|
|
|
|
handler: verifyHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 2,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
"VERSION": {
|
|
|
|
handler: versionHandler,
|
|
|
|
minParams: 0,
|
|
|
|
},
|
|
|
|
"WEBIRC": {
|
|
|
|
handler: webircHandler,
|
|
|
|
usablePreReg: true,
|
|
|
|
minParams: 4,
|
|
|
|
},
|
|
|
|
"WHO": {
|
2020-06-29 10:32:39 +02:00
|
|
|
handler: whoHandler,
|
|
|
|
minParams: 1,
|
2018-01-22 19:50:58 +01:00
|
|
|
},
|
|
|
|
"WHOIS": {
|
|
|
|
handler: whoisHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
|
|
|
"WHOWAS": {
|
|
|
|
handler: whowasHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2019-05-21 01:08:57 +02:00
|
|
|
"ZNC": {
|
|
|
|
handler: zncHandler,
|
|
|
|
minParams: 1,
|
|
|
|
},
|
2018-01-22 19:50:58 +01:00
|
|
|
}
|
2018-04-19 08:48:19 +02:00
|
|
|
|
|
|
|
initializeServices()
|
2014-03-17 20:11:35 +01:00
|
|
|
}
|