All checks were successful
check / check (push) Successful in 2m15s
Extract cmdLusers, cmdMode, cmdMotd, cmdNames, cmdNotice, cmdPing, cmdPong constants in internal/handlers/api.go. Add corresponding constants in cmd/neoirc-cli/main.go and cmd/neoirc-cli/api/client.go. Replace every bare IRC command string literal in switch cases and command dispatch code with the named constant. Zero bare command strings remain in any dispatch path.
922 lines
15 KiB
Go
922 lines
15 KiB
Go
// Package main is the entry point for the neoirc-cli client.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
api "git.eeqj.de/sneak/neoirc/cmd/neoirc-cli/api"
|
|
)
|
|
|
|
const (
|
|
splitParts = 2
|
|
pollTimeout = 15
|
|
pollRetry = 2 * time.Second
|
|
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.
|
|
type App struct {
|
|
ui *UI
|
|
client *api.Client
|
|
|
|
mu sync.Mutex
|
|
nick string
|
|
target string
|
|
connected bool
|
|
lastQID int64
|
|
stopPoll chan struct{}
|
|
}
|
|
|
|
func main() {
|
|
app := &App{ //nolint:exhaustruct
|
|
ui: NewUI(),
|
|
nick: "guest",
|
|
}
|
|
|
|
app.ui.OnInput(app.handleInput)
|
|
app.ui.SetStatus(app.nick, "", "disconnected")
|
|
|
|
app.ui.AddStatus(
|
|
"Welcome to neoirc-cli — an IRC-style client",
|
|
)
|
|
app.ui.AddStatus(
|
|
"Type [yellow]/connect <server-url>" +
|
|
"[white] to begin, " +
|
|
"or [yellow]/help[white] for commands",
|
|
)
|
|
|
|
err := app.ui.Run()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func (a *App) handleInput(text string) {
|
|
if strings.HasPrefix(text, "/") {
|
|
a.handleCommand(text)
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
target := a.target
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus(
|
|
"[red]Not connected. Use /connect <url>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
if target == "" {
|
|
a.ui.AddStatus(
|
|
"[red]No target. " +
|
|
"Use /join #channel or /query nick",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
|
Command: cmdPrivmsg,
|
|
To: target,
|
|
Body: []string{text},
|
|
})
|
|
if err != nil {
|
|
a.ui.AddStatus(
|
|
"[red]Send error: " + err.Error(),
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
timestamp := time.Now().Format(timeFormat)
|
|
|
|
a.mu.Lock()
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
a.ui.AddLine(target, fmt.Sprintf(
|
|
"[gray]%s [green]<%s>[white] %s",
|
|
timestamp, nick, text,
|
|
))
|
|
}
|
|
|
|
func (a *App) handleCommand(text string) {
|
|
parts := strings.SplitN(text, " ", splitParts)
|
|
cmd := strings.ToLower(parts[0])
|
|
|
|
args := ""
|
|
if len(parts) > 1 {
|
|
args = parts[1]
|
|
}
|
|
|
|
a.dispatchCommand(cmd, args)
|
|
}
|
|
|
|
func (a *App) dispatchCommand(cmd, args string) {
|
|
switch cmd {
|
|
case "/connect":
|
|
a.cmdConnect(args)
|
|
case "/nick":
|
|
a.cmdNick(args)
|
|
case "/join":
|
|
a.cmdJoin(args)
|
|
case "/part":
|
|
a.cmdPart(args)
|
|
case "/msg":
|
|
a.cmdMsg(args)
|
|
case "/query":
|
|
a.cmdQuery(args)
|
|
case "/topic":
|
|
a.cmdTopic(args)
|
|
case "/window", "/w":
|
|
a.cmdWindow(args)
|
|
case "/quit":
|
|
a.cmdQuit()
|
|
case "/help":
|
|
a.cmdHelp()
|
|
default:
|
|
a.dispatchInfoCommand(cmd, args)
|
|
}
|
|
}
|
|
|
|
func (a *App) dispatchInfoCommand(cmd, args string) {
|
|
switch cmd {
|
|
case "/names":
|
|
a.cmdNames()
|
|
case "/list":
|
|
a.cmdList()
|
|
case "/motd":
|
|
a.cmdMotd()
|
|
case "/who":
|
|
a.cmdWho(args)
|
|
case "/whois":
|
|
a.cmdWhois(args)
|
|
default:
|
|
a.ui.AddStatus(
|
|
"[red]Unknown command: " + cmd,
|
|
)
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdConnect(serverURL string) {
|
|
if serverURL == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /connect <server-url>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
serverURL = strings.TrimRight(serverURL, "/")
|
|
|
|
a.ui.AddStatus("Connecting to " + serverURL + "...")
|
|
|
|
a.mu.Lock()
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
client := api.NewClient(serverURL)
|
|
|
|
resp, err := client.CreateSession(nick)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Connection failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
a.client = client
|
|
a.nick = resp.Nick
|
|
a.connected = true
|
|
a.lastQID = 0
|
|
a.mu.Unlock()
|
|
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[green]Connected! Nick: %s, Session: %d",
|
|
resp.Nick, resp.ID,
|
|
))
|
|
a.ui.SetStatus(resp.Nick, "", "connected")
|
|
|
|
a.stopPoll = make(chan struct{})
|
|
|
|
go a.pollLoop()
|
|
}
|
|
|
|
func (a *App) cmdNick(nick string) {
|
|
if nick == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /nick <name>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.mu.Lock()
|
|
a.nick = nick
|
|
a.mu.Unlock()
|
|
|
|
a.ui.AddStatus(
|
|
"Nick set to " + nick +
|
|
" (will be used on connect)",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
|
Command: cmdNick,
|
|
Body: []string{nick},
|
|
})
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Nick change failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
a.nick = nick
|
|
target := a.target
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SetStatus(nick, target, "connected")
|
|
a.ui.AddStatus("Nick changed to " + nick)
|
|
}
|
|
|
|
func (a *App) cmdJoin(channel string) {
|
|
if channel == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /join #channel",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
if !strings.HasPrefix(channel, "#") {
|
|
channel = "#" + channel
|
|
}
|
|
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.JoinChannel(channel)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Join failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
a.target = channel
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SwitchToBuffer(channel)
|
|
a.ui.AddLine(channel,
|
|
"[yellow]*** Joined "+channel,
|
|
)
|
|
a.ui.SetStatus(nick, channel, "connected")
|
|
}
|
|
|
|
func (a *App) cmdPart(channel string) {
|
|
a.mu.Lock()
|
|
if channel == "" {
|
|
channel = a.target
|
|
}
|
|
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if channel == "" ||
|
|
!strings.HasPrefix(channel, "#") {
|
|
a.ui.AddStatus("[red]No channel to part")
|
|
|
|
return
|
|
}
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.PartChannel(channel)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Part failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.ui.AddLine(channel,
|
|
"[yellow]*** Left "+channel,
|
|
)
|
|
|
|
a.mu.Lock()
|
|
if a.target == channel {
|
|
a.target = ""
|
|
}
|
|
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SwitchBuffer(0)
|
|
a.ui.SetStatus(nick, "", "connected")
|
|
}
|
|
|
|
func (a *App) cmdMsg(args string) {
|
|
parts := strings.SplitN(args, " ", splitParts)
|
|
if len(parts) < splitParts {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /msg <nick> <text>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
target, text := parts[0], parts[1]
|
|
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
|
Command: cmdPrivmsg,
|
|
To: target,
|
|
Body: []string{text},
|
|
})
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Send failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
timestamp := time.Now().Format(timeFormat)
|
|
|
|
a.ui.AddLine(target, fmt.Sprintf(
|
|
"[gray]%s [green]<%s>[white] %s",
|
|
timestamp, nick, text,
|
|
))
|
|
}
|
|
|
|
func (a *App) cmdQuery(nick string) {
|
|
if nick == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /query <nick>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
a.mu.Lock()
|
|
a.target = nick
|
|
myNick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SwitchToBuffer(nick)
|
|
a.ui.SetStatus(myNick, nick, "connected")
|
|
}
|
|
|
|
func (a *App) cmdTopic(args string) {
|
|
a.mu.Lock()
|
|
target := a.target
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
if !strings.HasPrefix(target, "#") {
|
|
a.ui.AddStatus("[red]Not in a channel")
|
|
|
|
return
|
|
}
|
|
|
|
if args == "" {
|
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
|
Command: cmdTopic,
|
|
To: target,
|
|
})
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Topic query failed: %v", err,
|
|
))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(&api.Message{ //nolint:exhaustruct
|
|
Command: cmdTopic,
|
|
To: target,
|
|
Body: []string{args},
|
|
})
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Topic set failed: %v", err,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdNames() {
|
|
a.mu.Lock()
|
|
target := a.target
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
if !strings.HasPrefix(target, "#") {
|
|
a.ui.AddStatus("[red]Not in a channel")
|
|
|
|
return
|
|
}
|
|
|
|
members, err := a.client.GetMembers(target)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]Names failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.ui.AddLine(target, fmt.Sprintf(
|
|
"[cyan]*** Members of %s: %s",
|
|
target, strings.Join(members, " "),
|
|
))
|
|
}
|
|
|
|
func (a *App) cmdList() {
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
channels, err := a.client.ListChannels()
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]List failed: %v", err,
|
|
))
|
|
|
|
return
|
|
}
|
|
|
|
a.ui.AddStatus("[cyan]*** Channel list:")
|
|
|
|
for _, ch := range channels {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
" %s (%d members) %s",
|
|
ch.Name, ch.Members, ch.Topic,
|
|
))
|
|
}
|
|
|
|
a.ui.AddStatus("[cyan]*** End of channel list")
|
|
}
|
|
|
|
func (a *App) cmdMotd() {
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(
|
|
&api.Message{Command: cmdMotd}, //nolint:exhaustruct
|
|
)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]MOTD failed: %v", err,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdWho(args string) {
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
target := a.target
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
channel := args
|
|
if channel == "" {
|
|
channel = target
|
|
}
|
|
|
|
if channel == "" ||
|
|
!strings.HasPrefix(channel, "#") {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /who #channel",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(
|
|
&api.Message{ //nolint:exhaustruct
|
|
Command: cmdWho, To: channel,
|
|
},
|
|
)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]WHO failed: %v", err,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdWhois(args string) {
|
|
a.mu.Lock()
|
|
connected := a.connected
|
|
a.mu.Unlock()
|
|
|
|
if !connected {
|
|
a.ui.AddStatus("[red]Not connected")
|
|
|
|
return
|
|
}
|
|
|
|
if args == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /whois <nick>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
err := a.client.SendMessage(
|
|
&api.Message{ //nolint:exhaustruct
|
|
Command: cmdWhois, To: args,
|
|
},
|
|
)
|
|
if err != nil {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[red]WHOIS failed: %v", err,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdWindow(args string) {
|
|
if args == "" {
|
|
a.ui.AddStatus(
|
|
"[red]Usage: /window <number>",
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
var bufIndex int
|
|
|
|
_, _ = fmt.Sscanf(args, "%d", &bufIndex)
|
|
|
|
a.ui.SwitchBuffer(bufIndex)
|
|
|
|
a.mu.Lock()
|
|
nick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
if bufIndex >= 0 && bufIndex < a.ui.BufferCount() {
|
|
buf := a.ui.buffers[bufIndex]
|
|
if buf.Name != "(status)" {
|
|
a.mu.Lock()
|
|
a.target = buf.Name
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SetStatus(
|
|
nick, buf.Name, "connected",
|
|
)
|
|
} else {
|
|
a.ui.SetStatus(nick, "", "connected")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *App) cmdQuit() {
|
|
a.mu.Lock()
|
|
|
|
if a.connected && a.client != nil {
|
|
_ = a.client.SendMessage(
|
|
&api.Message{Command: cmdQuit}, //nolint:exhaustruct
|
|
)
|
|
}
|
|
|
|
if a.stopPoll != nil {
|
|
close(a.stopPoll)
|
|
}
|
|
|
|
a.mu.Unlock()
|
|
a.ui.Stop()
|
|
}
|
|
|
|
func (a *App) cmdHelp() {
|
|
help := []string{
|
|
"[cyan]*** neoirc-cli commands:",
|
|
" /connect <url> — Connect to server",
|
|
" /nick <name> — Change nickname",
|
|
" /join #channel — Join channel",
|
|
" /part [#chan] — Leave channel",
|
|
" /msg <nick> <text> — Send DM",
|
|
" /query <nick> — Open DM window",
|
|
" /topic [text] — View/set topic",
|
|
" /names — List channel members",
|
|
" /list — List channels",
|
|
" /who [#channel] — List users in channel",
|
|
" /whois <nick> — Show user info",
|
|
" /motd — Show message of the day",
|
|
" /window <n> — Switch buffer",
|
|
" /quit — Disconnect and exit",
|
|
" /help — This help",
|
|
" Plain text sends to current target.",
|
|
}
|
|
|
|
for _, line := range help {
|
|
a.ui.AddStatus(line)
|
|
}
|
|
}
|
|
|
|
// pollLoop long-polls for messages in the background.
|
|
func (a *App) pollLoop() {
|
|
for {
|
|
select {
|
|
case <-a.stopPoll:
|
|
return
|
|
default:
|
|
}
|
|
|
|
a.mu.Lock()
|
|
client := a.client
|
|
lastQID := a.lastQID
|
|
a.mu.Unlock()
|
|
|
|
if client == nil {
|
|
return
|
|
}
|
|
|
|
result, err := client.PollMessages(
|
|
lastQID, pollTimeout,
|
|
)
|
|
if err != nil {
|
|
time.Sleep(pollRetry)
|
|
|
|
continue
|
|
}
|
|
|
|
if result.LastID > 0 {
|
|
a.mu.Lock()
|
|
a.lastQID = result.LastID
|
|
a.mu.Unlock()
|
|
}
|
|
|
|
for i := range result.Messages {
|
|
a.handleServerMessage(&result.Messages[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *App) handleServerMessage(msg *api.Message) {
|
|
timestamp := a.formatTS(msg)
|
|
|
|
a.mu.Lock()
|
|
myNick := a.nick
|
|
a.mu.Unlock()
|
|
|
|
switch msg.Command {
|
|
case cmdPrivmsg:
|
|
a.handlePrivmsgEvent(msg, timestamp, myNick)
|
|
case cmdJoin:
|
|
a.handleJoinEvent(msg, timestamp)
|
|
case cmdPart:
|
|
a.handlePartEvent(msg, timestamp)
|
|
case cmdQuit:
|
|
a.handleQuitEvent(msg, timestamp)
|
|
case cmdNick:
|
|
a.handleNickEvent(msg, timestamp, myNick)
|
|
case cmdNotice:
|
|
a.handleNoticeEvent(msg, timestamp)
|
|
case cmdTopic:
|
|
a.handleTopicEvent(msg, timestamp)
|
|
default:
|
|
a.handleDefaultEvent(msg, timestamp)
|
|
}
|
|
}
|
|
|
|
func (a *App) formatTS(msg *api.Message) string {
|
|
if msg.TS != "" {
|
|
return msg.ParseTS().UTC().Format(timeFormat)
|
|
}
|
|
|
|
return time.Now().Format(timeFormat)
|
|
}
|
|
|
|
func (a *App) handlePrivmsgEvent(
|
|
msg *api.Message, timestamp, myNick string,
|
|
) {
|
|
lines := msg.BodyLines()
|
|
text := strings.Join(lines, " ")
|
|
|
|
if msg.From == myNick {
|
|
return
|
|
}
|
|
|
|
target := msg.To
|
|
if !strings.HasPrefix(target, "#") {
|
|
target = msg.From
|
|
}
|
|
|
|
a.ui.AddLine(target, fmt.Sprintf(
|
|
"[gray]%s [green]<%s>[white] %s",
|
|
timestamp, msg.From, text,
|
|
))
|
|
}
|
|
|
|
func (a *App) handleJoinEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
if msg.To == "" {
|
|
return
|
|
}
|
|
|
|
a.ui.AddLine(msg.To, fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s has joined %s",
|
|
timestamp, msg.From, msg.To,
|
|
))
|
|
}
|
|
|
|
func (a *App) handlePartEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
if msg.To == "" {
|
|
return
|
|
}
|
|
|
|
lines := msg.BodyLines()
|
|
reason := strings.Join(lines, " ")
|
|
|
|
if reason != "" {
|
|
a.ui.AddLine(msg.To, fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s has left %s (%s)",
|
|
timestamp, msg.From, msg.To, reason,
|
|
))
|
|
} else {
|
|
a.ui.AddLine(msg.To, fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s has left %s",
|
|
timestamp, msg.From, msg.To,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) handleQuitEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
lines := msg.BodyLines()
|
|
reason := strings.Join(lines, " ")
|
|
|
|
if reason != "" {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s has quit (%s)",
|
|
timestamp, msg.From, reason,
|
|
))
|
|
} else {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s has quit",
|
|
timestamp, msg.From,
|
|
))
|
|
}
|
|
}
|
|
|
|
func (a *App) handleNickEvent(
|
|
msg *api.Message, timestamp, myNick string,
|
|
) {
|
|
lines := msg.BodyLines()
|
|
|
|
newNick := ""
|
|
if len(lines) > 0 {
|
|
newNick = lines[0]
|
|
}
|
|
|
|
if msg.From == myNick && newNick != "" {
|
|
a.mu.Lock()
|
|
a.nick = newNick
|
|
|
|
target := a.target
|
|
a.mu.Unlock()
|
|
|
|
a.ui.SetStatus(newNick, target, "connected")
|
|
}
|
|
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[gray]%s [yellow]*** %s is now known as %s",
|
|
timestamp, msg.From, newNick,
|
|
))
|
|
}
|
|
|
|
func (a *App) handleNoticeEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
lines := msg.BodyLines()
|
|
text := strings.Join(lines, " ")
|
|
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[gray]%s [magenta]--%s-- %s",
|
|
timestamp, msg.From, text,
|
|
))
|
|
}
|
|
|
|
func (a *App) handleTopicEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
if msg.To == "" {
|
|
return
|
|
}
|
|
|
|
lines := msg.BodyLines()
|
|
text := strings.Join(lines, " ")
|
|
|
|
a.ui.AddLine(msg.To, fmt.Sprintf(
|
|
"[gray]%s [cyan]*** %s set topic: %s",
|
|
timestamp, msg.From, text,
|
|
))
|
|
}
|
|
|
|
func (a *App) handleDefaultEvent(
|
|
msg *api.Message, timestamp string,
|
|
) {
|
|
lines := msg.BodyLines()
|
|
text := strings.Join(lines, " ")
|
|
|
|
if text != "" {
|
|
a.ui.AddStatus(fmt.Sprintf(
|
|
"[gray]%s [white][%s] %s",
|
|
timestamp, msg.Command, text,
|
|
))
|
|
}
|
|
}
|