2 Commits

Author SHA1 Message Date
bc8df117ab Merge branch 'main' into feature/irc-numerics-batch2
Some checks failed
check / check (push) Failing after 22s
2026-03-09 23:00:43 +01:00
clawbot
df82c6b302 feat: implement IRC numerics batch 2 — connection registration, channel ops, user queries
All checks were successful
check / check (push) Successful in 2m50s
Add comprehensive IRC numeric reply support:

Connection registration (001-005):
- 002 RPL_YOURHOST, 003 RPL_CREATED, 004 RPL_MYINFO, 005 RPL_ISUPPORT
- All sent automatically during session creation after RPL_WELCOME

Server statistics (251-255):
- RPL_LUSERCLIENT, RPL_LUSEROP, RPL_LUSERCHANNELS, RPL_LUSERME
- Sent during connection registration and via LUSERS command

Channel operations:
- MODE command: query channel modes (324 RPL_CHANNELMODEIS, 329 RPL_CREATIONTIME)
- MODE command: query user modes (221 RPL_UMODEIS)
- NAMES command: query channel member list (353/366)
- LIST command: list all channels (322 RPL_LIST, 323 end of list)

User queries:
- WHOIS command: 311/312/318/319 numerics
- WHO command: 352 RPL_WHOREPLY, 315 RPL_ENDOFWHO

Database additions:
- GetChannelCount, ListAllChannelsWithCounts
- GetChannelCreatedAt, GetSessionCreatedAt

Also adds StartTime to Globals for RPL_CREATED and updates README
with comprehensive documentation of all new commands and numerics.

closes #52
2026-03-09 14:53:49 -07:00

View File

