telnetroulette/terminal_handler.go

164 lines
4.3 KiB
Go
Raw Permalink Normal View History

2024-06-08 11:52:12 +02:00
package main
import (
"github.com/BRNSystems/go-telnet"
"github.com/reiver/go-oi"
"strings"
)
2024-06-09 11:02:18 +02:00
type internalTerminalHandler struct {
2024-06-08 11:52:12 +02:00
ShellCharacter string
WelcomeMessage string
2024-06-09 11:02:18 +02:00
CommandRegistry *commandRegistry
2024-06-08 11:52:12 +02:00
}
2024-06-09 11:02:18 +02:00
func newInternalTerminalHandler(shellCharacter, welcomeMessage string, commandRegistry *commandRegistry) *internalTerminalHandler {
return &internalTerminalHandler{
2024-06-08 11:52:12 +02:00
ShellCharacter: shellCharacter,
WelcomeMessage: welcomeMessage,
CommandRegistry: commandRegistry,
}
}
2024-06-09 11:03:31 +02:00
func clearLine(w telnet.Writer) error {
2024-06-09 11:02:18 +02:00
_, err := w.RawWrite([]byte{0x1B, 0x5B, 0x4B})
2024-06-09 11:03:31 +02:00
return err
2024-06-09 11:02:18 +02:00
}
2024-06-08 11:52:12 +02:00
2024-06-09 11:02:18 +02:00
func (handler *internalTerminalHandler) ServeTELNET(ctx telnet.Context, w telnet.Writer, r telnet.Reader) {
clientID := newClient(&ctx, &w, &r)
defer removeClient(clientID)
_, err := w.RawWrite([]byte{0xff, 0xfb, 0x03})
if err != nil {
return
} //send char by char
_, err = w.RawWrite([]byte{0xff, 0xfb, 0x01})
if err != nil {
return
} //echo from server
_, err = w.Write([]byte(strings.ReplaceAll(handler.WelcomeMessage, "\n", "\r\n") + "\r\n"))
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
//replace every \n with \r\n in WelcomeMessage
2024-06-09 11:02:18 +02:00
_, err = w.Write([]byte(handler.ShellCharacter))
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
var lineBuffer []byte
CSISequence := 0
for {
var bt [1]byte
n, err := r.Read(bt[:])
if err != nil {
break
}
if n > 0 {
b := bt[0]
if b == 0x03 || b == 0x04 {
return
} else if b == 0x1B { //escape
CSISequence = 1
} else if CSISequence == 1 && b == 0x5B {
CSISequence = 2
} else if CSISequence == 2 && b == 'A' {
if len(lineBuffer) == 0 && len(clients[clientID].History) > 0 {
if clients[clientID].HistoryIndex < len(clients[clientID].History)-1 {
clients[clientID].HistoryIndex++
}
lineBuffer = []byte(clients[clientID].History[clients[clientID].HistoryIndex])
2024-06-09 11:03:31 +02:00
if clearLine(w) != nil {
return
}
2024-06-09 11:02:18 +02:00
_, err := w.Write(lineBuffer)
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
}
} else if CSISequence == 2 && b == 'B' {
if len(lineBuffer) == 0 && len(clients[clientID].History) > 0 {
if clients[clientID].HistoryIndex > 0 {
clients[clientID].HistoryIndex--
}
lineBuffer = []byte(clients[clientID].History[clients[clientID].HistoryIndex])
2024-06-09 11:03:31 +02:00
if clearLine(w) != nil {
return
}
2024-06-09 11:02:18 +02:00
_, err := w.Write(lineBuffer)
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
}
} else if b == 0x7F {
if len(lineBuffer) > 0 {
2024-06-09 11:02:18 +02:00
_, err := w.Write([]byte{0x08, 0x20, 0x08})
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
lineBuffer = lineBuffer[:len(lineBuffer)-1]
}
} else if b != '\r' && b != '\n' && b != 0 {
CSISequence = 0
lineBuffer = append(lineBuffer, b)
2024-06-09 11:02:18 +02:00
_, err := w.RawWrite([]byte{b})
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
} else if b == '\r' {
2024-06-09 11:02:18 +02:00
_, err := w.Write([]byte("\r\n"))
if err != nil {
return
}
2024-06-08 11:52:12 +02:00
command := string(lineBuffer)
args := strings.Fields(command)
2024-06-09 11:02:18 +02:00
var message strings.Builder
2024-06-08 11:52:12 +02:00
if len(args) > 0 {
cmd := args[0]
2024-06-08 23:23:20 +02:00
internalCommand := false
2024-06-08 11:52:12 +02:00
if cmd == "exit" {
2024-06-08 23:23:20 +02:00
internalCommand = true
2024-06-08 11:52:12 +02:00
return
2024-06-08 23:23:20 +02:00
} else if cmd == "help" {
internalCommand = true
2024-06-09 11:02:18 +02:00
var commands strings.Builder
2024-06-08 23:23:20 +02:00
for command, commandEntry := range handler.CommandRegistry.commands {
2024-06-09 11:02:18 +02:00
commands.WriteString(command + " - " + commandEntry.description + "\r\n")
2024-06-08 23:23:20 +02:00
}
// Handle help command
if len(clients) > 0 {
2024-06-09 11:02:18 +02:00
clients[clientID].send("Just help yourself, " + clients[clientID].Username + "\r\nCommands:\r\n" + commands.String())
2024-06-08 23:23:20 +02:00
} else {
2024-06-09 11:02:18 +02:00
clients[clientID].send("No clients available" + "\r\nCommands:\r\n" + commands.String())
2024-06-08 23:23:20 +02:00
}
2024-06-08 11:52:12 +02:00
}
2024-06-09 11:02:18 +02:00
handlerFunc, ok, clientID := handler.CommandRegistry.getCommandHandler(cmd, clientID)
2024-06-08 11:52:12 +02:00
clients[clientID].HistoryIndex = 0
2024-06-08 23:23:20 +02:00
if ok || internalCommand {
if ok {
2024-06-09 11:02:18 +02:00
message.WriteString(handlerFunc(args[1:], clientID))
2024-06-08 23:23:20 +02:00
}
2024-06-08 11:52:12 +02:00
clients[clientID].History = append(clients[clientID].History, command)
} else {
2024-06-09 11:02:18 +02:00
message.WriteString("Command not found")
2024-06-08 11:52:12 +02:00
}
2024-06-09 11:02:18 +02:00
message.WriteString("\n" + handler.ShellCharacter)
2024-06-08 11:52:12 +02:00
} else {
2024-06-09 11:02:18 +02:00
message.WriteString(handler.ShellCharacter)
}
_, err = oi.LongWrite(w, []byte(strings.ReplaceAll(message.String(), "\n", "\r\n")))
if err != nil {
return
2024-06-08 11:52:12 +02:00
}
lineBuffer = nil
}
}
}
}