2022-01-24 02:26:24 +02:00
|
|
|
// gorc project
|
2022-01-24 04:24:58 +02:00
|
|
|
// Copyright (C) 2022 IllusionMan1212
|
2022-01-24 02:26:24 +02:00
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License along
|
|
|
|
|
// with this program; if not, see https://www.gnu.org/licenses.
|
|
|
|
|
|
|
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
2022-02-19 19:55:01 +02:00
|
|
|
"strconv"
|
2022-01-24 02:26:24 +02:00
|
|
|
"strings"
|
2022-02-19 19:55:01 +02:00
|
|
|
"time"
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2022-01-24 04:23:02 +02:00
|
|
|
"github.com/illusionman1212/gorc/cmds"
|
2022-01-24 02:26:24 +02:00
|
|
|
"github.com/illusionman1212/gorc/irc"
|
|
|
|
|
"github.com/illusionman1212/gorc/irc/commands"
|
|
|
|
|
"github.com/illusionman1212/gorc/irc/parser"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func ReadLoop(client *irc.Client) {
|
|
|
|
|
// 512 bytes as a base + 8192 additional bytes for tags
|
2025-08-15 21:10:52 +02:00
|
|
|
// as specified here: https://modern.ircdocs.horse/#message-format
|
2025-08-11 22:51:50 +02:00
|
|
|
r := bufio.NewReaderSize(client.TCPConn, 8192+512)
|
2022-01-24 02:26:24 +02:00
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
msg, err := r.ReadString('\n')
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err != io.EOF {
|
|
|
|
|
log.Println(err)
|
|
|
|
|
}
|
2025-08-11 22:51:50 +02:00
|
|
|
client.TCPConn.Close()
|
2022-01-24 02:26:24 +02:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg = strings.Replace(msg, "\r\n", "", 1)
|
|
|
|
|
if ircMessage, valid := parser.ParseIRCMessage(msg); valid {
|
|
|
|
|
HandleCommand(ircMessage, client)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handlePing(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
token := msg.Parameters[0]
|
|
|
|
|
client.SendCommand(commands.PONG, token)
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handlePrivMsg(msg irc.Message, client *irc.Client) {
|
2025-08-15 21:34:04 +02:00
|
|
|
source := strings.ToLower(strings.SplitN(msg.Source, "!", 2)[0])
|
|
|
|
|
targets := strings.Split(msg.Parameters[0], ",")
|
2022-01-24 02:26:24 +02:00
|
|
|
msgContent := msg.Parameters[1]
|
2025-08-15 21:34:04 +02:00
|
|
|
privMsg := fmt.Sprintf("%s: %s", source, msgContent)
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:34:04 +02:00
|
|
|
targetsLoop:
|
|
|
|
|
for _, target := range targets {
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == target || current.Value.Name == source {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, privMsg, msgOpts)
|
2025-08-15 21:34:04 +02:00
|
|
|
continue targetsLoop
|
|
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
|
|
|
|
}
|
2025-08-15 21:34:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if target == client.Nickname {
|
|
|
|
|
newChannel := irc.Channel{
|
|
|
|
|
Name: source,
|
|
|
|
|
Users: map[string]irc.User{source: {}},
|
2025-08-13 13:05:15 +02:00
|
|
|
}
|
2025-08-15 21:34:04 +02:00
|
|
|
|
|
|
|
|
newChannel.AppendMsg(msg.Timestamp, privMsg, msgOpts)
|
2025-08-18 21:10:04 +02:00
|
|
|
client.AppendChannel(newChannel)
|
2025-08-13 13:05:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleNotice(msg irc.Message, client *irc.Client) {
|
|
|
|
|
source := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
targets := strings.Split(msg.Parameters[0], ",")
|
|
|
|
|
msgContent := msg.Parameters[1]
|
|
|
|
|
notice := fmt.Sprintf("%s: %s", source, msgContent)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, target := range targets {
|
|
|
|
|
if target == "*" || target == client.Nickname {
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, notice, msgOpts)
|
2025-08-13 13:05:15 +02:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == targets[0] {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, notice, msgOpts)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-13 13:05:15 +02:00
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-13 13:05:15 +02:00
|
|
|
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleJoin(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
nick := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
channel := msg.Parameters[0]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
joinMsg := fmt.Sprintf("%s has joined", nick)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
2022-01-24 08:18:30 +02:00
|
|
|
|
|
|
|
|
if nick == client.Nickname {
|
2025-08-18 21:10:04 +02:00
|
|
|
newChannel := irc.Channel{
|
2022-01-24 08:18:30 +02:00
|
|
|
Name: channel,
|
|
|
|
|
Users: make(map[string]irc.User),
|
2025-08-18 21:10:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client.ActiveChannel = client.AppendChannel(newChannel)
|
|
|
|
|
client.ActiveChannel.Value.AppendMsg(msg.Timestamp, joinMsg, msgOpts)
|
|
|
|
|
|
|
|
|
|
if _, exists := client.ActiveChannel.Value.Users[nick]; !exists {
|
|
|
|
|
client.ActiveChannel.Value.Users[nick] = irc.User{}
|
2022-01-24 08:18:30 +02:00
|
|
|
}
|
|
|
|
|
client.Tea.Send(cmds.UpdateTabBar())
|
|
|
|
|
} else {
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, joinMsg, msgOpts)
|
|
|
|
|
if _, exists := current.Value.Users[nick]; !exists {
|
|
|
|
|
current.Value.Users[nick] = irc.User{}
|
2022-01-24 08:18:30 +02:00
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
if channel == client.ActiveChannel.Value.Name {
|
2022-01-24 04:23:02 +02:00
|
|
|
client.Tea.Send(cmds.SwitchChannels())
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:35:27 +02:00
|
|
|
// Sent from server to client to acknowledge a nickname change, or to inform of a nickname change of another user.
|
|
|
|
|
func handleNick(msg irc.Message, client *irc.Client) {
|
|
|
|
|
oldNick := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
newNick := msg.Parameters[0]
|
|
|
|
|
|
|
|
|
|
// TODO: the actual case-sensitivity is determined by the CASEMAPPING feature
|
|
|
|
|
isMe := strings.EqualFold(oldNick, client.Nickname)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message := ""
|
|
|
|
|
|
|
|
|
|
if isMe {
|
|
|
|
|
message = fmt.Sprintf("Your nickname was changed to %v", newNick)
|
|
|
|
|
} else {
|
|
|
|
|
message = fmt.Sprintf("%v changed their nickname to %v", oldNick, newNick)
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
2025-08-15 21:35:27 +02:00
|
|
|
// Rename this user in every channel we can find
|
2025-08-18 21:10:04 +02:00
|
|
|
if user, ok := current.Value.Users[oldNick]; ok {
|
|
|
|
|
delete(current.Value.Users, oldNick)
|
|
|
|
|
current.Value.Users[newNick] = user
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:35:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have a private channel open with this user, rename it as well.
|
2025-08-18 21:10:04 +02:00
|
|
|
if strings.EqualFold(current.Value.Name, oldNick) {
|
|
|
|
|
current.Value.Name = newNick
|
2025-08-15 21:35:27 +02:00
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
if current == client.ActiveChannel {
|
|
|
|
|
current.Value.Name = newNick
|
2025-08-15 21:35:27 +02:00
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
// if client.ActiveChannelIndex == i {
|
|
|
|
|
// client.ActiveChannel = newNick
|
|
|
|
|
// }
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-15 21:35:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if isMe {
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:35:27 +02:00
|
|
|
client.Nickname = newNick
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client.Tea.Send(cmds.UpdateNicks())
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 22:21:34 +02:00
|
|
|
func handleKick(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[0]
|
|
|
|
|
nicks := strings.Split(msg.Parameters[1], ",")
|
|
|
|
|
|
|
|
|
|
// Reason is optional
|
|
|
|
|
reason := ""
|
|
|
|
|
|
|
|
|
|
if len(msg.Parameters) > 2 {
|
|
|
|
|
reason = msg.Parameters[2]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, nick := range nicks {
|
|
|
|
|
kicker := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
message := fmt.Sprintf("%v kicked %v from %v (%v)", kicker, nick, channel, reason)
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
2025-08-15 22:21:34 +02:00
|
|
|
if nick == client.Nickname {
|
2025-08-18 21:10:04 +02:00
|
|
|
if current == client.ActiveChannel {
|
|
|
|
|
client.ActiveChannel = current.Prev
|
2025-08-15 22:21:34 +02:00
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
client.RemoveChannel(current)
|
2025-08-15 22:21:34 +02:00
|
|
|
|
|
|
|
|
message = fmt.Sprintf("You were kicked by %v from %v (%v)", kicker, channel, reason)
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 22:21:34 +02:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
delete(current.Value.Users, nick)
|
2025-08-15 22:21:34 +02:00
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-15 22:21:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client.Tea.Send(cmds.SwitchChannels())
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleQuit(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
nick := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
reason := msg.Parameters[0]
|
2022-02-19 16:24:39 +02:00
|
|
|
quitMsg := fmt.Sprintf("%s has quit (%s)", nick, reason)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
// skip the server "channel"
|
|
|
|
|
current := client.RootChannel.Next
|
|
|
|
|
for {
|
|
|
|
|
// if i == 0 {
|
|
|
|
|
// continue
|
|
|
|
|
// }
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, quitMsg, msgOpts)
|
|
|
|
|
delete(current.Value.Users, nick)
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-24 04:23:02 +02:00
|
|
|
client.Tea.Send(cmds.SwitchChannels())
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handlePart(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
nick := strings.SplitN(msg.Source, "!", 2)[0]
|
|
|
|
|
channel := msg.Parameters[0]
|
|
|
|
|
reason := ""
|
|
|
|
|
if len(msg.Parameters) > 1 {
|
|
|
|
|
reason = msg.Parameters[1]
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
partMsg := fmt.Sprintf("%s has left %s (%s)", nick, channel, reason)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
2022-01-24 08:52:06 +02:00
|
|
|
if nick == client.Nickname {
|
2025-08-18 21:10:04 +02:00
|
|
|
if current == client.ActiveChannel {
|
|
|
|
|
client.ActiveChannel = current.Prev
|
2022-01-24 08:52:06 +02:00
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
client.RemoveChannel(current)
|
2022-01-24 08:52:06 +02:00
|
|
|
} else {
|
2025-08-18 21:10:04 +02:00
|
|
|
current.Value.AppendMsg(msg.Timestamp, partMsg, msgOpts)
|
|
|
|
|
delete(current.Value.Users, nick)
|
2022-01-24 08:52:06 +02:00
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-24 04:23:02 +02:00
|
|
|
client.Tea.Send(cmds.SwitchChannels())
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleTopic(msg irc.Message, client *irc.Client) {
|
2025-08-13 11:31:16 +02:00
|
|
|
channel := msg.Parameters[0]
|
|
|
|
|
topic := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.Topic = topic
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, fmt.Sprintf("Topic changed: %v", topic), msgOpts)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-13 11:31:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleCAP(msg irc.Message, client *irc.Client) {
|
2023-02-22 08:52:26 +02:00
|
|
|
switch msg.Parameters[1] {
|
|
|
|
|
case "LIST":
|
|
|
|
|
fallthrough
|
|
|
|
|
case "NEW":
|
|
|
|
|
fallthrough
|
|
|
|
|
case "LS":
|
|
|
|
|
caps := strings.Split(msg.Parameters[2], " ")
|
|
|
|
|
recognizedCaps := make([]irc.Capabilities, 0)
|
|
|
|
|
capabilities := make(irc.Capabilities, 0)
|
|
|
|
|
length := 0
|
|
|
|
|
|
|
|
|
|
for _, capability := range caps {
|
|
|
|
|
// NOTE: not sure if I should store the cap value the server advertises or use my own
|
|
|
|
|
parts := strings.Split(capability, "=")
|
|
|
|
|
key := parts[0]
|
|
|
|
|
value := ""
|
|
|
|
|
if len(parts) > 1 {
|
|
|
|
|
value = parts[1]
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:10:52 +02:00
|
|
|
if capEnabled, ok := commands.Capabilities[key]; ok {
|
|
|
|
|
if capEnabled {
|
|
|
|
|
// When the final parameter approaches 510 bytes,
|
|
|
|
|
// we send multiple REQ commands
|
|
|
|
|
// (https://ircv3.net/specs/extensions/capability-negotiation.html#the-cap-req-subcommand)
|
|
|
|
|
if length+len(capability) >= 500 {
|
|
|
|
|
recognizedCaps = append(recognizedCaps, capabilities)
|
|
|
|
|
capabilities = make(irc.Capabilities, 0)
|
|
|
|
|
length = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
capabilities[key] = value
|
|
|
|
|
length += len(capability)
|
|
|
|
|
} else {
|
|
|
|
|
log.Println("Unsupported capability:", capability)
|
2023-02-22 08:52:26 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log.Println("Unknown capability:", capability)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
recognizedCaps = append(recognizedCaps, capabilities)
|
|
|
|
|
|
|
|
|
|
for _, capsList := range recognizedCaps {
|
|
|
|
|
list := make([]string, 0)
|
|
|
|
|
for key, value := range capsList {
|
|
|
|
|
if len(value) > 0 {
|
|
|
|
|
list = append(list, key+"="+value)
|
|
|
|
|
} else {
|
|
|
|
|
list = append(list, key)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
client.SendCommand(commands.CAP, "REQ", strings.Join(list, " "))
|
|
|
|
|
}
|
|
|
|
|
client.SendCommand(commands.CAP, "END")
|
|
|
|
|
case "ACK":
|
2025-08-15 21:10:52 +02:00
|
|
|
if msg.Parameters[2] == "" {
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-02-22 08:52:26 +02:00
|
|
|
caps := strings.Split(msg.Parameters[2], " ")
|
|
|
|
|
for _, capability := range caps {
|
|
|
|
|
if capability[0] == '-' {
|
|
|
|
|
delete(client.EnabledCapabilities, capability[1:])
|
|
|
|
|
} else {
|
|
|
|
|
parts := strings.Split(capability, "=")
|
|
|
|
|
key := parts[0]
|
|
|
|
|
value := ""
|
|
|
|
|
if len(parts) > 1 {
|
|
|
|
|
value = parts[1]
|
|
|
|
|
}
|
|
|
|
|
client.EnabledCapabilities[key] = value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case "NAK":
|
|
|
|
|
caps := strings.Split(msg.Parameters[2], " ")
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, "Unrecognized capabilities: "+strings.Join(caps, " "), msgOpts)
|
2023-02-22 08:52:26 +02:00
|
|
|
case "DEL":
|
|
|
|
|
caps := strings.Split(msg.Parameters[2], " ")
|
|
|
|
|
for _, capability := range caps {
|
|
|
|
|
delete(client.EnabledCapabilities, capability)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWELCOME(msg irc.Message, client *irc.Client) {
|
2022-02-19 16:24:39 +02:00
|
|
|
nick := msg.Parameters[0]
|
2022-01-24 02:26:24 +02:00
|
|
|
welcomeMsg := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 22:18:55 +02:00
|
|
|
// set server-registered nickname because the server MAY return a different nickname than
|
|
|
|
|
// the one the user chose because of length restrictions or otherwise.
|
2022-02-19 16:24:39 +02:00
|
|
|
client.Nickname = nick
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, welcomeMsg, msgOpts)
|
2025-08-15 22:18:55 +02:00
|
|
|
|
|
|
|
|
// Only join the user-requested channel AFTER registration is complete.
|
|
|
|
|
if client.InitialChannel != "" {
|
|
|
|
|
client.SendCommand(commands.JOIN, client.InitialChannel)
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleYOURHOST(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
host := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, host, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleCREATED(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
created := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, created, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleMYINFO(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
info := strings.Join(msg.Parameters[1:], " ")
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, info, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:10:52 +02:00
|
|
|
func handleISUPPORT(msg irc.Message, client *irc.Client) {
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, token := range msg.Parameters[1 : len(msg.Parameters)-1] {
|
|
|
|
|
splits := strings.Split(token, "=")
|
|
|
|
|
key := splits[0]
|
|
|
|
|
value := ""
|
|
|
|
|
if len(splits) > 1 {
|
|
|
|
|
value = splits[1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if supported, known := commands.Features[key]; known {
|
|
|
|
|
if supported {
|
|
|
|
|
client.EnabledFeatures[key] = value
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("Unsupported feature: \"%v\" with value: \"%v\"\n", key, value)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("Unknown feature: \"%v\" with value: \"%v\"\n", key, value)
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, token, msgOpts)
|
2025-08-15 21:10:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLUSERCLIENT(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLUSEROP(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
message := strings.Join(msg.Parameters[1:], " ")
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLUSERUNKNOWN(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
message := strings.Join(msg.Parameters[1:], " ")
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLUSERCHANNELS(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
message := strings.Join(msg.Parameters[1:], " ")
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLUSERME(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleLOCALUSERS(msg irc.Message, client *irc.Client) {
|
2025-08-15 21:18:40 +02:00
|
|
|
message := ""
|
|
|
|
|
|
|
|
|
|
if len(msg.Parameters) > 2 {
|
|
|
|
|
message = msg.Parameters[3]
|
|
|
|
|
} else {
|
|
|
|
|
message = msg.Parameters[1]
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleGLOBALUSERS(msg irc.Message, client *irc.Client) {
|
2025-08-15 21:18:40 +02:00
|
|
|
message := ""
|
|
|
|
|
|
|
|
|
|
if len(msg.Parameters) > 2 {
|
|
|
|
|
message = msg.Parameters[3]
|
|
|
|
|
} else {
|
|
|
|
|
message = msg.Parameters[1]
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
func handleAWAY(msg irc.Message, client *irc.Client) {
|
|
|
|
|
nick := strings.SplitN(msg.Parameters[1], "!", 2)[0]
|
|
|
|
|
reason := msg.Parameters[2]
|
|
|
|
|
awayMsg := fmt.Sprintf("%s is away (%s)", nick, reason)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, awayMsg, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleUNAWAY(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleNOWAWAY(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISUSER(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
nick := msg.Parameters[1]
|
|
|
|
|
user := msg.Parameters[2]
|
|
|
|
|
host := msg.Parameters[3]
|
|
|
|
|
realName := msg.Parameters[5]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message := fmt.Sprintf(
|
|
|
|
|
"Nick: %s | User: %s | Host: %s | Real name: %s",
|
|
|
|
|
nick,
|
|
|
|
|
user,
|
|
|
|
|
host,
|
|
|
|
|
realName,
|
|
|
|
|
)
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, "WHOIS Information", msgOpts)
|
|
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISSERVER(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
server := msg.Parameters[2]
|
|
|
|
|
serverInfo := msg.Parameters[3]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message := fmt.Sprintf(
|
|
|
|
|
"server: %s [%s]",
|
|
|
|
|
server,
|
|
|
|
|
serverInfo,
|
|
|
|
|
)
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISIDLE(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
idleSeconds := msg.Parameters[2]
|
|
|
|
|
connectedTimestamp, err := strconv.ParseInt(msg.Parameters[3], 10, 64)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
// TODO: return this err and handle it in the parent
|
|
|
|
|
log.Println(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
since := time.Unix(connectedTimestamp, 0)
|
|
|
|
|
|
|
|
|
|
message := fmt.Sprintf(
|
|
|
|
|
"idle for: %s seconds, connected since: %s",
|
|
|
|
|
idleSeconds,
|
|
|
|
|
since.Format(time.ANSIC),
|
|
|
|
|
)
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleENDOFWHOIS(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISCHANNELS(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
chans := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message := fmt.Sprintf("channels: %s", chans)
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleNOTOPIC(msg irc.Message, client *irc.Client) {
|
2025-08-13 11:31:16 +02:00
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
msgStr := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, msgStr, msgOpts)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-13 11:31:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleTOPIC(msg irc.Message, client *irc.Client) {
|
2025-08-13 11:31:16 +02:00
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
topic := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.Topic = topic
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, fmt.Sprintf("TOPIC: %v", topic), msgOpts)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-13 11:31:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
func handleVERSION(msg irc.Message, client *irc.Client) {
|
|
|
|
|
version := msg.Parameters[1]
|
|
|
|
|
server := msg.Parameters[2]
|
|
|
|
|
versionMsg := fmt.Sprintf("Server: %v | Version: %v", server, version)
|
|
|
|
|
|
|
|
|
|
if len(msg.Parameters) > 3 && msg.Parameters[3] != "" {
|
|
|
|
|
comments := msg.Parameters[3]
|
|
|
|
|
versionMsg = fmt.Sprintf("Server: %v | Version: %v | (%s)", server, version, comments)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, versionMsg, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleNAMREPLY(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
// TODO: do i need these
|
|
|
|
|
// client := msg.Parameters[0]
|
|
|
|
|
// chanSymbol := msg.Parameters[1]
|
|
|
|
|
channel := msg.Parameters[2]
|
|
|
|
|
nicks := strings.Split(msg.Parameters[3], " ")
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
2022-01-24 02:26:24 +02:00
|
|
|
for _, nick := range nicks {
|
|
|
|
|
prefix := ""
|
|
|
|
|
_nick := nick
|
|
|
|
|
|
|
|
|
|
if commands.UserPrefixes[string(nick[0])] {
|
|
|
|
|
prefix = string(nick[0])
|
|
|
|
|
_nick = nick[1:]
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current.Value.Users[_nick] = irc.User{
|
2022-01-24 02:26:24 +02:00
|
|
|
Prefix: prefix,
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
if channel == client.ActiveChannel.Value.Name {
|
2022-01-24 04:23:02 +02:00
|
|
|
client.Tea.Send(cmds.SwitchChannels())
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
func handleINFO(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleENDOFINFO(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleMOTDStart(msg irc.Message, client *irc.Client) {
|
2022-02-19 16:24:39 +02:00
|
|
|
message := strings.Join(msg.Parameters[1:], " ")
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleMOTD(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
messageLine := msg.Parameters[1]
|
|
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, messageLine, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISHOST(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
message := msg.Parameters[1] + " " + msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleWHOISMODES(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
message := msg.Parameters[1] + " " + msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-15 22:17:13 +02:00
|
|
|
func handleNOSUCHNICK(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1] + ": " + msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 22:17:13 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleNOSUCHSERVER(msg irc.Message, client *irc.Client) {
|
2025-08-15 22:17:13 +02:00
|
|
|
message := msg.Parameters[1] + ": " + msg.Parameters[2]
|
2022-02-19 19:55:01 +02:00
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
2025-08-15 22:17:13 +02:00
|
|
|
AsErrorMsg: true,
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
func handleNOSUCHCHANNEL(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
message = fmt.Sprintf("%v: %v", channel, message)
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleCANNOTSENDTOCHAN(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
return
|
|
|
|
|
}
|
2025-08-18 21:10:04 +02:00
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
|
|
|
|
}
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message = fmt.Sprintf("%v: %v", channel, message)
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleTOOMANYCHANNELS(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, fmt.Sprintf("%v: %v", channel, message), msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleUNKNOWNCOMMAND(msg irc.Message, client *irc.Client) {
|
2023-02-22 08:52:26 +02:00
|
|
|
message := msg.Parameters[1] + " " + msg.Parameters[2]
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleNOMOTD(msg irc.Message, client *irc.Client) {
|
|
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
2023-02-22 08:52:26 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2023-02-22 08:52:26 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleNONICKNAMEGIVEN(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleNEEDMOREPARAMS(msg irc.Message, client *irc.Client) {
|
2025-08-15 21:18:40 +02:00
|
|
|
message := msg.Parameters[1] + ": " + msg.Parameters[2]
|
2022-02-19 19:55:01 +02:00
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
2025-08-15 21:18:40 +02:00
|
|
|
AsErrorMsg: true,
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func handleALREADYREGISTERED(msg irc.Message, client *irc.Client) {
|
2022-02-19 19:55:01 +02:00
|
|
|
message := msg.Parameters[1]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsServerMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
2022-02-19 19:55:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-15 21:21:21 +02:00
|
|
|
func handleBADCHANMASK(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, fmt.Sprintf("%v: %v", channel, message), msgOpts)
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func handleCHANOPRIVSNEEDED(msg irc.Message, client *irc.Client) {
|
|
|
|
|
channel := msg.Parameters[1]
|
|
|
|
|
message := msg.Parameters[2]
|
|
|
|
|
|
|
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
AsErrorMsg: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
current := client.RootChannel
|
|
|
|
|
for {
|
|
|
|
|
if current.Value.Name == channel {
|
|
|
|
|
current.Value.AppendMsg(msg.Timestamp, message, msgOpts)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.Next
|
|
|
|
|
if current == client.RootChannel {
|
|
|
|
|
break
|
2025-08-15 21:21:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 13:05:15 +02:00
|
|
|
func HandleCommand(msg irc.Message, client *irc.Client) {
|
2022-01-24 02:26:24 +02:00
|
|
|
// TODO: handle different commands
|
|
|
|
|
switch msg.Command {
|
|
|
|
|
case commands.PING:
|
|
|
|
|
handlePing(msg, client)
|
|
|
|
|
case commands.PRIVMSG:
|
|
|
|
|
handlePrivMsg(msg, client)
|
2025-08-13 13:05:15 +02:00
|
|
|
case commands.NOTICE:
|
|
|
|
|
handleNotice(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.JOIN:
|
|
|
|
|
handleJoin(msg, client)
|
2025-08-15 21:35:27 +02:00
|
|
|
case commands.NICK:
|
|
|
|
|
handleNick(msg, client)
|
2025-08-15 22:21:34 +02:00
|
|
|
case commands.KICK:
|
|
|
|
|
handleKick(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.QUIT:
|
|
|
|
|
handleQuit(msg, client)
|
|
|
|
|
case commands.PART:
|
|
|
|
|
handlePart(msg, client)
|
2025-08-13 11:31:16 +02:00
|
|
|
case commands.TOPIC:
|
|
|
|
|
handleTopic(msg, client)
|
2023-02-22 08:52:26 +02:00
|
|
|
case commands.CAP:
|
|
|
|
|
handleCAP(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.RPL_WELCOME:
|
|
|
|
|
handleWELCOME(msg, client)
|
|
|
|
|
case commands.RPL_YOURHOST:
|
|
|
|
|
handleYOURHOST(msg, client)
|
|
|
|
|
case commands.RPL_CREATED:
|
|
|
|
|
handleCREATED(msg, client)
|
|
|
|
|
case commands.RPL_MYINFO:
|
|
|
|
|
handleMYINFO(msg, client)
|
2025-08-15 21:10:52 +02:00
|
|
|
case commands.RPL_ISUPPORT:
|
|
|
|
|
handleISUPPORT(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.RPL_LUSERCLIENT:
|
|
|
|
|
handleLUSERCLIENT(msg, client)
|
|
|
|
|
case commands.RPL_LUSEROP:
|
|
|
|
|
handleLUSEROP(msg, client)
|
|
|
|
|
case commands.RPL_LUSERUNKNOWN:
|
|
|
|
|
handleLUSERUNKNOWN(msg, client)
|
|
|
|
|
case commands.RPL_LUSERCHANNELS:
|
|
|
|
|
handleLUSERCHANNELS(msg, client)
|
|
|
|
|
case commands.RPL_LUSERME:
|
|
|
|
|
handleLUSERME(msg, client)
|
|
|
|
|
case commands.RPL_LOCALUSERS:
|
|
|
|
|
handleLOCALUSERS(msg, client)
|
|
|
|
|
case commands.RPL_GLOBALUSERS:
|
|
|
|
|
handleGLOBALUSERS(msg, client)
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.RPL_AWAY:
|
|
|
|
|
handleAWAY(msg, client)
|
|
|
|
|
case commands.RPL_UNAWAY:
|
|
|
|
|
handleUNAWAY(msg, client)
|
|
|
|
|
case commands.RPL_NOWAWAY:
|
|
|
|
|
handleNOWAWAY(msg, client)
|
2022-02-19 19:55:01 +02:00
|
|
|
case commands.RPL_WHOISUSER:
|
|
|
|
|
handleWHOISUSER(msg, client)
|
|
|
|
|
case commands.RPL_WHOISSERVER:
|
|
|
|
|
handleWHOISSERVER(msg, client)
|
|
|
|
|
case commands.RPL_WHOISIDLE:
|
|
|
|
|
handleWHOISIDLE(msg, client)
|
|
|
|
|
case commands.RPL_ENDOFWHOIS:
|
|
|
|
|
handleENDOFWHOIS(msg, client)
|
|
|
|
|
case commands.RPL_WHOISCHANNELS:
|
|
|
|
|
handleWHOISCHANNELS(msg, client)
|
2025-08-13 11:31:16 +02:00
|
|
|
case commands.RPL_NOTOPIC:
|
|
|
|
|
handleNOTOPIC(msg, client)
|
|
|
|
|
case commands.RPL_TOPIC:
|
|
|
|
|
handleTOPIC(msg, client)
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.RPL_VERSION:
|
|
|
|
|
handleVERSION(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.RPL_NAMREPLY:
|
|
|
|
|
handleNAMREPLY(msg, client)
|
|
|
|
|
case commands.RPL_ENDOFNAMES:
|
|
|
|
|
// TODO: toggle a flag on the channel to indicate
|
|
|
|
|
// it received all the names correctly.
|
|
|
|
|
|
|
|
|
|
// start a timeout and update said timeout on every RPL_NAMREPLY
|
|
|
|
|
// and log an error if timeout ends without receiving this command.
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.RPL_INFO:
|
|
|
|
|
handleINFO(msg, client)
|
|
|
|
|
case commands.RPL_ENDOFINFO:
|
|
|
|
|
handleENDOFINFO(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
case commands.RPL_MOTDSTART:
|
|
|
|
|
handleMOTDStart(msg, client)
|
|
|
|
|
case commands.RPL_MOTD:
|
|
|
|
|
handleMOTD(msg, client)
|
|
|
|
|
case commands.RPL_ENDOFMOTD:
|
|
|
|
|
// TODO: toggle a flag on the client/server to indicate
|
|
|
|
|
// it received all the MOTD correctly
|
|
|
|
|
|
|
|
|
|
// start a timeout and update said timeout on every RPL_MOTD
|
|
|
|
|
// and log an error if timeout ends without receiving this command.
|
2022-02-19 19:55:01 +02:00
|
|
|
case commands.RPL_WHOISHOST:
|
|
|
|
|
handleWHOISHOST(msg, client)
|
|
|
|
|
case commands.RPL_WHOISMODES:
|
|
|
|
|
handleWHOISMODES(msg, client)
|
2025-08-15 22:17:13 +02:00
|
|
|
case commands.ERR_NOSUCHNICK:
|
|
|
|
|
handleNOSUCHNICK(msg, client)
|
2022-02-19 19:55:01 +02:00
|
|
|
case commands.ERR_NOSUCHSERVER:
|
|
|
|
|
handleNOSUCHSERVER(msg, client)
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.ERR_NOSUCHCHANNEL:
|
|
|
|
|
handleNOSUCHCHANNEL(msg, client)
|
|
|
|
|
case commands.ERR_CANNOTSENDTOCHAN:
|
|
|
|
|
handleCANNOTSENDTOCHAN(msg, client)
|
|
|
|
|
case commands.ERR_TOOMANYCHANNELS:
|
|
|
|
|
handleTOOMANYCHANNELS(msg, client)
|
2023-02-22 08:52:26 +02:00
|
|
|
case commands.ERR_UNKNOWNCOMMAND:
|
|
|
|
|
handleUNKNOWNCOMMAND(msg, client)
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.ERR_NOMOTD:
|
|
|
|
|
handleNOMOTD(msg, client)
|
2022-02-19 19:55:01 +02:00
|
|
|
case commands.ERR_NONICKNAMEGIVEN:
|
|
|
|
|
handleNONICKNAMEGIVEN(msg, client)
|
|
|
|
|
case commands.ERR_NEEDMOREPARAMS:
|
|
|
|
|
handleNEEDMOREPARAMS(msg, client)
|
|
|
|
|
case commands.ERR_ALREADYREGISTERED:
|
|
|
|
|
handleALREADYREGISTERED(msg, client)
|
2025-08-15 21:21:21 +02:00
|
|
|
case commands.ERR_BADCHANMASK:
|
|
|
|
|
handleBADCHANMASK(msg, client)
|
|
|
|
|
case commands.ERR_CHANOPRIVSNEEDED:
|
|
|
|
|
handleCHANOPRIVSNEEDED(msg, client)
|
2022-01-24 02:26:24 +02:00
|
|
|
default:
|
2022-02-19 12:27:25 +02:00
|
|
|
fullMsg := fmt.Sprintf(
|
2022-02-19 16:24:39 +02:00
|
|
|
"%s %s %s %s",
|
2022-02-19 12:27:25 +02:00
|
|
|
msg.Tags,
|
|
|
|
|
msg.Source,
|
|
|
|
|
msg.Command,
|
|
|
|
|
strings.Join(msg.Parameters, " "),
|
|
|
|
|
)
|
2022-01-24 02:26:24 +02:00
|
|
|
|
2022-02-19 16:24:39 +02:00
|
|
|
msgOpts := irc.MsgFmtOpts{
|
|
|
|
|
WithTimestamp: true,
|
|
|
|
|
NotImpl: true,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-18 21:10:04 +02:00
|
|
|
client.RootChannel.Value.AppendMsg(msg.Timestamp, fullMsg, msgOpts)
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// send a receivedIRCmsg tea message so the ui can update
|
|
|
|
|
// we also use this tea message to scroll the viewport down
|
2022-01-24 04:23:02 +02:00
|
|
|
client.Tea.Send(cmds.ReceivedIRCMsg())
|
2022-01-24 02:26:24 +02:00
|
|
|
}
|