@@ -27,15 +27,7 @@ const (
defaultMaxBodySize = 4096
defaultHistLimit = 50
maxHistLimit = 500
cmdJoin = "JOIN"
cmdList = "LIST"
cmdNick = "NICK"
cmdPart = "PART"
cmdPrivmsg = "PRIVMSG"
cmdQuit = "QUIT"
cmdTopic = "TOPIC"
cmdWho = "WHO"
cmdWhois = "WHOIS"
)
func (hdlr *Handlers) maxBodySize() int64 {
@@ -764,32 +756,32 @@ func (hdlr *Handlers) dispatchCommand(
sessionID, clientID, nick,
command, target, body, bodyLines,
)
case cmdJoin:
case "JOIN":
hdlr.handleJoin(
writer, request,
sessionID, clientID, nick, target,
)
case cmdPart:
case "PART":
hdlr.handlePart(
writer, request,
sessionID, clientID, nick, target, body,
)
case cmdNick:
case "NICK":
hdlr.handleNick(
writer, request,
sessionID, clientID, nick, bodyLines,
)
case cmdTopic:
case "TOPIC":
hdlr.handleTopic(
writer, request,
sessionID, clientID, nick,
target, body, bodyLines,
)
case cmdQuit:
case "QUIT":
hdlr.handleQuit(
writer, request, sessionID, nick, body,
)
case "MOTD", cmdList, cmdWho, cmdWhois, "PING":
case "MOTD", "LIST", "WHO", "WHOIS", "PING":
hdlr.dispatchInfoCommand(
writer, request,
sessionID, clientID, nick,
@@ -823,18 +815,18 @@ func (hdlr *Handlers) dispatchQueryCommand(
writer, request,
sessionID, clientID, nick, target,
)
case cmdList:
case "LIST":
hdlr.handleList(
writer, request,
sessionID, clientID, nick,
)
case cmdWhois:
case "WHOIS":
hdlr.handleWhois(
writer, request,
sessionID, clientID, nick,
target, bodyLines,
)
case cmdWho:
case "WHO":
hdlr.handleWho(
writer, request,
sessionID, clientID, nick, target,
@@ -1081,7 +1073,7 @@ func (hdlr *Handlers) handleJoin(
if target == "" {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdJoin},
"461", nick, []string{"JOIN"},
"Not enough parameters",
)
@@ -1152,7 +1144,7 @@ func (hdlr *Handlers) executeJoin(
)
_ = hdlr.fanOutSilent(
request, cmdJoin, nick, channel, nil, memberIDs,
request, "JOIN", nick, channel, nil, memberIDs,
)
hdlr.deliverJoinNumerics(
@@ -1250,7 +1242,7 @@ func (hdlr *Handlers) handlePart(
if target == "" {
hdlr.enqueueNumeric(
request.Context(), clientID,
"461", nick, []string{cmdPart},
"461", nick, []string{"PART"},
"Not enough parameters",
)
hdlr.broker.Notify(sessionID)
@@ -1288,7 +1280,7 @@ func (hdlr *Handlers) handlePart(
)
_ = hdlr.fanOutSilent(
request, cmdPart, nick, channel, body, memberIDs,
request, "PART", nick, channel, body, memberIDs,
)
err = hdlr.params.Database.PartChannel(
@@ -1330,7 +1322,7 @@ func (hdlr *Handlers) handleNick(
if len(lines) == 0 {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdNick},
"461", nick, []string{"NICK"},
"Not enough parameters",
)
@@ -1428,7 +1420,7 @@ func (hdlr *Handlers) broadcastNick(
}
dbID, _, _ := hdlr.params.Database.InsertMessage(
request.Context(), cmdNick, oldNick, "",
request.Context(), "NICK", oldNick, "",
nil, json.RawMessage(nickBody), nil,
)
@@ -1469,7 +1461,7 @@ func (hdlr *Handlers) handleTopic(
if target == "" {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdTopic},
"461", nick, []string{"TOPIC"},
"Not enough parameters",
)
@@ -1480,7 +1472,7 @@ func (hdlr *Handlers) handleTopic(
if len(lines) == 0 {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdTopic},
"461", nick, []string{"TOPIC"},
"Not enough parameters",
)
@@ -1542,7 +1534,7 @@ func (hdlr *Handlers) executeTopic(
)
_ = hdlr.fanOutSilent(
request, cmdTopic, nick, channel, body, memberIDs,
request, "TOPIC", nick, channel, body, memberIDs,
)
hdlr.enqueueNumeric(
@@ -1575,16 +1567,16 @@ func (hdlr *Handlers) dispatchInfoCommand(
hdlr.deliverMOTD(
request, clientID, sessionID, nick,
)
case cmdList:
case "LIST":
hdlr.handleListCmd(
request, clientID, sessionID, nick,
)
case cmdWho:
case "WHO":
hdlr.handleWhoCmd(
request, clientID, sessionID, nick,
target,
)
case cmdWhois:
case "WHOIS":
hdlr.handleWhoisCmd(
request, clientID, sessionID, nick,
target, bodyLines,
@@ -1665,7 +1657,7 @@ func (hdlr *Handlers) handleWhoCmd(
if target == "" {
hdlr.enqueueNumeric(
ctx, clientID, "461", nick,
[]string{cmdWho}, "Not enough parameters",
[]string{"WHO"}, "Not enough parameters",
)
hdlr.broker.Notify(sessionID)
@@ -1736,7 +1728,7 @@ func (hdlr *Handlers) handleWhoisCmd(
if whoisNick == "" {
hdlr.enqueueNumeric(
ctx, clientID, "461", nick,
[]string{cmdWhois}, "Not enough parameters",
[]string{"WHOIS"}, "Not enough parameters",
)
hdlr.broker.Notify(sessionID)
@@ -1839,7 +1831,7 @@ func (hdlr *Handlers) handleQuit(
if len(channels) > 0 {
dbID, _, _ = hdlr.params.Database.InsertMessage(
request.Context(), cmdQuit, nick, "",
request.Context(), "QUIT", nick, "",
nil, body, nil,
)
}
@@ -2108,7 +2100,7 @@ func (hdlr *Handlers) handleWhois(
if queryNick == "" {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdWhois},
"461", nick, []string{"WHOIS"},
"Not enough parameters",
)
@@ -2219,7 +2211,7 @@ func (hdlr *Handlers) handleWho(
if target == "" {
hdlr.respondIRCError(
writer, request, clientID, sessionID,
"461", nick, []string{cmdWho},
"461", nick, []string{"WHO"},
"Not enough parameters",
)
@@ -2507,7 +2499,7 @@ func (hdlr *Handlers) cleanupUser(
if len(channels) > 0 {
quitDBID, _, _ = hdlr.params.Database.InsertMessage(
ctx, cmdQuit, nick, "",
ctx, "QUIT", nick, "",
nil, nil, nil,
)
}