2024-06-08 11:52:12 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/BRNSystems/go-telnet"
|
|
|
|
"github.com/reiver/go-oi"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type InternalTerminalHandler struct {
|
|
|
|
ShellCharacter string
|
|
|
|
WelcomeMessage string
|
|
|
|
CommandRegistry *CommandRegistry
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewInternalTerminalHandler(shellCharacter, welcomeMessage string, commandRegistry *CommandRegistry) *InternalTerminalHandler {
|
|
|
|
return &InternalTerminalHandler{
|
|
|
|
ShellCharacter: shellCharacter,
|
|
|
|
WelcomeMessage: welcomeMessage,
|
|
|
|
CommandRegistry: commandRegistry,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (handler *InternalTerminalHandler) ServeTELNET(ctx telnet.Context, w telnet.Writer, r telnet.Reader) {
|
2024-06-08 13:52:22 +02:00
|
|
|
clientID := NewClient(&ctx, &w, &r)
|
2024-06-08 11:52:12 +02:00
|
|
|
|
|
|
|
defer RemoveClient(clientID)
|
|
|
|
w.RawWrite([]byte{0xff, 0xfb, 0x03}) //send char by char
|
|
|
|
w.RawWrite([]byte{0xff, 0xfb, 0x01}) //echo from server
|
|
|
|
w.Write([]byte(strings.ReplaceAll(handler.WelcomeMessage, "\n", "\r\n") + "\r\n"))
|
|
|
|
//replace every \n with \r\n in WelcomeMessage
|
|
|
|
w.Write([]byte(handler.ShellCharacter))
|
|
|
|
|
|
|
|
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])
|
|
|
|
w.RawWrite([]byte{0x1B, 0x5B, 0x4B}) //clear line
|
|
|
|
w.Write(lineBuffer)
|
|
|
|
}
|
|
|
|
} 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])
|
|
|
|
w.RawWrite([]byte{0x1B, 0x5B, 0x4B}) //clear line
|
|
|
|
w.Write(lineBuffer)
|
|
|
|
}
|
|
|
|
} else if b == 0x7F {
|
|
|
|
if len(lineBuffer) > 0 {
|
|
|
|
w.Write([]byte{0x08, 0x20, 0x08})
|
|
|
|
lineBuffer = lineBuffer[:len(lineBuffer)-1]
|
|
|
|
}
|
|
|
|
} else if b != '\r' && b != '\n' && b != 0 {
|
|
|
|
CSISequence = 0
|
|
|
|
lineBuffer = append(lineBuffer, b)
|
|
|
|
w.RawWrite([]byte{b})
|
|
|
|
} else if b == '\r' {
|
|
|
|
w.Write([]byte("\r\n"))
|
|
|
|
command := string(lineBuffer)
|
|
|
|
args := strings.Fields(command)
|
|
|
|
var message string
|
|
|
|
|
|
|
|
if len(args) > 0 {
|
|
|
|
cmd := args[0]
|
|
|
|
if cmd == "exit" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
handlerFunc, ok, clientID := handler.CommandRegistry.GetCommandHandler(cmd, clientID)
|
|
|
|
clients[clientID].HistoryIndex = 0
|
|
|
|
if ok {
|
|
|
|
message = handlerFunc(args[1:], clientID)
|
|
|
|
clients[clientID].History = append(clients[clientID].History, command)
|
|
|
|
} else {
|
|
|
|
message = "Command not found"
|
|
|
|
}
|
|
|
|
message += "\n" + handler.ShellCharacter
|
|
|
|
} else {
|
|
|
|
message = handler.ShellCharacter
|
|
|
|
}
|
|
|
|
oi.LongWrite(w, []byte(strings.ReplaceAll(message, "\n", "\r\n")))
|
|
|
|
lineBuffer = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|