USERHOST, VERSION, ADMIN, INFO, TIME, KILL and WALLOPS on both the HTTP API and the IRC listener, and user mode +w. Model: opus-5-5
This commit is contained in:
+51
-31
@@ -962,10 +962,12 @@ func (hdlr *Handlers) dispatchCommand(
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
switch command {
|
||||
case irc.CmdAway:
|
||||
hdlr.handleAway(
|
||||
case irc.CmdAway, irc.CmdNick,
|
||||
irc.CmdPass, irc.CmdInvite:
|
||||
hdlr.dispatchBodyOnlyCommand(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
sessionID, clientID, nick,
|
||||
command, bodyLines,
|
||||
)
|
||||
case irc.CmdPrivmsg, irc.CmdNotice:
|
||||
hdlr.handlePrivmsg(
|
||||
@@ -984,27 +986,12 @@ func (hdlr *Handlers) dispatchCommand(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, target, body,
|
||||
)
|
||||
case irc.CmdNick:
|
||||
hdlr.handleNick(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdPass:
|
||||
hdlr.handlePass(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdTopic:
|
||||
hdlr.handleTopic(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
target, body, bodyLines,
|
||||
)
|
||||
case irc.CmdInvite:
|
||||
hdlr.handleInvite(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdKick:
|
||||
hdlr.handleKick(
|
||||
writer, request,
|
||||
@@ -1015,12 +1002,15 @@ func (hdlr *Handlers) dispatchCommand(
|
||||
hdlr.handleQuit(
|
||||
writer, request, sessionID, nick, body,
|
||||
)
|
||||
case irc.CmdOper:
|
||||
hdlr.handleOper(
|
||||
case irc.CmdOper, irc.CmdKill, irc.CmdWallops:
|
||||
hdlr.dispatchOperCommand(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
sessionID, clientID, nick,
|
||||
command, bodyLines,
|
||||
)
|
||||
case irc.CmdMotd, irc.CmdPing:
|
||||
case irc.CmdMotd, irc.CmdPing,
|
||||
irc.CmdVersion, irc.CmdAdmin,
|
||||
irc.CmdInfo, irc.CmdTime:
|
||||
hdlr.dispatchInfoCommand(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
@@ -1075,6 +1065,11 @@ func (hdlr *Handlers) dispatchQueryCommand(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
)
|
||||
case irc.CmdUserhost:
|
||||
hdlr.handleUserhost(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
default:
|
||||
hdlr.enqueueNumeric(
|
||||
request.Context(), clientID,
|
||||
@@ -1868,7 +1863,8 @@ func (hdlr *Handlers) deliverSetTopicNumerics(
|
||||
}
|
||||
|
||||
// dispatchInfoCommand handles informational IRC commands
|
||||
// that produce server-side numerics (MOTD, PING).
|
||||
// that produce server-side numerics (MOTD, PING,
|
||||
// VERSION, ADMIN, INFO, TIME).
|
||||
func (hdlr *Handlers) dispatchInfoCommand(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
@@ -1894,6 +1890,34 @@ func (hdlr *Handlers) dispatchInfoCommand(
|
||||
},
|
||||
http.StatusOK)
|
||||
|
||||
return
|
||||
case irc.CmdVersion:
|
||||
hdlr.handleVersion(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
)
|
||||
|
||||
return
|
||||
case irc.CmdAdmin:
|
||||
hdlr.handleAdmin(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
)
|
||||
|
||||
return
|
||||
case irc.CmdInfo:
|
||||
hdlr.handleInfo(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
)
|
||||
|
||||
return
|
||||
case irc.CmdTime:
|
||||
hdlr.handleTime(
|
||||
writer, request,
|
||||
sessionID, clientID, nick,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1951,15 +1975,11 @@ func (hdlr *Handlers) handleMode(
|
||||
|
||||
channel := target
|
||||
if !strings.HasPrefix(channel, "#") {
|
||||
// User mode query — return empty modes.
|
||||
hdlr.enqueueNumeric(
|
||||
request.Context(), clientID,
|
||||
irc.RplUmodeIs, nick, nil, "+",
|
||||
hdlr.handleUserMode(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, target,
|
||||
bodyLines,
|
||||
)
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{statusKey: "ok"},
|
||||
http.StatusOK)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -293,6 +293,7 @@ func newTestHandlers(
|
||||
Config: cfg,
|
||||
Database: database,
|
||||
Broker: brk,
|
||||
Globals: globs,
|
||||
})
|
||||
|
||||
hdlr, err := handlers.New(lifecycle, handlers.Params{ //nolint:exhaustruct
|
||||
|
||||
@@ -0,0 +1,576 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sneak.berlin/go/neoirc/internal/db"
|
||||
"sneak.berlin/go/neoirc/internal/service"
|
||||
"sneak.berlin/go/neoirc/pkg/irc"
|
||||
)
|
||||
|
||||
// maxUserhostNicks is the maximum number of nicks allowed
|
||||
// in a single USERHOST query (RFC 2812).
|
||||
const maxUserhostNicks = 5
|
||||
|
||||
// dispatchBodyOnlyCommand routes commands that take
|
||||
// (writer, request, sessionID, clientID, nick, bodyLines).
|
||||
func (hdlr *Handlers) dispatchBodyOnlyCommand(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick, command string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
switch command {
|
||||
case irc.CmdAway:
|
||||
hdlr.handleAway(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdNick:
|
||||
hdlr.handleNick(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdPass:
|
||||
hdlr.handlePass(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdInvite:
|
||||
hdlr.handleInvite(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// dispatchOperCommand routes oper-related commands (OPER,
|
||||
// KILL, WALLOPS) to their handlers.
|
||||
func (hdlr *Handlers) dispatchOperCommand(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick, command string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
switch command {
|
||||
case irc.CmdOper:
|
||||
hdlr.handleOper(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdKill:
|
||||
hdlr.handleKill(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
case irc.CmdWallops:
|
||||
hdlr.handleWallops(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, bodyLines,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// handleUserhost handles the USERHOST command.
|
||||
// Returns user@host info for up to 5 nicks.
|
||||
func (hdlr *Handlers) handleUserhost(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
lines := bodyLines()
|
||||
if len(lines) == 0 {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNeedMoreParams, nick,
|
||||
[]string{irc.CmdUserhost},
|
||||
"Not enough parameters",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Limit to 5 nicks per RFC 2812.
|
||||
nicks := lines
|
||||
if len(nicks) > maxUserhostNicks {
|
||||
nicks = nicks[:maxUserhostNicks]
|
||||
}
|
||||
|
||||
infos, err := hdlr.params.Database.GetUserhostInfo(
|
||||
ctx, nicks,
|
||||
)
|
||||
if err != nil {
|
||||
hdlr.log.Error(
|
||||
"userhost query failed", "error", err,
|
||||
)
|
||||
hdlr.respondError(
|
||||
writer, request,
|
||||
"internal error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
replyStr := hdlr.buildUserhostReply(infos)
|
||||
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplUserHost, nick, nil,
|
||||
replyStr,
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// buildUserhostReply builds the RPL_USERHOST reply
|
||||
// string per RFC 2812.
|
||||
func (hdlr *Handlers) buildUserhostReply(
|
||||
infos []db.UserhostInfo,
|
||||
) string {
|
||||
replies := make([]string, 0, len(infos))
|
||||
|
||||
for idx := range infos {
|
||||
info := &infos[idx]
|
||||
|
||||
username := info.Username
|
||||
if username == "" {
|
||||
username = info.Nick
|
||||
}
|
||||
|
||||
hostname := info.Hostname
|
||||
if hostname == "" {
|
||||
hostname = hdlr.serverName()
|
||||
}
|
||||
|
||||
operStar := ""
|
||||
if info.IsOper {
|
||||
operStar = "*"
|
||||
}
|
||||
|
||||
awayPrefix := "+"
|
||||
if info.AwayMessage != "" {
|
||||
awayPrefix = "-"
|
||||
}
|
||||
|
||||
replies = append(replies,
|
||||
info.Nick+operStar+"="+
|
||||
awayPrefix+username+"@"+hostname,
|
||||
)
|
||||
}
|
||||
|
||||
return strings.Join(replies, " ")
|
||||
}
|
||||
|
||||
// handleVersion handles the VERSION command.
|
||||
// Returns the server version string.
|
||||
func (hdlr *Handlers) handleVersion(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
srvName := hdlr.serverName()
|
||||
version := hdlr.svc.ServerVersion()
|
||||
|
||||
// 351 RPL_VERSION
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplVersion, nick,
|
||||
[]string{version + ".", srvName},
|
||||
"",
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleAdmin handles the ADMIN command.
|
||||
// Returns server admin contact info.
|
||||
func (hdlr *Handlers) handleAdmin(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
srvName := hdlr.serverName()
|
||||
|
||||
// 256 RPL_ADMINME
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplAdminMe, nick,
|
||||
[]string{srvName},
|
||||
"Administrative info",
|
||||
)
|
||||
|
||||
// 257 RPL_ADMINLOC1
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplAdminLoc1, nick, nil,
|
||||
"neoirc server",
|
||||
)
|
||||
|
||||
// 258 RPL_ADMINLOC2
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplAdminLoc2, nick, nil,
|
||||
"IRC over HTTP",
|
||||
)
|
||||
|
||||
// 259 RPL_ADMINEMAIL
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplAdminEmail, nick, nil,
|
||||
"admin@"+srvName,
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleInfo handles the INFO command.
|
||||
// Returns server software information.
|
||||
func (hdlr *Handlers) handleInfo(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
for _, line := range hdlr.svc.InfoLines() {
|
||||
// 371 RPL_INFO
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplInfo, nick, nil,
|
||||
line,
|
||||
)
|
||||
}
|
||||
|
||||
// 374 RPL_ENDOFINFO
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplEndOfInfo, nick, nil,
|
||||
"End of /INFO list",
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleTime handles the TIME command.
|
||||
// Returns the server's local time in RFC format.
|
||||
func (hdlr *Handlers) handleTime(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
srvName := hdlr.serverName()
|
||||
|
||||
// 391 RPL_TIME
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplTime, nick,
|
||||
[]string{srvName},
|
||||
time.Now().Format(time.RFC1123),
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleKill handles the KILL command.
|
||||
// Forcibly disconnects a user (oper only).
|
||||
func (hdlr *Handlers) handleKill(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
// Check oper status.
|
||||
isOper, err := hdlr.params.Database.IsSessionOper(
|
||||
ctx, sessionID,
|
||||
)
|
||||
if err != nil || !isOper {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNoPrivileges, nick, nil,
|
||||
"Permission Denied- You're not an IRC operator",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
lines := bodyLines()
|
||||
|
||||
var targetNick string
|
||||
if len(lines) > 0 {
|
||||
targetNick = strings.TrimSpace(lines[0])
|
||||
}
|
||||
|
||||
if targetNick == "" {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNeedMoreParams, nick,
|
||||
[]string{irc.CmdKill},
|
||||
"Not enough parameters",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
reason := "KILLed"
|
||||
if len(lines) > 1 {
|
||||
reason = lines[1]
|
||||
}
|
||||
|
||||
targetSID, lookupErr := hdlr.params.Database.
|
||||
GetSessionByNick(ctx, targetNick)
|
||||
if lookupErr != nil {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNoSuchNick, nick,
|
||||
[]string{targetNick},
|
||||
"No such nick/channel",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Do not allow killing yourself.
|
||||
if targetSID == sessionID {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrCantKillServer, nick, nil,
|
||||
"You cannot KILL yourself",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
quitReason := "Killed (" + nick + " (" + reason + "))"
|
||||
|
||||
// KillSession broadcasts the QUIT, deletes the session
|
||||
// and disconnects the victim's wire connection if it
|
||||
// holds one.
|
||||
hdlr.svc.KillSession(
|
||||
ctx, targetSID, targetNick, quitReason,
|
||||
)
|
||||
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleWallops handles the WALLOPS command.
|
||||
// Broadcasts a message to all users with +w usermode
|
||||
// (oper only).
|
||||
func (hdlr *Handlers) handleWallops(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
// Check oper status.
|
||||
isOper, err := hdlr.params.Database.IsSessionOper(
|
||||
ctx, sessionID,
|
||||
)
|
||||
if err != nil || !isOper {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNoPrivileges, nick, nil,
|
||||
"Permission Denied- You're not an IRC operator",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
lines := bodyLines()
|
||||
if len(lines) == 0 {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrNeedMoreParams, nick,
|
||||
[]string{irc.CmdWallops},
|
||||
"Not enough parameters",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
message := strings.Join(lines, " ")
|
||||
|
||||
wallopsSIDs, err := hdlr.params.Database.
|
||||
GetWallopsSessionIDs(ctx)
|
||||
if err != nil {
|
||||
hdlr.log.Error(
|
||||
"get wallops sessions failed", "error", err,
|
||||
)
|
||||
hdlr.respondError(
|
||||
writer, request,
|
||||
"internal error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if len(wallopsSIDs) > 0 {
|
||||
body, mErr := json.Marshal([]string{message})
|
||||
if mErr != nil {
|
||||
hdlr.log.Error(
|
||||
"marshal wallops body", "error", mErr,
|
||||
)
|
||||
hdlr.respondError(
|
||||
writer, request,
|
||||
"internal error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdWallops, nick, "*",
|
||||
json.RawMessage(body), wallopsSIDs,
|
||||
)
|
||||
}
|
||||
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// handleUserMode handles user mode queries and changes
|
||||
// (e.g., MODE nick, MODE nick +w). Delegates to the
|
||||
// shared service.ApplyUserMode / service.QueryUserMode so
|
||||
// that mode string processing is identical for both the
|
||||
// HTTP API and IRC wire protocol.
|
||||
func (hdlr *Handlers) handleUserMode(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick, target string,
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
// Users can only query or change their own modes. The
|
||||
// check is above the query/change split so that both
|
||||
// forms are rejected, and uses EqualFold because IRC
|
||||
// nicks are case-insensitive — matching the wire path
|
||||
// in ircserver.handleUserMode.
|
||||
if target != "" && !strings.EqualFold(target, nick) {
|
||||
hdlr.respondIRCError(
|
||||
writer, request, clientID, sessionID,
|
||||
irc.ErrUsersDoNotMatch, nick, nil,
|
||||
"Can't change mode for other users",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
lines := bodyLines()
|
||||
|
||||
// Mode change requested.
|
||||
if len(lines) > 0 {
|
||||
hdlr.changeUserMode(
|
||||
writer, request,
|
||||
sessionID, clientID, nick, lines[0],
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Mode query — delegate to shared service.
|
||||
modeStr, err := hdlr.svc.QueryUserMode(ctx, sessionID)
|
||||
if err != nil {
|
||||
hdlr.log.Error(
|
||||
"query user mode failed", "error", err,
|
||||
)
|
||||
hdlr.respondError(
|
||||
writer, request,
|
||||
"internal error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplUmodeIs, nick, nil,
|
||||
modeStr,
|
||||
)
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
// changeUserMode applies a mode string to the caller's own
|
||||
// session. The caller has already verified that the target
|
||||
// nick is the caller's own.
|
||||
func (hdlr *Handlers) changeUserMode(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID, clientID int64,
|
||||
nick, modeStr string,
|
||||
) {
|
||||
ctx := request.Context()
|
||||
|
||||
newModes, err := hdlr.svc.ApplyUserMode(
|
||||
ctx, sessionID, modeStr,
|
||||
)
|
||||
if err != nil {
|
||||
var ircErr *service.IRCError
|
||||
if errors.As(err, &ircErr) {
|
||||
hdlr.respondIRCError(
|
||||
writer, request,
|
||||
clientID, sessionID,
|
||||
ircErr.Code, nick, ircErr.Params,
|
||||
ircErr.Message,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
hdlr.respondError(
|
||||
writer, request,
|
||||
"internal error",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
hdlr.enqueueNumeric(
|
||||
ctx, clientID, irc.RplUmodeIs, nick, nil,
|
||||
newModes,
|
||||
)
|
||||
|
||||
hdlr.broker.Notify(sessionID)
|
||||
hdlr.respondJSON(writer, request,
|
||||
map[string]string{"status": "ok"},
|
||||
http.StatusOK)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user