mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-25 15:10:28 +00:00
Telnet 32 ver
* refactoring * kinda works but off * two versions * update
This commit is contained in:
parent
39cff33dd3
commit
77f02374b4
8 changed files with 1290 additions and 85 deletions
Binary file not shown.
Binary file not shown.
BIN
src/Home/Telnet/Art/TelnetSplash.ans
Normal file
BIN
src/Home/Telnet/Art/TelnetSplash.ans
Normal file
Binary file not shown.
BIN
src/Home/Telnet/Art/ZealBBS.ans
Normal file
BIN
src/Home/Telnet/Art/ZealBBS.ans
Normal file
Binary file not shown.
83
src/Home/Telnet/Telnet.ZC
Executable file → Normal file
83
src/Home/Telnet/Telnet.ZC
Executable file → Normal file
|
@ -39,7 +39,88 @@ I64 TelnetOpen(U8 *host, U16 port) {
|
||||||
// sock(CTCPSocket *)->timeout = TCP_TIMEOUT;
|
// sock(CTCPSocket *)->timeout = TCP_TIMEOUT;
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
U0 HandleControlCodes(U8 ch) {
|
||||||
|
if (ch < 32) { // ASCII code below 32 (control character)
|
||||||
|
switch (ch) {
|
||||||
|
case 0: // NUL (Null) - Typically ignored
|
||||||
|
break;
|
||||||
|
case 7: // BEL (Bell)
|
||||||
|
Beep;
|
||||||
|
break;
|
||||||
|
case 8: // BS (Backspace)
|
||||||
|
term.cursor_x--;
|
||||||
|
break;
|
||||||
|
case 9: // HT (Horizontal Tab)
|
||||||
|
term.cursor_x += 8;
|
||||||
|
break;
|
||||||
|
case 10: // LF (Line Feed)
|
||||||
|
term.cursor_y++;
|
||||||
|
break;
|
||||||
|
case 11: // VT (Vertical Tab)
|
||||||
|
SysLog("Vertical Tab\n");
|
||||||
|
break;
|
||||||
|
case 12: // FF (Form Feed)
|
||||||
|
DocClear(term.doc);
|
||||||
|
break;
|
||||||
|
case 13: // CR (Carriage Return)
|
||||||
|
term.cursor_y++;
|
||||||
|
break;
|
||||||
|
case 14: // SO (Shift Out) - Switch to an alternate character set
|
||||||
|
case 15: // SI (Shift In) - Switch back to the default character set
|
||||||
|
SysLog("Shift In/Out\n");
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
SysLog("Synchronous Idle\n");
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
SysLog("End of Transmission Block\n");
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
SysLog("Cancel\n");
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
SysLog("End of Medium\n");
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
SysLog("Sub\n");
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
SysLog("Esc\n");
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
SysLog("Fs\n");
|
||||||
|
break;
|
||||||
|
case 29:
|
||||||
|
SysLog("Gs\n");
|
||||||
|
break;
|
||||||
|
case 30:
|
||||||
|
SysLog("Rs\n");
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
SysLog("Unit Separator\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// SysLog("CC %c happened\n", ch);
|
||||||
|
SysLog("CC happened\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ch == 127) {
|
||||||
|
SysLog("case 127");
|
||||||
|
}
|
||||||
|
if (ch == 0x24) {
|
||||||
|
// ch = "//$$$$";
|
||||||
|
}
|
||||||
|
if (ch >= 32 && ch < 256) // ZealOS's ASCII is up to 255
|
||||||
|
{
|
||||||
|
"%c", ch;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"%c", '?'; // unrecognized character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
U0 InputTask(U0 *args) {
|
U0 InputTask(U0 *args) {
|
||||||
I64 sock = *args;
|
I64 sock = *args;
|
||||||
I64 sc;
|
I64 sc;
|
||||||
|
|
821
src/Home/Telnet/Telnet32.ZC
Executable file
821
src/Home/Telnet/Telnet32.ZC
Executable file
|
@ -0,0 +1,821 @@
|
||||||
|
// Telnet client for ZealOS by y4my4m
|
||||||
|
// Public Domain
|
||||||
|
Cd(__DIR__);;
|
||||||
|
|
||||||
|
#define TELNET_PORT 23
|
||||||
|
#define BUF_SIZE 8192 // way too big?
|
||||||
|
#define INPUT_BUF_SIZE 32
|
||||||
|
#define TIMEOUT_DURATION 500000
|
||||||
|
|
||||||
|
#define NEGOTIATE 0xFF
|
||||||
|
|
||||||
|
#define ANSI_ESC 0x1B
|
||||||
|
#define ANSI_CSI 0x5B // [
|
||||||
|
|
||||||
|
#define CHAR_HEIGHT 8
|
||||||
|
#define CHAR_WIDTH 8
|
||||||
|
|
||||||
|
#define MAX_ANSI_PARAMS 32
|
||||||
|
|
||||||
|
#include "TelnetNegotiation"
|
||||||
|
#include "TelnetHelpers"
|
||||||
|
|
||||||
|
CTask *input_task = NULL;
|
||||||
|
Bool force_disconnect = FALSE;
|
||||||
|
Bool redraw_needed = FALSE;
|
||||||
|
|
||||||
|
class ScreenCell {
|
||||||
|
U8 ch;
|
||||||
|
I64 color;
|
||||||
|
}
|
||||||
|
class Terminal {
|
||||||
|
I64 sock;
|
||||||
|
Bool sock_ready;
|
||||||
|
I64 window_width;
|
||||||
|
I64 window_height;
|
||||||
|
CDoc *doc;
|
||||||
|
CTask *task;
|
||||||
|
CDC *dc;
|
||||||
|
|
||||||
|
ScreenCell screen[25][80];
|
||||||
|
|
||||||
|
I64 current_color;
|
||||||
|
I64 cursor_x;
|
||||||
|
I64 cursor_y;
|
||||||
|
|
||||||
|
U8 buffer[BUF_SIZE];
|
||||||
|
I64 buffer_len;
|
||||||
|
} term;
|
||||||
|
|
||||||
|
|
||||||
|
I64 TelnetOpen(U8 *host, U16 port) {
|
||||||
|
I64 socket;
|
||||||
|
|
||||||
|
if (host == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket = TCPConnectionCreate(host, port);
|
||||||
|
"$$GREEN$$Conecting to %s:%d.$$FG$$$$BG$$\n", host, port;
|
||||||
|
if (socket <= 0) {
|
||||||
|
PrintErr("Failed to connect to %s:%d\n", host, port);
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sock(CTCPSocket *)->timeout = 0;
|
||||||
|
// sock(CTCPSocket *)->timeout = TCP_TIMEOUT;
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 HandleControlCodes(U8 ch) {
|
||||||
|
if (ch < 32) { // ASCII code below 32 (control character)
|
||||||
|
switch (ch) {
|
||||||
|
case 0: // NUL (Null) - Typically ignored
|
||||||
|
break;
|
||||||
|
case 7: // BEL (Bell)
|
||||||
|
Beep;
|
||||||
|
break;
|
||||||
|
case 8: // BS (Backspace)
|
||||||
|
term.cursor_x--;
|
||||||
|
break;
|
||||||
|
case 9: // HT (Horizontal Tab)
|
||||||
|
term.cursor_x += 8;
|
||||||
|
break;
|
||||||
|
case 10: // LF (Line Feed)
|
||||||
|
term.cursor_y++;
|
||||||
|
// if (term.cursor_y >= term.window_height) {
|
||||||
|
// term.cursor_y = 0; // reset Y position to 0 when it exceeds window height
|
||||||
|
// }
|
||||||
|
// If the next character is CR, ignore it
|
||||||
|
// TODO: dont directly manipulate the buffer
|
||||||
|
// if (*(term.buffer + 1) == 13) term.buffer++;
|
||||||
|
break;
|
||||||
|
case 11: // VT (Vertical Tab)
|
||||||
|
SysLog("Vertical Tab\n");
|
||||||
|
break;
|
||||||
|
case 12: // FF (Form Feed)
|
||||||
|
DocClear(term.doc);
|
||||||
|
// term.cursor_x = 0;
|
||||||
|
// term.cursor_y = 0;
|
||||||
|
break;
|
||||||
|
case 13: // CR (Carriage Return)
|
||||||
|
term.cursor_x = 0;
|
||||||
|
// If the next character is LF, ignore it
|
||||||
|
// if (*(term.buffer + 1) == 10) term.buffer++;
|
||||||
|
break;
|
||||||
|
case 14: // SO (Shift Out) - Switch to an alternate character set
|
||||||
|
case 15: // SI (Shift In) - Switch back to the default character set
|
||||||
|
SysLog("Shift In/Out\n");
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
SysLog("Synchronous Idle\n");
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
SysLog("End of Transmission Block\n");
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
SysLog("Cancel\n");
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
SysLog("End of Medium\n");
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
SysLog("Sub\n");
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
SysLog("Esc\n");
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
SysLog("Fs\n");
|
||||||
|
break;
|
||||||
|
case 29:
|
||||||
|
SysLog("Gs\n");
|
||||||
|
break;
|
||||||
|
case 30:
|
||||||
|
SysLog("Rs\n");
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
SysLog("Unit Separator\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// SysLog("CC %c happened\n", ch);
|
||||||
|
SysLog("CC happened\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ch == 127) {
|
||||||
|
SysLog("case 127");
|
||||||
|
}
|
||||||
|
if (ch == 0x24) {
|
||||||
|
// ch = "//$$$$";
|
||||||
|
}
|
||||||
|
if (ch >= 32 && ch < 256) // ZealOS's ASCII is up to 255
|
||||||
|
{
|
||||||
|
term.screen[term.cursor_y][term.cursor_x].ch = ch;
|
||||||
|
term.screen[term.cursor_y][term.cursor_x].color = term.current_color;
|
||||||
|
term.cursor_x++;
|
||||||
|
if (term.cursor_x >= term.window_width) {
|
||||||
|
term.cursor_x = 0;
|
||||||
|
term.cursor_y++;
|
||||||
|
if (term.cursor_y >= term.window_height) {
|
||||||
|
term.cursor_y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// "%c", '?'; // unrecognized character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
U0 TerminalDrawIt(CTask *task, CDC *dc)
|
||||||
|
{
|
||||||
|
// Clear the document
|
||||||
|
// DocClear;
|
||||||
|
|
||||||
|
I64 row, col;
|
||||||
|
// Loop over the screen array and draw each character
|
||||||
|
for (row = 0; row < term.window_height; row++) {
|
||||||
|
for (col = 0; col < term.window_width; col++) {
|
||||||
|
// Get the character and color from the screen array
|
||||||
|
U8 ch = term.screen[row][col].ch;
|
||||||
|
|
||||||
|
// Set the color
|
||||||
|
dc->color = term.screen[row][col].color;
|
||||||
|
// term.dc->color = WHITE;
|
||||||
|
|
||||||
|
// Draw the character
|
||||||
|
// GrPutChar(term.dc, col * CHAR_WIDTH, row * CHAR_HEIGHT, ch);
|
||||||
|
GrPutChar(dc, col * 8, row * 8, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the cursor
|
||||||
|
// Note: this draws the cursor as a white rectangle. You may want to customize this.
|
||||||
|
// term.dc->color = WHITE;
|
||||||
|
// GrRect(term.dc, term.cursor_x * CHAR_WIDTH, term.cursor_y * CHAR_HEIGHT,
|
||||||
|
// (term.cursor_x + 1) * CHAR_WIDTH - 1, (term.cursor_y + 1) * CHAR_HEIGHT - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 TerminalTask() {
|
||||||
|
while (!term.sock_ready) {
|
||||||
|
Sleep(100); // Avoid busy waiting
|
||||||
|
}
|
||||||
|
// This task receives data from the socket and fills the buffer
|
||||||
|
while (!force_disconnect)
|
||||||
|
{
|
||||||
|
term.buffer_len = TCPSocketReceive(term.sock, term.buffer, BUF_SIZE - 1);
|
||||||
|
if (term.buffer_len > 0) {
|
||||||
|
redraw_needed = TRUE;
|
||||||
|
term.buffer[term.buffer_len] = '\0';
|
||||||
|
// Parse the buffer and draw the contents
|
||||||
|
U8 *ptr = term.buffer;
|
||||||
|
while (ptr < term.buffer + term.buffer_len) {
|
||||||
|
// Telnet negotiation sequence
|
||||||
|
if (*ptr == NEGOTIATE) {
|
||||||
|
// FIXME: i don't think the telnet negotiation is actually working properly?
|
||||||
|
TelnetNegotiate(term.sock, *ptr);
|
||||||
|
ptr += 3;
|
||||||
|
}
|
||||||
|
else if (*ptr == ANSI_ESC) {
|
||||||
|
// ANSI escape sequence
|
||||||
|
ptr++;
|
||||||
|
if (*ptr == ANSI_CSI) {
|
||||||
|
ptr++;
|
||||||
|
I64 ansi_code[MAX_ANSI_PARAMS], counter;
|
||||||
|
for (counter = 0; counter < MAX_ANSI_PARAMS; counter++) {
|
||||||
|
ansi_code[counter] = 0; // Initialize all elements to 0
|
||||||
|
}
|
||||||
|
I64 ansi_param_count = 0;
|
||||||
|
while (IsDigit(*ptr) || *ptr == ';') {
|
||||||
|
if (IsDigit(*ptr)) {
|
||||||
|
ansi_code[ansi_param_count] = ansi_code[ansi_param_count] * 10 + (*ptr - '0');
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else if (*ptr == ';') {
|
||||||
|
ansi_param_count++;
|
||||||
|
if (ansi_param_count >= MAX_ANSI_PARAMS) {
|
||||||
|
// Error handling: too many parameters
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
if(!IsDigit(*ptr) || *ptr == ';'){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle specific ANSI escape sequences
|
||||||
|
switch (*ptr) {
|
||||||
|
case 'n':
|
||||||
|
SysLog("Case n, %d\n",ansi_code[0]);
|
||||||
|
if (ansi_code[0] == 5) {
|
||||||
|
// Respond with terminal readiness
|
||||||
|
SysLog("reported terminal readiness\n");
|
||||||
|
U8 deviceStatusResponse[5];
|
||||||
|
deviceStatusResponse[0] = ANSI_ESC;
|
||||||
|
deviceStatusResponse[1] = ANSI_CSI;
|
||||||
|
deviceStatusResponse[2] = 0x30; // '0'
|
||||||
|
deviceStatusResponse[3] = 0x6E; // 'n'
|
||||||
|
deviceStatusResponse[4] = 0x00; // Null-terminator
|
||||||
|
TCPSocketSend(term.sock, deviceStatusResponse, 4);
|
||||||
|
// TCPSocketSendString(term.sock, "\x1B[0n");
|
||||||
|
}
|
||||||
|
else if (ansi_code[0] == 6) {
|
||||||
|
// Respond with cursor position
|
||||||
|
// U8 response[32] = "\x1B[%d;%dR", window_width, term.window_height;
|
||||||
|
SysLog("reported cursor position\n");
|
||||||
|
U8 cursorResponse[8];
|
||||||
|
cursorResponse[0] = ANSI_ESC;
|
||||||
|
cursorResponse[1] = ANSI_CSI;
|
||||||
|
cursorResponse[2] = 0x32;
|
||||||
|
cursorResponse[3] = 0x35;
|
||||||
|
cursorResponse[4] = 0x3B;
|
||||||
|
cursorResponse[5] = 0x38;
|
||||||
|
cursorResponse[6] = 0x30;
|
||||||
|
cursorResponse[6] = 0x52;
|
||||||
|
cursorResponse[7] = 0x00;
|
||||||
|
TCPSocketSend(term.sock, cursorResponse, 7);
|
||||||
|
// TCPSocketSendString(term.sock, "\x1B\[25;80R");
|
||||||
|
}
|
||||||
|
else if (ansi_code[0] == 255) {
|
||||||
|
// https://github.com/NuSkooler/enigma-bbs/blob/97cd0c3063b0c9f93a0fa4a44a85318ca81aef43/core/ansi_term.js#L140
|
||||||
|
SysLog("reported screensize?\n");
|
||||||
|
SendWindowSize(term.sock, 25, 80);
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
// Respond with device attributes
|
||||||
|
SysLog("reported device attributes\n");
|
||||||
|
// TCPSocketSendString(term.sock, "\x1B[?1;0c");
|
||||||
|
// Reports at VT101 (not sure why though)
|
||||||
|
U8 deviceAttributesResponse[8];
|
||||||
|
deviceAttributesResponse[0] = ANSI_ESC;
|
||||||
|
deviceAttributesResponse[1] = ANSI_CSI;
|
||||||
|
deviceAttributesResponse[2] = 0x3F; // '?'
|
||||||
|
deviceAttributesResponse[3] = 0x31; // '1'
|
||||||
|
deviceAttributesResponse[4] = 0x3B; // ';'
|
||||||
|
deviceAttributesResponse[5] = 0x32; // '0'
|
||||||
|
deviceAttributesResponse[6] = 0x63; // 'c'
|
||||||
|
deviceAttributesResponse[7] = 0x00; // Null-terminator
|
||||||
|
TCPSocketSend(term.sock, deviceAttributesResponse, 7);
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
// colors might be printed in the wrong order?
|
||||||
|
// like, <Esc>[1;40m and now <Esc>[40m;1m
|
||||||
|
I64 m;
|
||||||
|
Bool isBright = FALSE;
|
||||||
|
for (m = 0; m <= ansi_param_count; m++) {
|
||||||
|
if (ansi_code[m] <= 10) {
|
||||||
|
switch (ansi_code[m]) {
|
||||||
|
case 0:
|
||||||
|
term.current_color = WHITE; // should be BG FG for full reset
|
||||||
|
isBright = FALSE;
|
||||||
|
break; // reset
|
||||||
|
case 1: isBright = TRUE; break;
|
||||||
|
case 2: isBright = FALSE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((ansi_code[m] >= 30 && ansi_code[m] <= 39) || (ansi_code[m] >= 90 && ansi_code[m] <= 97)) {
|
||||||
|
// Set foreground color
|
||||||
|
// SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
|
||||||
|
if(!isBright){
|
||||||
|
switch (ansi_code[m]) {
|
||||||
|
case 30:
|
||||||
|
term.current_color = BLACK;
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
term.current_color = RED;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
term.current_color = GREEN;
|
||||||
|
break;
|
||||||
|
case 33:
|
||||||
|
term.current_color = YELLOW;
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
term.current_color = BLUE;
|
||||||
|
break;
|
||||||
|
case 35:
|
||||||
|
term.current_color = PURPLE;
|
||||||
|
break;
|
||||||
|
case 36:
|
||||||
|
term.current_color = CYAN;
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
term.current_color = WHITE;
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
term.current_color = WHITE;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (ansi_code[m]) {
|
||||||
|
case 90:
|
||||||
|
case 30:
|
||||||
|
term.current_color = DKGRAY;
|
||||||
|
break;
|
||||||
|
case 91:
|
||||||
|
case 31:
|
||||||
|
term.current_color = LTRED;
|
||||||
|
break;
|
||||||
|
case 92:
|
||||||
|
case 32:
|
||||||
|
term.current_color = LTGREEN;
|
||||||
|
break;
|
||||||
|
case 93:
|
||||||
|
case 33:
|
||||||
|
term.current_color = YELLOW;
|
||||||
|
break;
|
||||||
|
case 94:
|
||||||
|
case 34:
|
||||||
|
term.current_color = LTBLUE;
|
||||||
|
break;
|
||||||
|
case 95:
|
||||||
|
case 35:
|
||||||
|
term.current_color = LTPURPLE;
|
||||||
|
break;
|
||||||
|
case 96:
|
||||||
|
case 36:
|
||||||
|
term.current_color = LTCYAN;
|
||||||
|
break;
|
||||||
|
case 97:
|
||||||
|
case 37:
|
||||||
|
term.current_color = LTGRAY;
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
term.current_color = WHITE;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this is a dumb approach, just do a CatPrint or something
|
||||||
|
// until we properly catch the `;` it will stay buggy
|
||||||
|
else if ((ansi_code[m] >= 40 && ansi_code[m] <= 49) || (ansi_code[m] >= 100 && ansi_code[m] <= 107)) {
|
||||||
|
// Set background color
|
||||||
|
// SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
|
||||||
|
if(!isBright){
|
||||||
|
switch (ansi_code[m]) {
|
||||||
|
case 40:
|
||||||
|
term.current_color = BLACK;
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
term.current_color = RED;
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
term.current_color = GREEN;
|
||||||
|
break;
|
||||||
|
case 43:
|
||||||
|
term.current_color = YELLOW;
|
||||||
|
break;
|
||||||
|
case 44:
|
||||||
|
term.current_color = BLUE;
|
||||||
|
break;
|
||||||
|
case 45:
|
||||||
|
term.current_color = PURPLE;
|
||||||
|
break;
|
||||||
|
case 46:
|
||||||
|
term.current_color = CYAN;
|
||||||
|
break;
|
||||||
|
case 47:
|
||||||
|
term.current_color = WHITE;
|
||||||
|
break;
|
||||||
|
case 49:
|
||||||
|
// reset
|
||||||
|
term.current_color = BLACK;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (ansi_code[m]) {
|
||||||
|
case 100:
|
||||||
|
case 40:
|
||||||
|
term.current_color = DKGRAY;
|
||||||
|
break;
|
||||||
|
case 101:
|
||||||
|
case 41:
|
||||||
|
term.current_color = LTRED;
|
||||||
|
break;
|
||||||
|
case 102:
|
||||||
|
case 42:
|
||||||
|
term.current_color = LTGREEN;
|
||||||
|
break;
|
||||||
|
case 103:
|
||||||
|
case 43:
|
||||||
|
term.current_color = YELLOW;
|
||||||
|
break;
|
||||||
|
case 104:
|
||||||
|
case 44:
|
||||||
|
term.current_color = LTBLUE;
|
||||||
|
break;
|
||||||
|
case 105:
|
||||||
|
case 45:
|
||||||
|
term.current_color = LTPURPLE;
|
||||||
|
break;
|
||||||
|
case 106:
|
||||||
|
case 46:
|
||||||
|
term.current_color = LTCYAN;
|
||||||
|
break;
|
||||||
|
case 107:
|
||||||
|
case 47:
|
||||||
|
term.current_color = LTGRAY;
|
||||||
|
break;
|
||||||
|
case 49:
|
||||||
|
// reset
|
||||||
|
term.current_color = BLACK;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
// Cursor Up
|
||||||
|
SysLog("Cursor Up\n");
|
||||||
|
term.cursor_y -= ansi_code[0];
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
// Cursor Down
|
||||||
|
SysLog("Cursor Down\n");
|
||||||
|
term.cursor_y += ansi_code[0];
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
// Cursor Right
|
||||||
|
// SysLog("Cursor Right %d %d\n", ansi_param_count, ansi_code[0]);
|
||||||
|
term.cursor_x += ansi_code[0];
|
||||||
|
// NOTE: this has been "fixed" since we now change the window's background color
|
||||||
|
// if we just move the cursor,
|
||||||
|
// you dont get the colored background since we skip over it directly
|
||||||
|
// I64 C;
|
||||||
|
// for (C = 0; C < ansi_code[0]; C++) {
|
||||||
|
// " ";
|
||||||
|
// }
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
// Cursor Left
|
||||||
|
SysLog("Cursor Left\n");
|
||||||
|
term.cursor_x -= ansi_code[0];
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
// Cursor Next Line
|
||||||
|
SysLog("Cursor Next Line\n");
|
||||||
|
term.cursor_x = 0;
|
||||||
|
term.cursor_y++;
|
||||||
|
if (term.cursor_y >= term.window_height) {
|
||||||
|
// scroll
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
// Cursor Previous Line
|
||||||
|
SysLog("Cursor Previous Line\n");
|
||||||
|
term.cursor_x = 0;
|
||||||
|
term.cursor_y -= ansi_code[0];
|
||||||
|
if (term.cursor_y < 0) {
|
||||||
|
term.cursor_y = 0; // prevent y from going below 0
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
// Cursor Horizontal Absolute
|
||||||
|
SysLog("Cursor Horizontal Absolute\n");
|
||||||
|
term.cursor_x = ansi_code[0];
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'f':
|
||||||
|
I64 row = 1, col = 1; // default values
|
||||||
|
// Parse the row number
|
||||||
|
if(ansi_code[0] != 1)
|
||||||
|
row = ansi_code[0];
|
||||||
|
if(ansi_code[1] != 1)
|
||||||
|
col = ansi_code[1];
|
||||||
|
|
||||||
|
// TODO: This is a hack, dont skip row 0, col 0 (maybe?)
|
||||||
|
if (row == 0 && col == 0) {
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count);
|
||||||
|
|
||||||
|
if (row >= term.window_height)
|
||||||
|
row = term.window_height;
|
||||||
|
if (col >= term.window_width)
|
||||||
|
col = term.window_width;
|
||||||
|
// "$$CM,0,0$$";
|
||||||
|
// term.cursor_x = col-1;
|
||||||
|
// term.cursor_y = row-1;
|
||||||
|
term.cursor_x = col;
|
||||||
|
term.cursor_y = row;
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
// SysLog("J code, %d %d\n", ansi_param_count, ansi_code[0]);
|
||||||
|
// Erase in Display
|
||||||
|
if (ansi_code[0] == 0) {
|
||||||
|
// Erase from cursor to end of display
|
||||||
|
// DocDelToNum(Fs->display_doc, Fs->display_doc->cur_entry->line_num);
|
||||||
|
} else if (ansi_code[0] == 1) {
|
||||||
|
// Erase from cursor to beginning of display
|
||||||
|
// DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE);
|
||||||
|
} else if (ansi_code[0] == 2) {
|
||||||
|
// Erase entire display
|
||||||
|
DocClear(term.doc);
|
||||||
|
term.cursor_x = 0;
|
||||||
|
term.cursor_y = 0;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
// TODO: I have no idea if this actually works
|
||||||
|
SysLog("K code\n");
|
||||||
|
// Erase in Line
|
||||||
|
// CDocEntry *cur_entry = Fs->display_doc->cur_entry;
|
||||||
|
// CDocEntry *next_entry = cur_entry->next;
|
||||||
|
|
||||||
|
// // Delete the current entry
|
||||||
|
// if (!(cur_entry->de_flags & (DOCEF_HOLD | DOCEF_FILTER_SKIP))) {
|
||||||
|
// Fs->display_doc->cur_entry = next_entry;
|
||||||
|
// Fs->display_doc->cur_col = next_entry->min_col;
|
||||||
|
// DocEntryDel(Fs->display_doc, cur_entry);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create a new entry (line) in its place
|
||||||
|
// CDocEntry *new_entry = DocEntryNewTag(Fs->display_doc, cur_entry, "");
|
||||||
|
// DocInsEntry(Fs->display_doc, new_entry);
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
SysLog("L code\n");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
// TODO: Scroll Up
|
||||||
|
SysLog("Scroll Up");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
// TODO: Scroll Down
|
||||||
|
SysLog("Scroll Down");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
SysLog("Case M\n");
|
||||||
|
term.cursor_y--;
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
ptr++;
|
||||||
|
I64 code = 0;
|
||||||
|
|
||||||
|
while (IsDigit(*ptr)) {
|
||||||
|
code = code * 10 + (*ptr - '0');
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
switch (code) {
|
||||||
|
case 25:
|
||||||
|
if (*ptr == 'l') DocCursor(OFF); // Hide cursor
|
||||||
|
if (*ptr == 'h') DocCursor(ON); // Show cursor
|
||||||
|
ptr++; // Move past 'l' or 'h'
|
||||||
|
break;
|
||||||
|
case 47:
|
||||||
|
if (*ptr == 'l') SysLog("code 47l\n"); // restore screen
|
||||||
|
if (*ptr == 'h') SysLog("code 47h\n"); // save screen
|
||||||
|
ptr++; // Move past 'l' or 'h'
|
||||||
|
break;
|
||||||
|
case 1049:
|
||||||
|
if (*ptr == 'l') SysLog("code 1049l\n"); // enables the alternative buffer
|
||||||
|
if (*ptr == 'h') SysLog("code 1049h\n"); // disables the alternative buffer
|
||||||
|
ptr++; // Move past 'l' or 'h'
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
SysLog("SaveCurrentCursorPosition\n");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
SysLog("RestoreCurrentCursorPosition\n");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
// self.restoreCursorPosition();
|
||||||
|
SysLog("r case \n");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case 'l':
|
||||||
|
// TODO: Handle 'h' (set mode) or 'l' (reset mode) codes
|
||||||
|
SysLog("h or l case \n");
|
||||||
|
ptr++; // Skip 'h' or 'l'
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
SysLog("ScreenMode attempt\n");
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(!IsDigit(*ptr)) {
|
||||||
|
SysLog("Unknown code: %c\n", *ptr);
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Print the received character
|
||||||
|
HandleControlCodes(*ptr);
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (redraw_needed) {
|
||||||
|
// TerminalDrawIt(term.task, term.task);
|
||||||
|
DocClear(term.doc);
|
||||||
|
term.cursor_x = 0;
|
||||||
|
term.cursor_y = 0;
|
||||||
|
redraw_needed = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"Error: Connection closed by the remote host.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
|
||||||
|
|
||||||
|
term.sock_ready = 0; // Initialize the semaphore
|
||||||
|
term.sock = TelnetOpen(host, port);
|
||||||
|
term.window_width = 80;
|
||||||
|
term.window_height = 25;
|
||||||
|
if (term.sock <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
term.sock_ready = 1; // Signal that the socket is ready
|
||||||
|
term.doc = Fs->display_doc;
|
||||||
|
|
||||||
|
// Spawn a task to receive data from the socket
|
||||||
|
term.task = Spawn(&TerminalTask, NULL, "Telnet");
|
||||||
|
// term.task->win_inhibit = WIG_USER_TASK_DEFAULT;
|
||||||
|
// LBts(&term.task->display_flags, DISPLAYf_SHOW);
|
||||||
|
|
||||||
|
Fs->draw_it = &TerminalDrawIt;
|
||||||
|
|
||||||
|
StrCopy(Fs->task_title, "TELNET");
|
||||||
|
Fs->border_src = BDS_CONST;
|
||||||
|
Fs->border_attr = LTGREEN << 4 + DriveTextAttrGet(':') & 15;
|
||||||
|
Fs->text_attr = BLACK << 4 + WHITE;
|
||||||
|
Fs->title_src = TTS_LOCKED_CONST;
|
||||||
|
|
||||||
|
Fs->win_width = term.window_width;
|
||||||
|
WinHorz((TEXT_COLS / 2) - (Fs->win_width / 2),
|
||||||
|
(TEXT_COLS / 2) - (Fs->win_width / 2) +
|
||||||
|
(Fs->win_width - 1),
|
||||||
|
Fs);
|
||||||
|
Fs->win_height = term.window_height;
|
||||||
|
WinVert((TEXT_ROWS / 2) - (Fs->win_height / 2),
|
||||||
|
(TEXT_ROWS / 2) - (Fs->win_height / 2) +
|
||||||
|
(Fs->win_height - 1),
|
||||||
|
Fs);
|
||||||
|
DocClear;
|
||||||
|
// WinFocus(term.task);
|
||||||
|
// DocClear(Fs->border_doc, TRUE);
|
||||||
|
|
||||||
|
// probably should use word wrap?
|
||||||
|
// DocPrint(, "$$WW,1$$");
|
||||||
|
// DocCursor(OFF);
|
||||||
|
// term.dc = DCAlias;
|
||||||
|
"$$BG,GREEN$$$$WHITE$$Connected$$FG$$$$BG$$\n";
|
||||||
|
|
||||||
|
I64 sc;
|
||||||
|
// https://theasciicode.com.ar/ascii-control-characters/escape-ascii-code-27.html
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!force_disconnect) {
|
||||||
|
U8 key = KeyGet(&sc);
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
switch (sc.u8[0])
|
||||||
|
{
|
||||||
|
case SC_CURSOR_LEFT:
|
||||||
|
TCPSocketSendString(term.sock, "\x1B[D");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_CURSOR_RIGHT:
|
||||||
|
TCPSocketSendString(term.sock, "\x1B[C");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_CURSOR_UP:
|
||||||
|
TCPSocketSendString(term.sock, "\x1B[A");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_CURSOR_DOWN:
|
||||||
|
TCPSocketSendString(term.sock, "\x1B[B");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
switch (sc.u8[0])
|
||||||
|
{
|
||||||
|
case SC_TAB:
|
||||||
|
TCPSocketSendString(term.sock, "\x09");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CH_BACKSPACE:
|
||||||
|
TCPSocketSendString(term.sock, "\x08");
|
||||||
|
break;
|
||||||
|
case CH_ESC:
|
||||||
|
TCPSocketSendString(term.sock, "\x1B");
|
||||||
|
break;
|
||||||
|
case CH_SHIFT_ESC:
|
||||||
|
force_disconnect = TRUE;
|
||||||
|
break;
|
||||||
|
// send buffer on enter
|
||||||
|
case '\n':
|
||||||
|
TCPSocketSendString(term.sock, "\r\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (key >= ' ' && key <= '~') {
|
||||||
|
// Handle regular keys
|
||||||
|
U8 input_buf[2];
|
||||||
|
input_buf[0] = key;
|
||||||
|
input_buf[1] = '\0';
|
||||||
|
TCPSocketSend(term.sock, input_buf, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
PutExcept;
|
||||||
|
|
||||||
|
Kill(term.task);
|
||||||
|
TCPSocketClose(term.sock);
|
||||||
|
"Telnet connection closed.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// dev server
|
||||||
|
Telnet("localhost", 8888);
|
|
@ -17,89 +17,392 @@ U0 TelnetPrompt() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
U0 HandleControlCodes(U8 ch) {
|
|
||||||
if (ch < 32) { // ASCII code below 32 (control character)
|
// U0 SplashScreen(U8 ch) {
|
||||||
switch (ch) {
|
//
|
||||||
case 0: // NUL (Null) - Typically ignored
|
// }
|
||||||
break;
|
|
||||||
case 7: // BEL (Bell)
|
// Eventually would like to parse it here:
|
||||||
Beep;
|
|
||||||
break;
|
// U0 TelnetANSIParser(I64 sock, U8 *ptr) {
|
||||||
case 8: // BS (Backspace)
|
// U8 buffer[BUF_SIZE];
|
||||||
// "%c%c%c", 8, ' ', 8; // Move cursor back, erase character, move cursor back again
|
|
||||||
"$$CM,-8,0$$";
|
// I64 window_width = 80;
|
||||||
break;
|
// I64 window_height = 25;
|
||||||
case 9: // HT (Horizontal Tab)
|
// if (*ptr == ANSI_CSI) {
|
||||||
// " "; // 8 spaces
|
// ptr++;
|
||||||
"$$CM,8,0$$";
|
// I64 ansi_code[MAX_ANSI_PARAMS], counter;
|
||||||
break;
|
// for (counter = 0; counter < MAX_ANSI_PARAMS; counter++) {
|
||||||
case 10: // LF (Line Feed)
|
// ansi_code[counter] = 0; // Initialize all elements to 0
|
||||||
"\n";
|
// }
|
||||||
break;
|
// I64 ansi_param_count = 0;
|
||||||
case 11: // VT (Vertical Tab)
|
// while (IsDigit(*ptr) || *ptr == ';') {
|
||||||
SysLog("Vertical Tab\n");
|
// if (IsDigit(*ptr)) {
|
||||||
break;
|
// ansi_code[ansi_param_count] = ansi_code[ansi_param_count] * 10 + (*ptr - '0');
|
||||||
case 12: // FF (Form Feed)
|
// ptr++;
|
||||||
DocClear;
|
// }
|
||||||
break;
|
// else if (*ptr == ';') {
|
||||||
case 13: // CR (Carriage Return)
|
// ansi_param_count++;
|
||||||
"\r";
|
// if (ansi_param_count >= MAX_ANSI_PARAMS) {
|
||||||
break;
|
// // Error handling: too many parameters
|
||||||
case 14: // SO (Shift Out) - Switch to an alternate character set
|
// break;
|
||||||
case 15: // SI (Shift In) - Switch back to the default character set
|
// }
|
||||||
SysLog("Shift In/Out\n");
|
// ptr++;
|
||||||
break;
|
// if(!IsDigit(*ptr) || *ptr == ';'){
|
||||||
case 22:
|
// break;
|
||||||
SysLog("Synchronous Idle\n");
|
// }
|
||||||
break;
|
// }
|
||||||
case 23:
|
// }
|
||||||
SysLog("End of Transmission Block\n");
|
|
||||||
break;
|
// // Handle specific ANSI escape sequences
|
||||||
case 24:
|
// switch (*ptr) {
|
||||||
SysLog("Cancel\n");
|
// case 'n':
|
||||||
break;
|
// SysLog("Case n, %d\n",ansi_code[0]);
|
||||||
case 25:
|
// if (ansi_code[0] == 5) {
|
||||||
SysLog("End of Medium\n");
|
// // Respond with terminal readiness
|
||||||
break;
|
// SysLog("reported terminal readiness\n");
|
||||||
case 26:
|
// U8 deviceStatusResponse[5];
|
||||||
SysLog("Sub\n");
|
// deviceStatusResponse[0] = ANSI_ESC;
|
||||||
break;
|
// deviceStatusResponse[1] = ANSI_CSI;
|
||||||
case 27:
|
// deviceStatusResponse[2] = 0x30; // '0'
|
||||||
SysLog("Esc\n");
|
// deviceStatusResponse[3] = 0x6E; // 'n'
|
||||||
break;
|
// deviceStatusResponse[4] = 0x00; // Null-terminator
|
||||||
case 28:
|
// TCPSocketSend(sock, deviceStatusResponse, 4);
|
||||||
SysLog("Fs\n");
|
// // TCPSocketSendString(sock, "\x1B[0n");
|
||||||
break;
|
// }
|
||||||
case 29:
|
// else if (ansi_code[0] == 6) {
|
||||||
SysLog("Gs\n");
|
// // Respond with cursor position
|
||||||
break;
|
// // U8 response[32] = "\x1B[%d;%dR", window_width, window_height;
|
||||||
case 30:
|
// SysLog("reported cursor position\n");
|
||||||
SysLog("Rs\n");
|
// U8 cursorResponse[8];
|
||||||
break;
|
// cursorResponse[0] = ANSI_ESC;
|
||||||
case 31:
|
// cursorResponse[1] = ANSI_CSI;
|
||||||
SysLog("Unit Separator\n");
|
// cursorResponse[2] = 0x32;
|
||||||
break;
|
// cursorResponse[3] = 0x35;
|
||||||
default:
|
// cursorResponse[4] = 0x3B;
|
||||||
SysLog("CC happened\n", ch);
|
// cursorResponse[5] = 0x38;
|
||||||
break;
|
// cursorResponse[6] = 0x30;
|
||||||
}
|
// cursorResponse[6] = 0x52;
|
||||||
}
|
// cursorResponse[7] = 0x00;
|
||||||
else {
|
// TCPSocketSend(sock, cursorResponse, 7);
|
||||||
if (ch == 127) {
|
// // TCPSocketSendString(sock, "\x1B\[25;80R");
|
||||||
SysLog("case 127");
|
// }
|
||||||
}
|
// else if (ansi_code[0] == 255) {
|
||||||
if (ch == 0x24) {
|
// // https://github.com/NuSkooler/enigma-bbs/blob/97cd0c3063b0c9f93a0fa4a44a85318ca81aef43/core/ansi_term.js#L140
|
||||||
ch = "//$$$$";
|
// SysLog("reported screensize?\n");
|
||||||
}
|
// SendWindowSize(sock, 25, 80);
|
||||||
if (ch >= 32 && ch < 256) // ZealOS's ASCII is up to 255
|
// }
|
||||||
{
|
// ptr++;
|
||||||
"%c", ch;
|
// break;
|
||||||
}
|
// case 'c':
|
||||||
else {
|
// // Respond with device attributes
|
||||||
"%c", '?'; // unrecognized character
|
// SysLog("reported device attributes\n");
|
||||||
}
|
// // TCPSocketSendString(sock, "\x1B[?1;0c");
|
||||||
}
|
// // Reports at VT101 (not sure why though)
|
||||||
}
|
// U8 deviceAttributesResponse[8];
|
||||||
|
// deviceAttributesResponse[0] = ANSI_ESC;
|
||||||
|
// deviceAttributesResponse[1] = ANSI_CSI;
|
||||||
|
// deviceAttributesResponse[2] = 0x3F; // '?'
|
||||||
|
// deviceAttributesResponse[3] = 0x31; // '1'
|
||||||
|
// deviceAttributesResponse[4] = 0x3B; // ';'
|
||||||
|
// deviceAttributesResponse[5] = 0x32; // '0'
|
||||||
|
// deviceAttributesResponse[6] = 0x63; // 'c'
|
||||||
|
// deviceAttributesResponse[7] = 0x00; // Null-terminator
|
||||||
|
// TCPSocketSend(sock, deviceAttributesResponse, 7);
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'm':
|
||||||
|
// // colors might be printed in the wrong order?
|
||||||
|
// // like, <Esc>[1;40m and now <Esc>[40m;1m
|
||||||
|
// I64 m;
|
||||||
|
// Bool isBright = FALSE;
|
||||||
|
// for (m = 0; m <= ansi_param_count; m++) {
|
||||||
|
// if (ansi_code[m] <= 10) {
|
||||||
|
// switch (ansi_code[m]) {
|
||||||
|
// case 0: "$$BG$$$$FG$$"; isBright = FALSE; break; // reset
|
||||||
|
// case 1: isBright = TRUE; break;
|
||||||
|
// case 2: isBright = FALSE; break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if ((ansi_code[m] >= 30 && ansi_code[m] <= 39) || (ansi_code[m] >= 90 && ansi_code[m] <= 97)) {
|
||||||
|
// // Set foreground color
|
||||||
|
// // SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
|
||||||
|
// if(!isBright){
|
||||||
|
// switch (ansi_code[m]) {
|
||||||
|
// case 30: "$$BLACK$$"; break;
|
||||||
|
// case 31: "$$RED$$"; break;
|
||||||
|
// case 32: "$$GREEN$$"; break;
|
||||||
|
// case 33: "$$YELLOW$$"; break;
|
||||||
|
// case 34: "$$BLUE$$"; break;
|
||||||
|
// case 35: "$$PURPLE$$"; break;
|
||||||
|
// case 36: "$$CYAN$$"; break;
|
||||||
|
// case 37: "$$WHITE$$"; break;
|
||||||
|
// case 39: "$$FG$$"; break;
|
||||||
|
// default: break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// switch (ansi_code[m]) {
|
||||||
|
// case 90:
|
||||||
|
// case 30: "$$DKGRAY$$"; break;
|
||||||
|
// case 91:
|
||||||
|
// case 31: "$$LTRED$$"; break;
|
||||||
|
// case 92:
|
||||||
|
// case 32: "$$LTGREEN$$"; break;
|
||||||
|
// case 93:
|
||||||
|
// case 33: "$$YELLOW$$"; break;
|
||||||
|
// case 94:
|
||||||
|
// case 34: "$$LTBLUE$$"; break;
|
||||||
|
// case 95:
|
||||||
|
// case 35: "$$LTPURPLE$$"; break;
|
||||||
|
// case 96:
|
||||||
|
// case 36: "$$LTCYAN$$"; break;
|
||||||
|
// case 97:
|
||||||
|
// case 37: "$$LTGRAY$$"; break;
|
||||||
|
// case 39: "$$FG$$"; break;
|
||||||
|
// default: break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // this is a dumb approach, just do a CatPrint or something
|
||||||
|
// // until we properly catch the `;` it will stay buggy
|
||||||
|
// else if ((ansi_code[m] >= 40 && ansi_code[m] <= 49) || (ansi_code[m] >= 100 && ansi_code[m] <= 107)) {
|
||||||
|
// // Set background color
|
||||||
|
// // SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
|
||||||
|
// if(!isBright){
|
||||||
|
// switch (ansi_code[m]) {
|
||||||
|
// case 40: "$$BG,BLACK$$"; break;
|
||||||
|
// case 41: "$$BG,RED$$"; break;
|
||||||
|
// case 42: "$$BG,GREEN$$"; break;
|
||||||
|
// case 43: "$$BG,YELLOW$$"; break;
|
||||||
|
// case 44: "$$BG,BLUE$$"; break;
|
||||||
|
// case 45: "$$BG,PURPLE$$"; break;
|
||||||
|
// case 46: "$$BG,CYAN$$"; break;
|
||||||
|
// case 47: "$$BG,WHITE$$"; break;
|
||||||
|
// case 49: "$$BG$$"; break; // reset
|
||||||
|
// default: break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// switch (ansi_code[m]) {
|
||||||
|
// case 100:
|
||||||
|
// case 40: "$$BG,DKGRAY$$"; break;
|
||||||
|
// case 101:
|
||||||
|
// case 41: "$$BG,LTRED$$"; break;
|
||||||
|
// case 102:
|
||||||
|
// case 42: "$$BG,LTGREEN$$"; break;
|
||||||
|
// case 103:
|
||||||
|
// case 43: "$$BG,YELLOW$$"; break;
|
||||||
|
// case 104:
|
||||||
|
// case 44: "$$BG,LTBLUE$$"; break;
|
||||||
|
// case 105:
|
||||||
|
// case 45: "$$BG,LTPURPLE$$"; break;
|
||||||
|
// case 106:
|
||||||
|
// case 46: "$$BG,LTCYAN$$"; break;
|
||||||
|
// case 107:
|
||||||
|
// case 47: "$$BG,LTGRAY$$"; break;
|
||||||
|
// case 49: "$$BG$$"; break; // reset
|
||||||
|
// default: break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'A':
|
||||||
|
// // Cursor Up
|
||||||
|
// SysLog("Cursor Up\n");
|
||||||
|
// // "$$CM+TY,0,-%d$$", ansi_code[0];
|
||||||
|
// "$$CM,0,-%d$$", ansi_code[0];
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'B':
|
||||||
|
// // Cursor Down
|
||||||
|
// SysLog("Cursor Down\n");
|
||||||
|
// "$$CM,0,%d$$", ansi_code[0];
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'C':
|
||||||
|
// // Cursor Right
|
||||||
|
// // SysLog("Cursor Right %d %d\n", ansi_param_count, ansi_code[0]);
|
||||||
|
// "$$CM,%d,0$$", ansi_code[0];
|
||||||
|
// // NOTE: this has been "fixed" since we now change the window's background color
|
||||||
|
// // if we just move the cursor,
|
||||||
|
// // you dont get the colored background since we skip over it directly
|
||||||
|
// // I64 C;
|
||||||
|
// // for (C = 0; C < ansi_code[0]; C++) {
|
||||||
|
// // " ";
|
||||||
|
// // }
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'D':
|
||||||
|
// // Cursor Left
|
||||||
|
// SysLog("Cursor Left\n");
|
||||||
|
// "$$CM,-%d,0$$", ansi_code[0];
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'E':
|
||||||
|
// // Cursor Next Line
|
||||||
|
// SysLog("Cursor Next Line\n");
|
||||||
|
// // "$$CM+TY,0,+%d$$", ansi_code[0];
|
||||||
|
// "\n";
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'F':
|
||||||
|
// // Cursor Previous Line
|
||||||
|
// SysLog("Cursor Previous Line\n");
|
||||||
|
// "$$CM+LY,0,-%d$$", ansi_code[0];
|
||||||
|
// // "\n";
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'G':
|
||||||
|
// // Cursor Horizontal Absolute
|
||||||
|
// SysLog("Cursor Horizontal Absolute\n");
|
||||||
|
// "$$CM,%d,0$$", ansi_code[0];
|
||||||
|
// // "\n";
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'H':
|
||||||
|
// case 'f':
|
||||||
|
// I64 row = 1, col = 1; // default values
|
||||||
|
// // Parse the row number
|
||||||
|
// if(ansi_code[0] != 1)
|
||||||
|
// row = ansi_code[0];
|
||||||
|
// if(ansi_code[1] != 1)
|
||||||
|
// col = ansi_code[1];
|
||||||
|
|
||||||
|
// // TODO: This is a hack, dont skip row 0, col 0 (maybe?)
|
||||||
|
// if (row == 0 && col == 0) {
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// // SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count);
|
||||||
|
|
||||||
|
// if (row > window_height)
|
||||||
|
// row = window_height-1;
|
||||||
|
// if (col > window_width)
|
||||||
|
// col = window_width-1;
|
||||||
|
// // "$$CM,0,0$$";
|
||||||
|
// "$$CM+LX+TY,LE=%d,RE=%d$$", col-1, row-1;
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'J':
|
||||||
|
// // SysLog("J code, %d %d\n", ansi_param_count, ansi_code[0]);
|
||||||
|
// // Erase in Display
|
||||||
|
// if (ansi_code[0] == 0) {
|
||||||
|
// // Erase from cursor to end of display
|
||||||
|
// // DocDelToNum(Fs->display_doc, Fs->display_doc->cur_entry->line_num);
|
||||||
|
// } else if (ansi_code[0] == 1) {
|
||||||
|
// // Erase from cursor to beginning of display
|
||||||
|
// // DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE);
|
||||||
|
// } else if (ansi_code[0] == 2) {
|
||||||
|
// // Erase entire display
|
||||||
|
// DocClear;
|
||||||
|
// }
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'K':
|
||||||
|
// // TODO: I have no idea if this actually works
|
||||||
|
// SysLog("K code\n");
|
||||||
|
// // Erase in Line
|
||||||
|
// // CDocEntry *cur_entry = Fs->display_doc->cur_entry;
|
||||||
|
// // CDocEntry *next_entry = cur_entry->next;
|
||||||
|
|
||||||
|
// // // Delete the current entry
|
||||||
|
// // if (!(cur_entry->de_flags & (DOCEF_HOLD | DOCEF_FILTER_SKIP))) {
|
||||||
|
// // Fs->display_doc->cur_entry = next_entry;
|
||||||
|
// // Fs->display_doc->cur_col = next_entry->min_col;
|
||||||
|
// // DocEntryDel(Fs->display_doc, cur_entry);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // // Create a new entry (line) in its place
|
||||||
|
// // CDocEntry *new_entry = DocEntryNewTag(Fs->display_doc, cur_entry, "");
|
||||||
|
// // DocInsEntry(Fs->display_doc, new_entry);
|
||||||
|
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'L':
|
||||||
|
// SysLog("L code\n");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'S':
|
||||||
|
// // TODO: Scroll Up
|
||||||
|
// SysLog("Scroll Up");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'T':
|
||||||
|
// // TODO: Scroll Down
|
||||||
|
// SysLog("Scroll Down");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'M':
|
||||||
|
// SysLog("Case M\n");
|
||||||
|
// // TODO: is this correct? cursor should go one line up
|
||||||
|
// "$$CM,0,-1$$";
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case '?':
|
||||||
|
// ptr++;
|
||||||
|
// I64 code = 0;
|
||||||
|
|
||||||
|
// while (IsDigit(*ptr)) {
|
||||||
|
// code = code * 10 + (*ptr - '0');
|
||||||
|
// ptr++;
|
||||||
|
// }
|
||||||
|
// switch (code) {
|
||||||
|
// case 25:
|
||||||
|
// if (*ptr == 'l') DocCursor(OFF); // Hide cursor
|
||||||
|
// if (*ptr == 'h') DocCursor(ON); // Show cursor
|
||||||
|
// ptr++; // Move past 'l' or 'h'
|
||||||
|
// break;
|
||||||
|
// case 47:
|
||||||
|
// if (*ptr == 'l') SysLog("code 47l\n"); // restore screen
|
||||||
|
// if (*ptr == 'h') SysLog("code 47h\n"); // save screen
|
||||||
|
// ptr++; // Move past 'l' or 'h'
|
||||||
|
// break;
|
||||||
|
// case 1049:
|
||||||
|
// if (*ptr == 'l') SysLog("code 1049l\n"); // enables the alternative buffer
|
||||||
|
// if (*ptr == 'h') SysLog("code 1049h\n"); // disables the alternative buffer
|
||||||
|
// ptr++; // Move past 'l' or 'h'
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case 's':
|
||||||
|
// SysLog("SaveCurrentCursorPosition\n");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'u':
|
||||||
|
// SysLog("RestoreCurrentCursorPosition\n");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'r':
|
||||||
|
// // self.restoreCursorPosition();
|
||||||
|
// SysLog("r case \n");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// case 'h':
|
||||||
|
// case 'l':
|
||||||
|
// // TODO: Handle 'h' (set mode) or 'l' (reset mode) codes
|
||||||
|
// SysLog("h or l case \n");
|
||||||
|
// ptr++; // Skip 'h' or 'l'
|
||||||
|
// break;
|
||||||
|
// case '=':
|
||||||
|
// SysLog("ScreenMode attempt\n");
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// if(!IsDigit(*ptr)) {
|
||||||
|
// SysLog("Unknown code: %c\n", *ptr);
|
||||||
|
// }
|
||||||
|
// ptr++;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
// Placeholder for the full ANSI text styling
|
// Placeholder for the full ANSI text styling
|
||||||
// if (ansi_code[m] <= 10) {
|
// if (ansi_code[m] <= 10) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ U0 SendTerminalType(I64 sock, U8 *terminal_type) {
|
||||||
TCPSocketSendString(sock, response);
|
TCPSocketSendString(sock, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
U0 TelnetNegotiate(I64 sock, U8 *ptr)
|
U0 TelnetNegotiate(I64 sock, U8 ptr)
|
||||||
{
|
{
|
||||||
U8 negotiation_code = *(ptr + 1);
|
U8 negotiation_code = *(ptr + 1);
|
||||||
U8 option_code = *(ptr + 2);
|
U8 option_code = *(ptr + 2);
|
||||||
|
|
Loading…
Reference in a new issue