feat: implement IRC numerics batch 2 — connection registration, channel ops, user queries #59
@@ -13,15 +13,14 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.eeqj.de/sneak/neoirc/internal/irc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
httpTimeout = 30 * time.Second
|
httpTimeout = 30 * time.Second
|
||||||
pollExtraTime = 5
|
pollExtraTime = 5
|
||||||
httpErrThreshold = 400
|
httpErrThreshold = 400
|
||||||
|
|
||||||
cmdJoin = "JOIN"
|
|
||||||
cmdPart = "PART"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errHTTP = errors.New("HTTP error")
|
var errHTTP = errors.New("HTTP error")
|
||||||
@@ -171,7 +170,7 @@ func (client *Client) PollMessages(
|
|||||||
func (client *Client) JoinChannel(channel string) error {
|
func (client *Client) JoinChannel(channel string) error {
|
||||||
return client.SendMessage(
|
return client.SendMessage(
|
||||||
&Message{ //nolint:exhaustruct // only command+to needed
|
&Message{ //nolint:exhaustruct // only command+to needed
|
||||||
Command: cmdJoin, To: channel,
|
Command: irc.CmdJoin, To: channel,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -180,7 +179,7 @@ func (client *Client) JoinChannel(channel string) error {
|
|||||||
func (client *Client) PartChannel(channel string) error {
|
func (client *Client) PartChannel(channel string) error {
|
||||||
return client.SendMessage(
|
return client.SendMessage(
|
||||||
&Message{ //nolint:exhaustruct // only command+to needed
|
&Message{ //nolint:exhaustruct // only command+to needed
|
||||||
Command: cmdPart, To: channel,
|
Command: irc.CmdPart, To: channel,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
api "git.eeqj.de/sneak/neoirc/cmd/neoirc-cli/api"
|
api "git.eeqj.de/sneak/neoirc/cmd/neoirc-cli/api"
|
||||||
|
"git.eeqj.de/sneak/neoirc/internal/irc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -16,17 +17,6 @@ const (
|
|||||||
pollTimeout = 15
|
pollTimeout = 15
|
||||||
pollRetry = 2 * time.Second
|
pollRetry = 2 * time.Second
|
||||||
timeFormat = "15:04"
|
timeFormat = "15:04"
|
||||||
|
|
||||||
cmdJoin = "JOIN"
|
|
||||||
cmdMotd = "MOTD"
|
|
||||||
cmdNick = "NICK"
|
|
||||||
cmdNotice = "NOTICE"
|
|
||||||
cmdPart = "PART"
|
|
||||||
cmdPrivmsg = "PRIVMSG"
|
|
||||||
cmdQuit = "QUIT"
|
|
||||||
cmdTopic = "TOPIC"
|
|
||||||
cmdWho = "WHO"
|
|
||||||
cmdWhois = "WHOIS"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// App holds the application state.
|
// App holds the application state.
|
||||||
@@ -97,7 +87,7 @@ func (a *App) handleInput(text string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdPrivmsg,
|
Command: irc.CmdPrivmsg,
|
||||||
To: target,
|
To: target,
|
||||||
Body: []string{text},
|
Body: []string{text},
|
||||||
})
|
})
|
||||||
@@ -252,7 +242,7 @@ func (a *App) cmdNick(nick string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdNick,
|
Command: irc.CmdNick,
|
||||||
Body: []string{nick},
|
Body: []string{nick},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -387,7 +377,7 @@ func (a *App) cmdMsg(args string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdPrivmsg,
|
Command: irc.CmdPrivmsg,
|
||||||
To: target,
|
To: target,
|
||||||
Body: []string{text},
|
Body: []string{text},
|
||||||
})
|
})
|
||||||
@@ -445,7 +435,7 @@ func (a *App) cmdTopic(args string) {
|
|||||||
|
|
||||||
if args == "" {
|
if args == "" {
|
||||||
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdTopic,
|
Command: irc.CmdTopic,
|
||||||
To: target,
|
To: target,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -458,7 +448,7 @@ func (a *App) cmdTopic(args string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdTopic,
|
Command: irc.CmdTopic,
|
||||||
To: target,
|
To: target,
|
||||||
Body: []string{args},
|
Body: []string{args},
|
||||||
})
|
})
|
||||||
@@ -546,7 +536,7 @@ func (a *App) cmdMotd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := a.client.SendMessage(
|
err := a.client.SendMessage(
|
||||||
&api.Message{Command: cmdMotd}, //nolint:exhaustruct
|
&api.Message{Command: irc.CmdMotd}, //nolint:exhaustruct
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.ui.AddStatus(fmt.Sprintf(
|
a.ui.AddStatus(fmt.Sprintf(
|
||||||
@@ -583,7 +573,7 @@ func (a *App) cmdWho(args string) {
|
|||||||
|
|
||||||
err := a.client.SendMessage(
|
err := a.client.SendMessage(
|
||||||
&api.Message{ //nolint:exhaustruct
|
&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdWho, To: channel,
|
Command: irc.CmdWho, To: channel,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -614,7 +604,7 @@ func (a *App) cmdWhois(args string) {
|
|||||||
|
|
||||||
err := a.client.SendMessage(
|
err := a.client.SendMessage(
|
||||||
&api.Message{ //nolint:exhaustruct
|
&api.Message{ //nolint:exhaustruct
|
||||||
Command: cmdWhois, To: args,
|
Command: irc.CmdWhois, To: args,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -664,7 +654,7 @@ func (a *App) cmdQuit() {
|
|||||||
|
|
||||||
if a.connected && a.client != nil {
|
if a.connected && a.client != nil {
|
||||||
_ = a.client.SendMessage(
|
_ = a.client.SendMessage(
|
||||||
&api.Message{Command: cmdQuit}, //nolint:exhaustruct
|
&api.Message{Command: irc.CmdQuit}, //nolint:exhaustruct
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,19 +739,19 @@ func (a *App) handleServerMessage(msg *api.Message) {
|
|||||||
a.mu.Unlock()
|
a.mu.Unlock()
|
||||||
|
|
||||||
switch msg.Command {
|
switch msg.Command {
|
||||||
case cmdPrivmsg:
|
case irc.CmdPrivmsg:
|
||||||
a.handlePrivmsgEvent(msg, timestamp, myNick)
|
a.handlePrivmsgEvent(msg, timestamp, myNick)
|
||||||
case cmdJoin:
|
case irc.CmdJoin:
|
||||||
a.handleJoinEvent(msg, timestamp)
|
a.handleJoinEvent(msg, timestamp)
|
||||||
case cmdPart:
|
case irc.CmdPart:
|
||||||
a.handlePartEvent(msg, timestamp)
|
a.handlePartEvent(msg, timestamp)
|
||||||
case cmdQuit:
|
case irc.CmdQuit:
|
||||||
a.handleQuitEvent(msg, timestamp)
|
a.handleQuitEvent(msg, timestamp)
|
||||||
case cmdNick:
|
case irc.CmdNick:
|
||||||
a.handleNickEvent(msg, timestamp, myNick)
|
a.handleNickEvent(msg, timestamp, myNick)
|
||||||
case cmdNotice:
|
case irc.CmdNotice:
|
||||||
a.handleNoticeEvent(msg, timestamp)
|
a.handleNoticeEvent(msg, timestamp)
|
||||||
case cmdTopic:
|
case irc.CmdTopic:
|
||||||
a.handleTopicEvent(msg, timestamp)
|
a.handleTopicEvent(msg, timestamp)
|
||||||
default:
|
default:
|
||||||
a.handleDefaultEvent(msg, timestamp)
|
a.handleDefaultEvent(msg, timestamp)
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.eeqj.de/sneak/neoirc/internal/irc"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ func generateToken() (string, error) {
|
|||||||
type IRCMessage struct {
|
type IRCMessage struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
|
Code int `json:"code,omitempty"`
|
||||||
From string `json:"from,omitempty"`
|
From string `json:"from,omitempty"`
|
||||||
To string `json:"to,omitempty"`
|
To string `json:"to,omitempty"`
|
||||||
Params json.RawMessage `json:"params,omitempty"`
|
Params json.RawMessage `json:"params,omitempty"`
|
||||||
@@ -42,6 +45,15 @@ type IRCMessage struct {
|
|||||||
DBID int64 `json:"-"`
|
DBID int64 `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isNumericCode returns true if s is exactly a 3-digit
|
||||||
|
// IRC numeric reply code.
|
||||||
|
func isNumericCode(s string) bool {
|
||||||
|
return len(s) == 3 &&
|
||||||
|
s[0] >= '0' && s[0] <= '9' &&
|
||||||
|
s[1] >= '0' && s[1] <= '9' &&
|
||||||
|
s[2] >= '0' && s[2] <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
// ChannelInfo is a lightweight channel representation.
|
// ChannelInfo is a lightweight channel representation.
|
||||||
type ChannelInfo struct {
|
type ChannelInfo struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
@@ -717,6 +729,15 @@ func scanMessages(
|
|||||||
msg.DBID = qID
|
msg.DBID = qID
|
||||||
lastQID = qID
|
lastQID = qID
|
||||||
|
|
||||||
|
if isNumericCode(msg.Command) {
|
||||||
|
code, _ := strconv.Atoi(msg.Command)
|
||||||
|
msg.Code = code
|
||||||
|
|
||||||
|
if name := irc.Name(code); name != "" {
|
||||||
|
msg.Command = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msgs = append(msgs, msg)
|
msgs = append(msgs, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.eeqj.de/sneak/neoirc/internal/irc"
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,22 +28,6 @@ const (
|
|||||||
defaultMaxBodySize = 4096
|
defaultMaxBodySize = 4096
|
||||||
defaultHistLimit = 50
|
defaultHistLimit = 50
|
||||||
maxHistLimit = 500
|
maxHistLimit = 500
|
||||||
cmdJoin = "JOIN"
|
|
||||||
cmdList = "LIST"
|
|
||||||
cmdLusers = "LUSERS"
|
|
||||||
cmdMode = "MODE"
|
|
||||||
cmdMotd = "MOTD"
|
|
||||||
cmdNames = "NAMES"
|
|
||||||
cmdNick = "NICK"
|
|
||||||
cmdNotice = "NOTICE"
|
|
||||||
cmdPart = "PART"
|
|
||||||
cmdPing = "PING"
|
|
||||||
cmdPong = "PONG"
|
|
||||||
cmdPrivmsg = "PRIVMSG"
|
|
||||||
cmdQuit = "QUIT"
|
|
||||||
cmdTopic = "TOPIC"
|
|
||||||
cmdWho = "WHO"
|
|
||||||
cmdWhois = "WHOIS"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (hdlr *Handlers) maxBodySize() int64 {
|
func (hdlr *Handlers) maxBodySize() int64 {
|
||||||
@@ -247,20 +232,20 @@ func (hdlr *Handlers) deliverWelcome(
|
|||||||
|
|
||||||
// 001 RPL_WELCOME
|
// 001 RPL_WELCOME
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "001", nick, nil,
|
ctx, clientID, irc.RplWelcome, nick, nil,
|
||||||
"Welcome to the network, "+nick,
|
"Welcome to the network, "+nick,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 002 RPL_YOURHOST
|
// 002 RPL_YOURHOST
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "002", nick, nil,
|
ctx, clientID, irc.RplYourHost, nick, nil,
|
||||||
"Your host is "+srvName+
|
"Your host is "+srvName+
|
||||||
", running version "+version,
|
", running version "+version,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 003 RPL_CREATED
|
// 003 RPL_CREATED
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "003", nick, nil,
|
ctx, clientID, irc.RplCreated, nick, nil,
|
||||||
"This server was created "+
|
"This server was created "+
|
||||||
hdlr.params.Globals.StartTime.
|
hdlr.params.Globals.StartTime.
|
||||||
Format("2006-01-02"),
|
Format("2006-01-02"),
|
||||||
@@ -268,14 +253,14 @@ func (hdlr *Handlers) deliverWelcome(
|
|||||||
|
|
||||||
// 004 RPL_MYINFO
|
// 004 RPL_MYINFO
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "004", nick,
|
ctx, clientID, irc.RplMyInfo, nick,
|
||||||
[]string{srvName, version, "", "imnst"},
|
[]string{srvName, version, "", "imnst"},
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
|
|
||||||
// 005 RPL_ISUPPORT
|
// 005 RPL_ISUPPORT
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "005", nick,
|
ctx, clientID, irc.RplIsupport, nick,
|
||||||
[]string{
|
[]string{
|
||||||
"CHANTYPES=#",
|
"CHANTYPES=#",
|
||||||
"NICKLEN=32",
|
"NICKLEN=32",
|
||||||
@@ -320,7 +305,7 @@ func (hdlr *Handlers) deliverLusers(
|
|||||||
|
|
||||||
// 251 RPL_LUSERCLIENT
|
// 251 RPL_LUSERCLIENT
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "251", nick, nil,
|
ctx, clientID, irc.RplLuserClient, nick, nil,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"There are %d users and 0 invisible on 1 servers",
|
"There are %d users and 0 invisible on 1 servers",
|
||||||
userCount,
|
userCount,
|
||||||
@@ -329,21 +314,21 @@ func (hdlr *Handlers) deliverLusers(
|
|||||||
|
|
||||||
// 252 RPL_LUSEROP
|
// 252 RPL_LUSEROP
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "252", nick,
|
ctx, clientID, irc.RplLuserOp, nick,
|
||||||
[]string{"0"},
|
[]string{"0"},
|
||||||
"operator(s) online",
|
"operator(s) online",
|
||||||
)
|
)
|
||||||
|
|
||||||
// 254 RPL_LUSERCHANNELS
|
// 254 RPL_LUSERCHANNELS
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "254", nick,
|
ctx, clientID, irc.RplLuserChannels, nick,
|
||||||
[]string{strconv.FormatInt(chanCount, 10)},
|
[]string{strconv.FormatInt(chanCount, 10)},
|
||||||
"channels formed",
|
"channels formed",
|
||||||
)
|
)
|
||||||
|
|
||||||
// 255 RPL_LUSERME
|
// 255 RPL_LUSERME
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "255", nick, nil,
|
ctx, clientID, irc.RplLuserMe, nick, nil,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"I have %d clients and 1 servers",
|
"I have %d clients and 1 servers",
|
||||||
userCount,
|
userCount,
|
||||||
@@ -381,19 +366,19 @@ func (hdlr *Handlers) deliverMOTD(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "375", nick, nil,
|
ctx, clientID, irc.RplMotdStart, nick, nil,
|
||||||
"- "+srvName+" Message of the Day -",
|
"- "+srvName+" Message of the Day -",
|
||||||
)
|
)
|
||||||
|
|
||||||
for line := range strings.SplitSeq(motd, "\n") {
|
for line := range strings.SplitSeq(motd, "\n") {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "372", nick, nil,
|
ctx, clientID, irc.RplMotd, nick, nil,
|
||||||
"- "+line,
|
"- "+line,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "376", nick, nil,
|
ctx, clientID, irc.RplEndOfMotd, nick, nil,
|
||||||
"End of /MOTD command.",
|
"End of /MOTD command.",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -412,10 +397,13 @@ func (hdlr *Handlers) serverName() string {
|
|||||||
func (hdlr *Handlers) enqueueNumeric(
|
func (hdlr *Handlers) enqueueNumeric(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
clientID int64,
|
clientID int64,
|
||||||
command, nick string,
|
code int,
|
||||||
|
nick string,
|
||||||
params []string,
|
params []string,
|
||||||
text string,
|
text string,
|
||||||
) {
|
) {
|
||||||
|
command := fmt.Sprintf("%03d", code)
|
||||||
|
|
||||||
body, err := json.Marshal([]string{text})
|
body, err := json.Marshal([]string{text})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.log.Error(
|
hdlr.log.Error(
|
||||||
@@ -765,38 +753,38 @@ func (hdlr *Handlers) dispatchCommand(
|
|||||||
bodyLines func() []string,
|
bodyLines func() []string,
|
||||||
) {
|
) {
|
||||||
switch command {
|
switch command {
|
||||||
case cmdPrivmsg, cmdNotice:
|
case irc.CmdPrivmsg, irc.CmdNotice:
|
||||||
hdlr.handlePrivmsg(
|
hdlr.handlePrivmsg(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
command, target, body, bodyLines,
|
command, target, body, bodyLines,
|
||||||
)
|
)
|
||||||
case cmdJoin:
|
case irc.CmdJoin:
|
||||||
hdlr.handleJoin(
|
hdlr.handleJoin(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick, target,
|
sessionID, clientID, nick, target,
|
||||||
)
|
)
|
||||||
case cmdPart:
|
case irc.CmdPart:
|
||||||
hdlr.handlePart(
|
hdlr.handlePart(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick, target, body,
|
sessionID, clientID, nick, target, body,
|
||||||
)
|
)
|
||||||
case cmdNick:
|
case irc.CmdNick:
|
||||||
hdlr.handleNick(
|
hdlr.handleNick(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick, bodyLines,
|
sessionID, clientID, nick, bodyLines,
|
||||||
)
|
)
|
||||||
case cmdTopic:
|
case irc.CmdTopic:
|
||||||
hdlr.handleTopic(
|
hdlr.handleTopic(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
target, body, bodyLines,
|
target, body, bodyLines,
|
||||||
)
|
)
|
||||||
case cmdQuit:
|
case irc.CmdQuit:
|
||||||
hdlr.handleQuit(
|
hdlr.handleQuit(
|
||||||
writer, request, sessionID, nick, body,
|
writer, request, sessionID, nick, body,
|
||||||
)
|
)
|
||||||
case cmdMotd, cmdList, cmdWho, cmdWhois, cmdPing:
|
case irc.CmdMotd, irc.CmdPing:
|
||||||
hdlr.dispatchInfoCommand(
|
hdlr.dispatchInfoCommand(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
@@ -819,34 +807,34 @@ func (hdlr *Handlers) dispatchQueryCommand(
|
|||||||
bodyLines func() []string,
|
bodyLines func() []string,
|
||||||
) {
|
) {
|
||||||
switch command {
|
switch command {
|
||||||
case cmdMode:
|
case irc.CmdMode:
|
||||||
hdlr.handleMode(
|
hdlr.handleMode(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
target, bodyLines,
|
target, bodyLines,
|
||||||
)
|
)
|
||||||
case cmdNames:
|
case irc.CmdNames:
|
||||||
hdlr.handleNames(
|
hdlr.handleNames(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick, target,
|
sessionID, clientID, nick, target,
|
||||||
)
|
)
|
||||||
case cmdList:
|
case irc.CmdList:
|
||||||
hdlr.handleList(
|
hdlr.handleList(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
)
|
)
|
||||||
case cmdWhois:
|
case irc.CmdWhois:
|
||||||
hdlr.handleWhois(
|
hdlr.handleWhois(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
target, bodyLines,
|
target, bodyLines,
|
||||||
)
|
)
|
||||||
case cmdWho:
|
case irc.CmdWho:
|
||||||
hdlr.handleWho(
|
hdlr.handleWho(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick, target,
|
sessionID, clientID, nick, target,
|
||||||
)
|
)
|
||||||
case cmdLusers:
|
case irc.CmdLusers:
|
||||||
hdlr.handleLusers(
|
hdlr.handleLusers(
|
||||||
writer, request,
|
writer, request,
|
||||||
sessionID, clientID, nick,
|
sessionID, clientID, nick,
|
||||||
@@ -854,7 +842,7 @@ func (hdlr *Handlers) dispatchQueryCommand(
|
|||||||
default:
|
default:
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"421", nick, []string{command},
|
irc.ErrUnknownCommand, nick, []string{command},
|
||||||
"Unknown command",
|
"Unknown command",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -875,7 +863,7 @@ func (hdlr *Handlers) handlePrivmsg(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"461", nick, []string{command},
|
irc.ErrNeedMoreParams, nick, []string{command},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -890,7 +878,7 @@ func (hdlr *Handlers) handlePrivmsg(
|
|||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"461", nick, []string{command},
|
irc.ErrNeedMoreParams, nick, []string{command},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -924,13 +912,14 @@ func (hdlr *Handlers) respondIRCError(
|
|||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
clientID, sessionID int64,
|
clientID, sessionID int64,
|
||||||
numeric, nick string,
|
code int,
|
||||||
|
nick string,
|
||||||
params []string,
|
params []string,
|
||||||
text string,
|
text string,
|
||||||
) {
|
) {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
numeric, nick, params, text,
|
code, nick, params, text,
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
hdlr.respondJSON(writer, request,
|
hdlr.respondJSON(writer, request,
|
||||||
@@ -951,7 +940,7 @@ func (hdlr *Handlers) handleChannelMsg(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"403", nick, []string{target},
|
irc.ErrNoSuchChannel, nick, []string{target},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -977,7 +966,7 @@ func (hdlr *Handlers) handleChannelMsg(
|
|||||||
if !isMember {
|
if !isMember {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"442", nick, []string{target},
|
irc.ErrNotOnChannel, nick, []string{target},
|
||||||
"You're not on that channel",
|
"You're not on that channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1044,7 +1033,7 @@ func (hdlr *Handlers) handleDirectMsg(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"401", nick, []string{target},
|
irc.ErrNoSuchNick, nick, []string{target},
|
||||||
"No such nick/channel",
|
"No such nick/channel",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -1088,7 +1077,7 @@ func (hdlr *Handlers) handleJoin(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdJoin},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdJoin},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1103,7 +1092,7 @@ func (hdlr *Handlers) handleJoin(
|
|||||||
if !validChannelRe.MatchString(channel) {
|
if !validChannelRe.MatchString(channel) {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"403", nick, []string{channel},
|
irc.ErrNoSuchChannel, nick, []string{channel},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1159,7 +1148,7 @@ func (hdlr *Handlers) executeJoin(
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = hdlr.fanOutSilent(
|
_ = hdlr.fanOutSilent(
|
||||||
request, cmdJoin, nick, channel, nil, memberIDs,
|
request, irc.CmdJoin, nick, channel, nil, memberIDs,
|
||||||
)
|
)
|
||||||
|
|
||||||
hdlr.deliverJoinNumerics(
|
hdlr.deliverJoinNumerics(
|
||||||
@@ -1210,12 +1199,12 @@ func (hdlr *Handlers) deliverJoinNumerics(
|
|||||||
|
|
||||||
if topic != "" {
|
if topic != "" {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "332", nick,
|
ctx, clientID, irc.RplTopic, nick,
|
||||||
[]string{channel}, topic,
|
[]string{channel}, topic,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "331", nick,
|
ctx, clientID, irc.RplNoTopic, nick,
|
||||||
[]string{channel}, "No topic is set",
|
[]string{channel}, "No topic is set",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1233,14 +1222,14 @@ func (hdlr *Handlers) deliverJoinNumerics(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "353", nick,
|
ctx, clientID, irc.RplNamReply, nick,
|
||||||
[]string{"=", channel},
|
[]string{"=", channel},
|
||||||
strings.Join(nicks, " "),
|
strings.Join(nicks, " "),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "366", nick,
|
ctx, clientID, irc.RplEndOfNames, nick,
|
||||||
[]string{channel}, "End of /NAMES list",
|
[]string{channel}, "End of /NAMES list",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1257,7 +1246,7 @@ func (hdlr *Handlers) handlePart(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"461", nick, []string{cmdPart},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdPart},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -1279,7 +1268,7 @@ func (hdlr *Handlers) handlePart(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"403", nick, []string{channel},
|
irc.ErrNoSuchChannel, nick, []string{channel},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
@@ -1295,7 +1284,7 @@ func (hdlr *Handlers) handlePart(
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = hdlr.fanOutSilent(
|
_ = hdlr.fanOutSilent(
|
||||||
request, cmdPart, nick, channel, body, memberIDs,
|
request, irc.CmdPart, nick, channel, body, memberIDs,
|
||||||
)
|
)
|
||||||
|
|
||||||
err = hdlr.params.Database.PartChannel(
|
err = hdlr.params.Database.PartChannel(
|
||||||
@@ -1337,7 +1326,7 @@ func (hdlr *Handlers) handleNick(
|
|||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdNick},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdNick},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1349,7 +1338,7 @@ func (hdlr *Handlers) handleNick(
|
|||||||
if !validNickRe.MatchString(newNick) {
|
if !validNickRe.MatchString(newNick) {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"432", nick, []string{newNick},
|
irc.ErrErroneusNickname, nick, []string{newNick},
|
||||||
"Erroneous nickname",
|
"Erroneous nickname",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1385,7 +1374,7 @@ func (hdlr *Handlers) executeNickChange(
|
|||||||
if strings.Contains(err.Error(), "UNIQUE") {
|
if strings.Contains(err.Error(), "UNIQUE") {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"433", nick, []string{newNick},
|
irc.ErrNicknameInUse, nick, []string{newNick},
|
||||||
"Nickname is already in use",
|
"Nickname is already in use",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1435,7 +1424,7 @@ func (hdlr *Handlers) broadcastNick(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbID, _, _ := hdlr.params.Database.InsertMessage(
|
dbID, _, _ := hdlr.params.Database.InsertMessage(
|
||||||
request.Context(), cmdNick, oldNick, "",
|
request.Context(), irc.CmdNick, oldNick, "",
|
||||||
nil, json.RawMessage(nickBody), nil,
|
nil, json.RawMessage(nickBody), nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1476,7 +1465,7 @@ func (hdlr *Handlers) handleTopic(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdTopic},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdTopic},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1487,7 +1476,7 @@ func (hdlr *Handlers) handleTopic(
|
|||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdTopic},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdTopic},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1505,7 +1494,7 @@ func (hdlr *Handlers) handleTopic(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"403", nick, []string{channel},
|
irc.ErrNoSuchChannel, nick, []string{channel},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1549,12 +1538,12 @@ func (hdlr *Handlers) executeTopic(
|
|||||||
)
|
)
|
||||||
|
|
||||||
_ = hdlr.fanOutSilent(
|
_ = hdlr.fanOutSilent(
|
||||||
request, cmdTopic, nick, channel, body, memberIDs,
|
request, irc.CmdTopic, nick, channel, body, memberIDs,
|
||||||
)
|
)
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"332", nick, []string{channel}, topic,
|
irc.RplTopic, nick, []string{channel}, topic,
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
|
|
||||||
@@ -1566,8 +1555,7 @@ func (hdlr *Handlers) executeTopic(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dispatchInfoCommand handles informational IRC commands
|
// dispatchInfoCommand handles informational IRC commands
|
||||||
// that produce server-side numerics (MOTD, LIST, WHO,
|
// that produce server-side numerics (MOTD, PING).
|
||||||
// WHOIS, PING).
|
|
||||||
func (hdlr *Handlers) dispatchInfoCommand(
|
func (hdlr *Handlers) dispatchInfoCommand(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
@@ -1575,31 +1563,20 @@ func (hdlr *Handlers) dispatchInfoCommand(
|
|||||||
nick, command, target string,
|
nick, command, target string,
|
||||||
bodyLines func() []string,
|
bodyLines func() []string,
|
||||||
) {
|
) {
|
||||||
|
_ = target
|
||||||
|
_ = bodyLines
|
||||||
|
|
||||||
okResp := map[string]string{"status": "ok"}
|
okResp := map[string]string{"status": "ok"}
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
case cmdMotd:
|
case irc.CmdMotd:
|
||||||
hdlr.deliverMOTD(
|
hdlr.deliverMOTD(
|
||||||
request, clientID, sessionID, nick,
|
request, clientID, sessionID, nick,
|
||||||
)
|
)
|
||||||
case cmdList:
|
case irc.CmdPing:
|
||||||
hdlr.handleListCmd(
|
|
||||||
request, clientID, sessionID, nick,
|
|
||||||
)
|
|
||||||
case cmdWho:
|
|
||||||
hdlr.handleWhoCmd(
|
|
||||||
request, clientID, sessionID, nick,
|
|
||||||
target,
|
|
||||||
)
|
|
||||||
case cmdWhois:
|
|
||||||
hdlr.handleWhoisCmd(
|
|
||||||
request, clientID, sessionID, nick,
|
|
||||||
target, bodyLines,
|
|
||||||
)
|
|
||||||
case cmdPing:
|
|
||||||
hdlr.respondJSON(writer, request,
|
hdlr.respondJSON(writer, request,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"command": cmdPong,
|
"command": irc.CmdPong,
|
||||||
"from": hdlr.serverName(),
|
"from": hdlr.serverName(),
|
||||||
},
|
},
|
||||||
http.StatusOK)
|
http.StatusOK)
|
||||||
@@ -1612,222 +1589,6 @@ func (hdlr *Handlers) dispatchInfoCommand(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleListCmd sends RPL_LIST (322) for each channel,
|
|
||||||
// then sends 323 to signal the end of the list.
|
|
||||||
func (hdlr *Handlers) handleListCmd(
|
|
||||||
request *http.Request,
|
|
||||||
clientID, sessionID int64,
|
|
||||||
nick string,
|
|
||||||
) {
|
|
||||||
ctx := request.Context()
|
|
||||||
|
|
||||||
channels, err := hdlr.params.Database.ListAllChannels(
|
|
||||||
ctx,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "323", nick, nil,
|
|
||||||
"End of /LIST",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, channel := range channels {
|
|
||||||
memberIDs, _ :=
|
|
||||||
hdlr.params.Database.GetChannelMemberIDs(
|
|
||||||
ctx, channel.ID,
|
|
||||||
)
|
|
||||||
|
|
||||||
count := strconv.Itoa(len(memberIDs))
|
|
||||||
topic := channel.Topic
|
|
||||||
|
|
||||||
if topic == "" {
|
|
||||||
topic = " "
|
|
||||||
}
|
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "322", nick,
|
|
||||||
[]string{channel.Name, count}, topic,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "323", nick, nil,
|
|
||||||
"End of /LIST",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleWhoCmd sends RPL_WHOREPLY (352) for each member
|
|
||||||
// of the target channel, followed by RPL_ENDOFWHO (315).
|
|
||||||
func (hdlr *Handlers) handleWhoCmd(
|
|
||||||
request *http.Request,
|
|
||||||
clientID, sessionID int64,
|
|
||||||
nick, target string,
|
|
||||||
) {
|
|
||||||
ctx := request.Context()
|
|
||||||
|
|
||||||
if target == "" {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "461", nick,
|
|
||||||
[]string{cmdWho}, "Not enough parameters",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
channel := target
|
|
||||||
if !strings.HasPrefix(channel, "#") {
|
|
||||||
channel = "#" + channel
|
|
||||||
}
|
|
||||||
|
|
||||||
chID, err := hdlr.params.Database.GetChannelByName(
|
|
||||||
ctx, channel,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "315", nick,
|
|
||||||
[]string{channel}, "End of /WHO list",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
members, err := hdlr.params.Database.ChannelMembers(
|
|
||||||
ctx, chID,
|
|
||||||
)
|
|
||||||
if err == nil {
|
|
||||||
srvName := hdlr.serverName()
|
|
||||||
|
|
||||||
for _, mem := range members {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "352", nick,
|
|
||||||
[]string{
|
|
||||||
channel, mem.Nick, "neoirc",
|
|
||||||
srvName, mem.Nick, "H",
|
|
||||||
},
|
|
||||||
"0 "+mem.Nick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "315", nick,
|
|
||||||
[]string{channel}, "End of /WHO list",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleWhoisCmd sends WHOIS reply numerics (311, 312,
|
|
||||||
// 319, 318) for the target nick.
|
|
||||||
func (hdlr *Handlers) handleWhoisCmd(
|
|
||||||
request *http.Request,
|
|
||||||
clientID, sessionID int64,
|
|
||||||
nick, target string,
|
|
||||||
bodyLines func() []string,
|
|
||||||
) {
|
|
||||||
ctx := request.Context()
|
|
||||||
|
|
||||||
whoisNick := target
|
|
||||||
if whoisNick == "" {
|
|
||||||
lines := bodyLines()
|
|
||||||
if len(lines) > 0 {
|
|
||||||
whoisNick = strings.TrimSpace(lines[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if whoisNick == "" {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "461", nick,
|
|
||||||
[]string{cmdWhois}, "Not enough parameters",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
targetSID, err :=
|
|
||||||
hdlr.params.Database.GetSessionByNick(
|
|
||||||
ctx, whoisNick,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "401", nick,
|
|
||||||
[]string{whoisNick},
|
|
||||||
"No such nick/channel",
|
|
||||||
)
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "318", nick,
|
|
||||||
[]string{whoisNick},
|
|
||||||
"End of /WHOIS list",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
hdlr.sendWhoisNumerics(
|
|
||||||
ctx, clientID, sessionID, nick,
|
|
||||||
whoisNick, targetSID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendWhoisNumerics emits 311/312/319/318 for a
|
|
||||||
// resolved WHOIS target.
|
|
||||||
func (hdlr *Handlers) sendWhoisNumerics(
|
|
||||||
ctx context.Context,
|
|
||||||
clientID, sessionID int64,
|
|
||||||
nick, whoisNick string,
|
|
||||||
targetSID int64,
|
|
||||||
) {
|
|
||||||
srvName := hdlr.serverName()
|
|
||||||
|
|
||||||
// 311 RPL_WHOISUSER
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "311", nick,
|
|
||||||
[]string{whoisNick, whoisNick, "neoirc", "*"},
|
|
||||||
whoisNick,
|
|
||||||
)
|
|
||||||
|
|
||||||
// 312 RPL_WHOISSERVER
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "312", nick,
|
|
||||||
[]string{whoisNick, srvName},
|
|
||||||
srvName,
|
|
||||||
)
|
|
||||||
|
|
||||||
// 319 RPL_WHOISCHANNELS
|
|
||||||
channels, _ := hdlr.params.Database.GetSessionChannels(
|
|
||||||
ctx, targetSID,
|
|
||||||
)
|
|
||||||
|
|
||||||
if len(channels) > 0 {
|
|
||||||
names := make([]string, 0, len(channels))
|
|
||||||
|
|
||||||
for _, chanInfo := range channels {
|
|
||||||
names = append(names, chanInfo.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "319", nick,
|
|
||||||
[]string{whoisNick},
|
|
||||||
strings.Join(names, " "),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 318 RPL_ENDOFWHOIS
|
|
||||||
hdlr.enqueueNumeric(
|
|
||||||
ctx, clientID, "318", nick,
|
|
||||||
[]string{whoisNick},
|
|
||||||
"End of /WHOIS list",
|
|
||||||
)
|
|
||||||
hdlr.broker.Notify(sessionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hdlr *Handlers) handleQuit(
|
func (hdlr *Handlers) handleQuit(
|
||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
@@ -1846,7 +1607,7 @@ func (hdlr *Handlers) handleQuit(
|
|||||||
|
|
||||||
if len(channels) > 0 {
|
if len(channels) > 0 {
|
||||||
dbID, _, _ = hdlr.params.Database.InsertMessage(
|
dbID, _, _ = hdlr.params.Database.InsertMessage(
|
||||||
request.Context(), cmdQuit, nick, "",
|
request.Context(), irc.CmdQuit, nick, "",
|
||||||
nil, body, nil,
|
nil, body, nil,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1899,7 +1660,7 @@ func (hdlr *Handlers) handleMode(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdMode},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdMode},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1911,7 +1672,7 @@ func (hdlr *Handlers) handleMode(
|
|||||||
// User mode query — return empty modes.
|
// User mode query — return empty modes.
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
request.Context(), clientID,
|
request.Context(), clientID,
|
||||||
"221", nick, nil, "+",
|
irc.RplUmodeIs, nick, nil, "+",
|
||||||
)
|
)
|
||||||
hdlr.broker.Notify(sessionID)
|
hdlr.broker.Notify(sessionID)
|
||||||
hdlr.respondJSON(writer, request,
|
hdlr.respondJSON(writer, request,
|
||||||
@@ -1943,7 +1704,7 @@ func (hdlr *Handlers) handleChannelMode(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"403", nick, []string{channel},
|
irc.ErrNoSuchChannel, nick, []string{channel},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1952,7 +1713,7 @@ func (hdlr *Handlers) handleChannelMode(
|
|||||||
|
|
||||||
// 324 RPL_CHANNELMODEIS
|
// 324 RPL_CHANNELMODEIS
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "324", nick,
|
ctx, clientID, irc.RplChannelModeIs, nick,
|
||||||
[]string{channel, "+n"}, "",
|
[]string{channel, "+n"}, "",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1961,7 +1722,7 @@ func (hdlr *Handlers) handleChannelMode(
|
|||||||
GetChannelCreatedAt(ctx, chID)
|
GetChannelCreatedAt(ctx, chID)
|
||||||
if timeErr == nil {
|
if timeErr == nil {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "329", nick,
|
ctx, clientID, irc.RplCreationTime, nick,
|
||||||
[]string{
|
[]string{
|
||||||
channel,
|
channel,
|
||||||
strconv.FormatInt(
|
strconv.FormatInt(
|
||||||
@@ -1988,7 +1749,7 @@ func (hdlr *Handlers) handleNames(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdNames},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdNames},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2008,7 +1769,7 @@ func (hdlr *Handlers) handleNames(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"403", nick, []string{channel},
|
irc.ErrNoSuchChannel, nick, []string{channel},
|
||||||
"No such channel",
|
"No such channel",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2026,14 +1787,14 @@ func (hdlr *Handlers) handleNames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "353", nick,
|
ctx, clientID, irc.RplNamReply, nick,
|
||||||
[]string{"=", channel},
|
[]string{"=", channel},
|
||||||
strings.Join(nicks, " "),
|
strings.Join(nicks, " "),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "366", nick,
|
ctx, clientID, irc.RplEndOfNames, nick,
|
||||||
[]string{channel}, "End of /NAMES list",
|
[]string{channel}, "End of /NAMES list",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2071,7 +1832,7 @@ func (hdlr *Handlers) handleList(
|
|||||||
for _, chanInfo := range channels {
|
for _, chanInfo := range channels {
|
||||||
// 322 RPL_LIST
|
// 322 RPL_LIST
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "322", nick,
|
ctx, clientID, irc.RplList, nick,
|
||||||
[]string{
|
[]string{
|
||||||
chanInfo.Name,
|
chanInfo.Name,
|
||||||
strconv.FormatInt(
|
strconv.FormatInt(
|
||||||
@@ -2084,7 +1845,7 @@ func (hdlr *Handlers) handleList(
|
|||||||
|
|
||||||
// 323 — end of channel list.
|
// 323 — end of channel list.
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "323", nick, nil,
|
ctx, clientID, irc.RplListEnd, nick, nil,
|
||||||
"End of /LIST",
|
"End of /LIST",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2115,7 +1876,7 @@ func (hdlr *Handlers) handleWhois(
|
|||||||
if queryNick == "" {
|
if queryNick == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdWhois},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdWhois},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2142,12 +1903,12 @@ func (hdlr *Handlers) executeWhois(
|
|||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "401", nick,
|
ctx, clientID, irc.ErrNoSuchNick, nick,
|
||||||
[]string{queryNick},
|
[]string{queryNick},
|
||||||
"No such nick/channel",
|
"No such nick/channel",
|
||||||
)
|
)
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "318", nick,
|
ctx, clientID, irc.RplEndOfWhois, nick,
|
||||||
[]string{queryNick},
|
[]string{queryNick},
|
||||||
"End of /WHOIS list",
|
"End of /WHOIS list",
|
||||||
)
|
)
|
||||||
@@ -2161,14 +1922,14 @@ func (hdlr *Handlers) executeWhois(
|
|||||||
|
|
||||||
// 311 RPL_WHOISUSER
|
// 311 RPL_WHOISUSER
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "311", nick,
|
ctx, clientID, irc.RplWhoisUser, nick,
|
||||||
[]string{queryNick, queryNick, srvName, "*"},
|
[]string{queryNick, queryNick, srvName, "*"},
|
||||||
queryNick,
|
queryNick,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 312 RPL_WHOISSERVER
|
// 312 RPL_WHOISSERVER
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "312", nick,
|
ctx, clientID, irc.RplWhoisServer, nick,
|
||||||
[]string{queryNick, srvName},
|
[]string{queryNick, srvName},
|
||||||
"neoirc server",
|
"neoirc server",
|
||||||
)
|
)
|
||||||
@@ -2180,7 +1941,7 @@ func (hdlr *Handlers) executeWhois(
|
|||||||
|
|
||||||
// 318 RPL_ENDOFWHOIS
|
// 318 RPL_ENDOFWHOIS
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "318", nick,
|
ctx, clientID, irc.RplEndOfWhois, nick,
|
||||||
[]string{queryNick},
|
[]string{queryNick},
|
||||||
"End of /WHOIS list",
|
"End of /WHOIS list",
|
||||||
)
|
)
|
||||||
@@ -2210,7 +1971,7 @@ func (hdlr *Handlers) deliverWhoisChannels(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "319", nick,
|
ctx, clientID, irc.RplWhoisChannels, nick,
|
||||||
[]string{queryNick},
|
[]string{queryNick},
|
||||||
strings.Join(chanNames, " "),
|
strings.Join(chanNames, " "),
|
||||||
)
|
)
|
||||||
@@ -2226,7 +1987,7 @@ func (hdlr *Handlers) handleWho(
|
|||||||
if target == "" {
|
if target == "" {
|
||||||
hdlr.respondIRCError(
|
hdlr.respondIRCError(
|
||||||
writer, request, clientID, sessionID,
|
writer, request, clientID, sessionID,
|
||||||
"461", nick, []string{cmdWho},
|
irc.ErrNeedMoreParams, nick, []string{irc.CmdWho},
|
||||||
"Not enough parameters",
|
"Not enough parameters",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2247,7 +2008,7 @@ func (hdlr *Handlers) handleWho(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// 315 RPL_ENDOFWHO (empty result)
|
// 315 RPL_ENDOFWHO (empty result)
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "315", nick,
|
ctx, clientID, irc.RplEndOfWho, nick,
|
||||||
[]string{target},
|
[]string{target},
|
||||||
"End of /WHO list",
|
"End of /WHO list",
|
||||||
)
|
)
|
||||||
@@ -2266,7 +2027,7 @@ func (hdlr *Handlers) handleWho(
|
|||||||
for _, mem := range members {
|
for _, mem := range members {
|
||||||
// 352 RPL_WHOREPLY
|
// 352 RPL_WHOREPLY
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "352", nick,
|
ctx, clientID, irc.RplWhoReply, nick,
|
||||||
[]string{
|
[]string{
|
||||||
channel, mem.Nick, srvName,
|
channel, mem.Nick, srvName,
|
||||||
srvName, mem.Nick, "H",
|
srvName, mem.Nick, "H",
|
||||||
@@ -2278,7 +2039,7 @@ func (hdlr *Handlers) handleWho(
|
|||||||
|
|
||||||
// 315 RPL_ENDOFWHO
|
// 315 RPL_ENDOFWHO
|
||||||
hdlr.enqueueNumeric(
|
hdlr.enqueueNumeric(
|
||||||
ctx, clientID, "315", nick,
|
ctx, clientID, irc.RplEndOfWho, nick,
|
||||||
[]string{channel},
|
[]string{channel},
|
||||||
"End of /WHO list",
|
"End of /WHO list",
|
||||||
)
|
)
|
||||||
@@ -2514,7 +2275,7 @@ func (hdlr *Handlers) cleanupUser(
|
|||||||
|
|
||||||
if len(channels) > 0 {
|
if len(channels) > 0 {
|
||||||
quitDBID, _, _ = hdlr.params.Database.InsertMessage(
|
quitDBID, _, _ = hdlr.params.Database.InsertMessage(
|
||||||
ctx, cmdQuit, nick, "",
|
ctx, irc.CmdQuit, nick, "",
|
||||||
nil, nil, nil,
|
nil, nil, nil,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -467,8 +468,11 @@ func findNumeric(
|
|||||||
msgs []map[string]any,
|
msgs []map[string]any,
|
||||||
numeric string,
|
numeric string,
|
||||||
) bool {
|
) bool {
|
||||||
|
want, _ := strconv.Atoi(numeric)
|
||||||
|
|
||||||
for _, msg := range msgs {
|
for _, msg := range msgs {
|
||||||
if msg[commandKey] == numeric {
|
code, ok := msg["code"].(float64)
|
||||||
|
if ok && int(code) == want {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
internal/irc/commands.go
Normal file
21
internal/irc/commands.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package irc
|
||||||
|
|
||||||
|
// IRC command names (RFC 1459 / RFC 2812).
|
||||||
|
const (
|
||||||
|
CmdJoin = "JOIN"
|
||||||
|
CmdList = "LIST"
|
||||||
|
CmdLusers = "LUSERS"
|
||||||
|
CmdMode = "MODE"
|
||||||
|
CmdMotd = "MOTD"
|
||||||
|
CmdNames = "NAMES"
|
||||||
|
CmdNick = "NICK"
|
||||||
|
CmdNotice = "NOTICE"
|
||||||
|
CmdPart = "PART"
|
||||||
|
CmdPing = "PING"
|
||||||
|
CmdPong = "PONG"
|
||||||
|
CmdPrivmsg = "PRIVMSG"
|
||||||
|
CmdQuit = "QUIT"
|
||||||
|
CmdTopic = "TOPIC"
|
||||||
|
CmdWho = "WHO"
|
||||||
|
CmdWhois = "WHOIS"
|
||||||
|
)
|
||||||
150
internal/irc/numerics.go
Normal file
150
internal/irc/numerics.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// Package irc provides constants and utilities for the
|
||||||
|
// IRC protocol, including numeric reply codes from
|
||||||
|
// RFC 1459 and RFC 2812, and standard command names.
|
||||||
|
package irc
|
||||||
|
|
||||||
|
// Connection registration replies (001-005).
|
||||||
|
const (
|
||||||
|
RplWelcome = 1
|
||||||
|
RplYourHost = 2
|
||||||
|
RplCreated = 3
|
||||||
|
RplMyInfo = 4
|
||||||
|
RplIsupport = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command responses (200-399).
|
||||||
|
const (
|
||||||
|
RplUmodeIs = 221
|
||||||
|
RplLuserClient = 251
|
||||||
|
RplLuserOp = 252
|
||||||
|
RplLuserUnknown = 253
|
||||||
|
RplLuserChannels = 254
|
||||||
|
RplLuserMe = 255
|
||||||
|
RplAway = 301
|
||||||
|
RplUserHost = 302
|
||||||
|
RplIson = 303
|
||||||
|
RplUnaway = 305
|
||||||
|
RplNowAway = 306
|
||||||
|
RplWhoisUser = 311
|
||||||
|
RplWhoisServer = 312
|
||||||
|
RplWhoisOperator = 313
|
||||||
|
RplEndOfWho = 315
|
||||||
|
RplWhoisIdle = 317
|
||||||
|
RplEndOfWhois = 318
|
||||||
|
RplWhoisChannels = 319
|
||||||
|
RplList = 322
|
||||||
|
RplListEnd = 323
|
||||||
|
RplChannelModeIs = 324
|
||||||
|
RplCreationTime = 329
|
||||||
|
RplNoTopic = 331
|
||||||
|
RplTopic = 332
|
||||||
|
RplTopicWhoTime = 333
|
||||||
|
RplInviting = 341
|
||||||
|
RplWhoReply = 352
|
||||||
|
RplNamReply = 353
|
||||||
|
RplEndOfNames = 366
|
||||||
|
RplBanList = 367
|
||||||
|
RplEndOfBanList = 368
|
||||||
|
RplMotd = 372
|
||||||
|
RplMotdStart = 375
|
||||||
|
RplEndOfMotd = 376
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error replies (400-599).
|
||||||
|
const (
|
||||||
|
ErrNoSuchNick = 401
|
||||||
|
ErrNoSuchServer = 402
|
||||||
|
ErrNoSuchChannel = 403
|
||||||
|
ErrCannotSendToChan = 404
|
||||||
|
ErrTooManyChannels = 405
|
||||||
|
ErrNoRecipient = 411
|
||||||
|
ErrNoTextToSend = 412
|
||||||
|
ErrUnknownCommand = 421
|
||||||
|
ErrNoNicknameGiven = 431
|
||||||
|
ErrErroneusNickname = 432
|
||||||
|
ErrNicknameInUse = 433
|
||||||
|
ErrUserNotInChannel = 441
|
||||||
|
ErrNotOnChannel = 442
|
||||||
|
ErrNotRegistered = 451
|
||||||
|
ErrNeedMoreParams = 461
|
||||||
|
ErrAlreadyRegistered = 462
|
||||||
|
ErrChannelIsFull = 471
|
||||||
|
ErrInviteOnlyChan = 473
|
||||||
|
ErrBannedFromChan = 474
|
||||||
|
ErrBadChannelKey = 475
|
||||||
|
ErrChanOpPrivsNeeded = 482
|
||||||
|
)
|
||||||
|
|
||||||
|
// names maps numeric codes to their standard IRC names.
|
||||||
|
//
|
||||||
|
//nolint:gochecknoglobals
|
||||||
|
var names = map[int]string{
|
||||||
|
RplWelcome: "RPL_WELCOME",
|
||||||
|
RplYourHost: "RPL_YOURHOST",
|
||||||
|
RplCreated: "RPL_CREATED",
|
||||||
|
RplMyInfo: "RPL_MYINFO",
|
||||||
|
RplIsupport: "RPL_ISUPPORT",
|
||||||
|
RplUmodeIs: "RPL_UMODEIS",
|
||||||
|
RplLuserClient: "RPL_LUSERCLIENT",
|
||||||
|
RplLuserOp: "RPL_LUSEROP",
|
||||||
|
RplLuserUnknown: "RPL_LUSERUNKNOWN",
|
||||||
|
RplLuserChannels: "RPL_LUSERCHANNELS",
|
||||||
|
RplLuserMe: "RPL_LUSERME",
|
||||||
|
RplAway: "RPL_AWAY",
|
||||||
|
RplUserHost: "RPL_USERHOST",
|
||||||
|
RplIson: "RPL_ISON",
|
||||||
|
RplUnaway: "RPL_UNAWAY",
|
||||||
|
RplNowAway: "RPL_NOWAWAY",
|
||||||
|
RplWhoisUser: "RPL_WHOISUSER",
|
||||||
|
RplWhoisServer: "RPL_WHOISSERVER",
|
||||||
|
RplWhoisOperator: "RPL_WHOISOPERATOR",
|
||||||
|
RplEndOfWho: "RPL_ENDOFWHO",
|
||||||
|
RplWhoisIdle: "RPL_WHOISIDLE",
|
||||||
|
RplEndOfWhois: "RPL_ENDOFWHOIS",
|
||||||
|
RplWhoisChannels: "RPL_WHOISCHANNELS",
|
||||||
|
RplList: "RPL_LIST",
|
||||||
|
RplListEnd: "RPL_LISTEND", //nolint:misspell
|
||||||
|
RplChannelModeIs: "RPL_CHANNELMODEIS",
|
||||||
|
RplCreationTime: "RPL_CREATIONTIME",
|
||||||
|
RplNoTopic: "RPL_NOTOPIC",
|
||||||
|
RplTopic: "RPL_TOPIC",
|
||||||
|
RplTopicWhoTime: "RPL_TOPICWHOTIME",
|
||||||
|
RplInviting: "RPL_INVITING",
|
||||||
|
RplWhoReply: "RPL_WHOREPLY",
|
||||||
|
RplNamReply: "RPL_NAMREPLY",
|
||||||
|
RplEndOfNames: "RPL_ENDOFNAMES",
|
||||||
|
RplBanList: "RPL_BANLIST",
|
||||||
|
RplEndOfBanList: "RPL_ENDOFBANLIST",
|
||||||
|
RplMotd: "RPL_MOTD",
|
||||||
|
RplMotdStart: "RPL_MOTDSTART",
|
||||||
|
RplEndOfMotd: "RPL_ENDOFMOTD",
|
||||||
|
|
||||||
|
ErrNoSuchNick: "ERR_NOSUCHNICK",
|
||||||
|
ErrNoSuchServer: "ERR_NOSUCHSERVER",
|
||||||
|
ErrNoSuchChannel: "ERR_NOSUCHCHANNEL",
|
||||||
|
ErrCannotSendToChan: "ERR_CANNOTSENDTOCHAN",
|
||||||
|
ErrTooManyChannels: "ERR_TOOMANYCHANNELS",
|
||||||
|
ErrNoRecipient: "ERR_NORECIPIENT",
|
||||||
|
ErrNoTextToSend: "ERR_NOTEXTTOSEND",
|
||||||
|
ErrUnknownCommand: "ERR_UNKNOWNCOMMAND",
|
||||||
|
ErrNoNicknameGiven: "ERR_NONICKNAMEGIVEN",
|
||||||
|
ErrErroneusNickname: "ERR_ERRONEUSNICKNAME",
|
||||||
|
ErrNicknameInUse: "ERR_NICKNAMEINUSE",
|
||||||
|
ErrUserNotInChannel: "ERR_USERNOTINCHANNEL",
|
||||||
|
ErrNotOnChannel: "ERR_NOTONCHANNEL",
|
||||||
|
ErrNotRegistered: "ERR_NOTREGISTERED",
|
||||||
|
ErrNeedMoreParams: "ERR_NEEDMOREPARAMS",
|
||||||
|
ErrAlreadyRegistered: "ERR_ALREADYREGISTERED",
|
||||||
|
ErrChannelIsFull: "ERR_CHANNELISFULL",
|
||||||
|
ErrInviteOnlyChan: "ERR_INVITEONLYCHAN",
|
||||||
|
ErrBannedFromChan: "ERR_BANNEDFROMCHAN",
|
||||||
|
ErrBadChannelKey: "ERR_BADCHANNELKEY",
|
||||||
|
ErrChanOpPrivsNeeded: "ERR_CHANOPRIVSNEEDED",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the standard IRC name for a numeric code
|
||||||
|
// (e.g., Name(2) returns "RPL_YOURHOST"). Returns an
|
||||||
|
// empty string if the code is unknown.
|
||||||
|
func Name(code int) string {
|
||||||
|
return names[code]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user