Telnet display in it's own task

This commit is contained in:
y4my4my4m 2023-05-13 13:24:05 +09:00
parent df0b3bef94
commit 7aa082e962
2 changed files with 316 additions and 235 deletions

View file

@ -17,9 +17,24 @@ Cd(__DIR__);;
#include "TelnetNegotiation" #include "TelnetNegotiation"
#include "TelnetHelpers" #include "TelnetHelpers"
CTask *input_task = NULL;
Bool force_disconnect = FALSE; Bool force_disconnect = FALSE;
class Terminal {
I64 sock;
Bool sock_ready;
I64 window_width;
I64 window_height;
CDoc *doc;
CTask *task;
I64 current_color;
I64 current_bgcolor;
I64 cursor_x;
I64 cursor_y;
U8 buffer[BUF_SIZE];
I64 buffer_len;
} term;
I64 TelnetOpen(U8 *host, U16 port) { I64 TelnetOpen(U8 *host, U16 port) {
I64 sock; I64 sock;
@ -29,7 +44,7 @@ I64 TelnetOpen(U8 *host, U16 port) {
} }
sock = TCPConnectionCreate(host, port); sock = TCPConnectionCreate(host, port);
"$$GREEN$$Conecting to %s:%d.$$FG$$$$BG$$\n", host, port; "$$GREEN$$Connecting to %s:%d.$$FG$$$$BG$$\n", host, port;
if (sock <= 0) { if (sock <= 0) {
PrintErr("Failed to connect to %s:%d\n", host, port); PrintErr("Failed to connect to %s:%d\n", host, port);
return sock; return sock;
@ -41,6 +56,7 @@ I64 TelnetOpen(U8 *host, U16 port) {
} }
U0 HandleControlCodes(U8 ch) { U0 HandleControlCodes(U8 ch) {
Sleep(100);
if (ch < 32) { // ASCII code below 32 (control character) if (ch < 32) { // ASCII code below 32 (control character)
switch (ch) { switch (ch) {
case 0: // NUL (Null) - Typically ignored case 0: // NUL (Null) - Typically ignored
@ -50,23 +66,23 @@ U0 HandleControlCodes(U8 ch) {
break; break;
case 8: // BS (Backspace) case 8: // BS (Backspace)
// "%c%c%c", 8, ' ', 8; // Move cursor back, erase character, move cursor back again // "%c%c%c", 8, ' ', 8; // Move cursor back, erase character, move cursor back again
"$$CM,-8,0$$"; DocPrint(term.doc, "$$CM,-8,0$$");
break; break;
case 9: // HT (Horizontal Tab) case 9: // HT (Horizontal Tab)
// " "; // 8 spaces // " "; // 8 spaces
"$$CM,8,0$$"; DocPrint(term.doc, "$$CM,8,0$$");
break; break;
case 10: // LF (Line Feed) case 10: // LF (Line Feed)
"\n"; DocPrint(term.doc, "\n");
break; break;
case 11: // VT (Vertical Tab) case 11: // VT (Vertical Tab)
SysLog("Vertical Tab\n"); SysLog("Vertical Tab\n");
break; break;
case 12: // FF (Form Feed) case 12: // FF (Form Feed)
DocClear; DocClear(term.doc);
break; break;
case 13: // CR (Carriage Return) case 13: // CR (Carriage Return)
"\r"; DocPrint(term.doc, "\r");
break; break;
case 14: // SO (Shift Out) - Switch to an alternate character set case 14: // SO (Shift Out) - Switch to an alternate character set
case 15: // SI (Shift In) - Switch back to the default character set case 15: // SI (Shift In) - Switch back to the default character set
@ -114,160 +130,35 @@ U0 HandleControlCodes(U8 ch) {
SysLog("case 127"); SysLog("case 127");
} }
if (ch == 0x24) { if (ch == 0x24) {
ch = "//$$$$"; DocPrint(term.doc, "%s", "//$$$$");
} }
if (ch >= 32 && ch < 256) // ZealOS's ASCII is up to 255 if (ch >= 32 && ch < 256) // ZealOS's ASCII is up to 255
{ {
"%c", ch; DocPrint(term.doc, "%c", ch);
} }
else { else {
"%c", '?'; // unrecognized character DocPrint(term.doc, "%c", '?'); // unrecognized character
} }
} }
} }
U0 InputTask(U0 *args) { U0 TerminalTask() {
I64 sock = *args; while (!term.sock_ready) {
I64 sc; Sleep(100); // Avoid busy waiting
DocTermNew;
DocPrint(, "$$WW,1$$");
// WinBorder(OFF);
DocBottom(input_task->put_doc);
"\n$$GREEN$$$BK,1$Input$BK,0$$$BLACK$$:";
// 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(sock, "\x1B[D");
break;
case SC_CURSOR_RIGHT:
TCPSocketSendString(sock, "\x1B[C");
break;
case SC_CURSOR_UP:
TCPSocketSendString(sock, "\x1B[A");
break;
case SC_CURSOR_DOWN:
TCPSocketSendString(sock, "\x1B[B");
break;
default:
break;
}
break;
case 9:
switch (sc.u8[0])
{
case SC_TAB:
TCPSocketSendString(sock, "\x09");
break;
default:
break;
}
case CH_BACKSPACE:
TCPSocketSendString(sock, "\x08");
break;
case CH_ESC:
TCPSocketSendString(sock, "\x1B");
break;
case CH_SHIFT_ESC:
force_disconnect = TRUE;
break;
// send buffer on enter
case '\n':
TCPSocketSendString(sock, "\r\n");
break;
default:
if (key >= ' ' && key <= '~') {
// Handle regular keys
U8 input_buf[2];
input_buf[0] = key;
input_buf[1] = '\0';
TCPSocketSend(sock, input_buf, 1);
}
break;
}
}
} }
catch
PutExcept;
}
U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
I64 sock, bytes_received;
U8 buffer[BUF_SIZE], *ptr;
I64 window_width = 80;
I64 window_height = 25;
// CDoc *doc = DocPut;
// Fs->display_doc->flags |= DOCF_SIZE_MIN;
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;
DocClear(Fs->border_doc, TRUE);
// LBtr(&Fs->display_flags, DISPLAYf_SHOW);
Fs->win_width = 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 = window_height;
WinVert((TEXT_ROWS / 2) - (Fs->win_height / 2),
(TEXT_ROWS / 2) - (Fs->win_height / 2) +
(Fs->win_height - 1),
Fs);
DocClear;
// probably should use word wrap?
DocPrint(, "$$WW,1$$");
DocCursor(OFF);
sock = TelnetOpen(host, port);
if (sock <= 0) {
return;
}
// Spawn input window
input_task = Spawn(&InputTask, &sock, "Telnet Input");
input_task->win_inhibit = WIG_USER_TASK_DEFAULT;
LBts(&input_task->display_flags, DISPLAYf_SHOW);
WinFocus(input_task);
input_task->text_attr = TRANSPARENT << 4 + WHITE;
input_task->win_top = Fs->win_top + window_height + 1;
input_task->win_bottom = Fs->win_top + 30;
input_task->win_left = Fs->win_left;
input_task->win_right = Fs->win_left+window_width - 1;
"$$BG,GREEN$$$$WHITE$$Connected$$FG$$$$BG$$\n";
while (!force_disconnect) { while (!force_disconnect) {
bytes_received = TCPSocketReceive(sock, buffer, BUF_SIZE - 1); term.buffer_len = TCPSocketReceive(term.sock, term.buffer, BUF_SIZE - 1);
if (bytes_received > 0) { if (term.buffer_len > 0) {
buffer[bytes_received] = '\0'; term.buffer[term.buffer_len] = '\0';
// Basic Telnet protocol parser // Basic Telnet protocol parser
ptr = buffer; U8 *ptr = term.buffer;
while (*ptr) { while (ptr < term.buffer + term.buffer_len) {
// Telnet negotiation sequence // Telnet negotiation sequence
if (*ptr == NEGOTIATE) { if (*ptr == NEGOTIATE) {
// FIXME: i don't think the telnet negotiation is actually working properly? // FIXME: i don't think the telnet negotiation is actually working properly?
TelnetNegotiate(sock, ptr); TelnetNegotiate(term.sock, ptr);
ptr += 3; ptr += 3;
} }
else if (*ptr == ANSI_ESC) { else if (*ptr == ANSI_ESC) {
@ -311,8 +202,8 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
deviceStatusResponse[2] = 0x30; // '0' deviceStatusResponse[2] = 0x30; // '0'
deviceStatusResponse[3] = 0x6E; // 'n' deviceStatusResponse[3] = 0x6E; // 'n'
deviceStatusResponse[4] = 0x00; // Null-terminator deviceStatusResponse[4] = 0x00; // Null-terminator
TCPSocketSend(sock, deviceStatusResponse, 4); TCPSocketSend(term.sock, deviceStatusResponse, 4);
// TCPSocketSendString(sock, "\x1B[0n"); // TCPSocketSendString(term.sock, "\x1B[0n");
} }
else if (ansi_code[0] == 6) { else if (ansi_code[0] == 6) {
// Respond with cursor position // Respond with cursor position
@ -328,20 +219,20 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
cursorResponse[6] = 0x30; cursorResponse[6] = 0x30;
cursorResponse[6] = 0x52; cursorResponse[6] = 0x52;
cursorResponse[7] = 0x00; cursorResponse[7] = 0x00;
TCPSocketSend(sock, cursorResponse, 7); TCPSocketSend(term.sock, cursorResponse, 7);
// TCPSocketSendString(sock, "\x1B\[25;80R"); // TCPSocketSendString(term.sock, "\x1B\[25;80R");
} }
else if (ansi_code[0] == 255) { else if (ansi_code[0] == 255) {
// https://github.com/NuSkooler/enigma-bbs/blob/97cd0c3063b0c9f93a0fa4a44a85318ca81aef43/core/ansi_term.js#L140 // https://github.com/NuSkooler/enigma-bbs/blob/97cd0c3063b0c9f93a0fa4a44a85318ca81aef43/core/ansi_term.js#L140
SysLog("reported screensize?\n"); SysLog("reported screensize?\n");
SendWindowSize(sock, 25, 80); SendWindowSize(term.sock, 25, 80);
} }
ptr++; ptr++;
break; break;
case 'c': case 'c':
// Respond with device attributes // Respond with device attributes
SysLog("reported device attributes\n"); SysLog("reported device attributes\n");
// TCPSocketSendString(sock, "\x1B[?1;0c"); // TCPSocketSendString(term.sock, "\x1B[?1;0c");
// Reports at VT101 (not sure why though) // Reports at VT101 (not sure why though)
U8 deviceAttributesResponse[8]; U8 deviceAttributesResponse[8];
deviceAttributesResponse[0] = ANSI_ESC; deviceAttributesResponse[0] = ANSI_ESC;
@ -352,7 +243,7 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
deviceAttributesResponse[5] = 0x32; // '0' deviceAttributesResponse[5] = 0x32; // '0'
deviceAttributesResponse[6] = 0x63; // 'c' deviceAttributesResponse[6] = 0x63; // 'c'
deviceAttributesResponse[7] = 0x00; // Null-terminator deviceAttributesResponse[7] = 0x00; // Null-terminator
TCPSocketSend(sock, deviceAttributesResponse, 7); TCPSocketSend(term.sock, deviceAttributesResponse, 7);
ptr++; ptr++;
break; break;
case 'm': case 'm':
@ -363,7 +254,10 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
for (m = 0; m <= ansi_param_count; m++) { for (m = 0; m <= ansi_param_count; m++) {
if (ansi_code[m] <= 10) { if (ansi_code[m] <= 10) {
switch (ansi_code[m]) { switch (ansi_code[m]) {
case 0: "$$BG$$$$FG$$"; isBright = FALSE; break; // reset case 0:
DocPrint(term.doc, "$$BG$$$$FG$$");
isBright = FALSE;
break; // reset
case 1: isBright = TRUE; break; case 1: isBright = TRUE; break;
case 2: isBright = FALSE; break; case 2: isBright = FALSE; break;
} }
@ -373,37 +267,73 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
// SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]); // SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
if(!isBright){ if(!isBright){
switch (ansi_code[m]) { switch (ansi_code[m]) {
case 30: "$$BLACK$$"; break; case 30:
case 31: "$$RED$$"; break; DocPrint(term.doc, "$$BLACK$$");
case 32: "$$GREEN$$"; break; break;
case 33: "$$YELLOW$$"; break; case 31:
case 34: "$$BLUE$$"; break; DocPrint(term.doc, "$$RED$$");
case 35: "$$PURPLE$$"; break; break;
case 36: "$$CYAN$$"; break; case 32:
case 37: "$$WHITE$$"; break; DocPrint(term.doc, "$$GREEN$$");
case 39: "$$FG$$"; break; break;
case 33:
DocPrint(term.doc, "$$YELLOW$$");
break;
case 34:
DocPrint(term.doc, "$$BLUE$$");
break;
case 35:
DocPrint(term.doc, "$$PURPLE$$");
break;
case 36:
DocPrint(term.doc, "$$CYAN$$");
break;
case 37:
DocPrint(term.doc, "$$WHITE$$");
break;
case 39:
DocPrint(term.doc, "$$FG$$");
break;
default: break; default: break;
} }
} }
else { else {
switch (ansi_code[m]) { switch (ansi_code[m]) {
case 90: case 90:
case 30: "$$DKGRAY$$"; break; case 30:
DocPrint(term.doc, "$$DKGRAY$$");
break;
case 91: case 91:
case 31: "$$LTRED$$"; break; case 31:
DocPrint(term.doc, "$$LTRED$$");
break;
case 92: case 92:
case 32: "$$LTGREEN$$"; break; case 32:
DocPrint(term.doc, "$$LTGREEN$$");
break;
case 93: case 93:
case 33: "$$YELLOW$$"; break; case 33:
DocPrint(term.doc, "$$YELLOW$$");
break;
case 94: case 94:
case 34: "$$LTBLUE$$"; break; case 34:
DocPrint(term.doc, "$$LTBLUE$$");
break;
case 95: case 95:
case 35: "$$LTPURPLE$$"; break; case 35:
DocPrint(term.doc, "$$LTPURPLE$$");
break;
case 96: case 96:
case 36: "$$LTCYAN$$"; break; case 36:
DocPrint(term.doc, "$$LTCYAN$$");
break;
case 97: case 97:
case 37: "$$LTGRAY$$"; break; case 37:
case 39: "$$FG$$"; break; DocPrint(term.doc, "$$LTGRAY$$");
break;
case 39:
DocPrint(term.doc, "$$FG$$");
break;
default: break; default: break;
} }
} }
@ -415,37 +345,74 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
// SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]); // SysLog("ansi_code[%d] = %d\n", m, ansi_code[m]);
if(!isBright){ if(!isBright){
switch (ansi_code[m]) { switch (ansi_code[m]) {
case 40: "$$BG,BLACK$$"; break; case 40:
case 41: "$$BG,RED$$"; break; DocPrint(term.doc,"$$BG,BLACK$$");
case 42: "$$BG,GREEN$$"; break; break;
case 43: "$$BG,YELLOW$$"; break; case 41:
case 44: "$$BG,BLUE$$"; break; DocPrint(term.doc,"$$BG,RED$$");
case 45: "$$BG,PURPLE$$"; break; break;
case 46: "$$BG,CYAN$$"; break; case 42:
case 47: "$$BG,WHITE$$"; break; DocPrint(term.doc,"$$BG,GREEN$$");
case 49: "$$BG$$"; break; // reset break;
case 43:
DocPrint(term.doc,"$$BG,YELLOW$$");
break;
case 44:
DocPrint(term.doc,"$$BG,BLUE$$");
break;
case 45:
DocPrint(term.doc,"$$BG,PURPLE$$");
break;
case 46:
DocPrint(term.doc,"$$BG,CYAN$$");
break;
case 47:
DocPrint(term.doc,"$$BG,WHITE$$");
break;
case 49:
DocPrint(term.doc,"$$BG$$");
break;
default: break; default: break;
} }
} }
else { else {
switch (ansi_code[m]) { switch (ansi_code[m]) {
case 100: case 100:
case 40: "$$BG,DKGRAY$$"; break; case 40:
DocPrint(term.doc,"$$BG,DKGRAY$$");
break;
case 101: case 101:
case 41: "$$BG,LTRED$$"; break; case 41:
DocPrint(term.doc,"$$BG,LTRED$$");
break;
case 102: case 102:
case 42: "$$BG,LTGREEN$$"; break; case 42:
DocPrint(term.doc,"$$BG,LTGREEN$$");
break;
case 103: case 103:
case 43: "$$BG,YELLOW$$"; break; case 43:
DocPrint(term.doc,"$$BG,YELLOW$$");
break;
case 104: case 104:
case 44: "$$BG,LTBLUE$$"; break; case 44:
DocPrint(term.doc,"$$BG,LTBLUE$$");
break;
case 105: case 105:
case 45: "$$BG,LTPURPLE$$"; break; case 45:
DocPrint(term.doc,"$$BG,LTPURPLE$$");
break;
case 106: case 106:
case 46: "$$BG,LTCYAN$$"; break; case 46:
DocPrint(term.doc,"$$BG,LTCYAN$$");
break;
case 107: case 107:
case 47: "$$BG,LTGRAY$$"; break; case 47:
case 49: "$$BG$$"; break; // reset DocPrint(term.doc,"$$BG,LTGRAY$$");
break;
case 49:
DocPrint(term.doc,"$$BG$$");
break;
// reset
default: break; default: break;
} }
} }
@ -457,19 +424,19 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
// Cursor Up // Cursor Up
SysLog("Cursor Up\n"); SysLog("Cursor Up\n");
// "$$CM+TY,0,-%d$$", ansi_code[0]; // "$$CM+TY,0,-%d$$", ansi_code[0];
"$$CM,0,-%d$$", ansi_code[0]; DocPrint(term.doc, "$$CM,0,-%d$$", ansi_code[0]);
ptr++; ptr++;
break; break;
case 'B': case 'B':
// Cursor Down // Cursor Down
SysLog("Cursor Down\n"); SysLog("Cursor Down\n");
"$$CM,0,%d$$", ansi_code[0]; DocPrint(term.doc, "$$CM,0,%d$$", ansi_code[0]);
ptr++; ptr++;
break; break;
case 'C': case 'C':
// Cursor Right // Cursor Right
// SysLog("Cursor Right %d %d\n", ansi_param_count, ansi_code[0]); // SysLog("Cursor Right %d %d\n", ansi_param_count, ansi_code[0]);
"$$CM,%d,0$$", ansi_code[0]; DocPrint(term.doc, "$$CM,%d,0$$", ansi_code[0]);
// NOTE: this has been "fixed" since we now change the window's background color // NOTE: this has been "fixed" since we now change the window's background color
// if we just move the cursor, // if we just move the cursor,
// you dont get the colored background since we skip over it directly // you dont get the colored background since we skip over it directly
@ -482,27 +449,27 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
case 'D': case 'D':
// Cursor Left // Cursor Left
SysLog("Cursor Left\n"); SysLog("Cursor Left\n");
"$$CM,-%d,0$$", ansi_code[0]; DocPrint(term.doc, "$$CM,-%d,0$$", ansi_code[0]);
ptr++; ptr++;
break; break;
case 'E': case 'E':
// Cursor Next Line // Cursor Next Line
SysLog("Cursor Next Line\n"); SysLog("Cursor Next Line\n");
// "$$CM+TY,0,+%d$$", ansi_code[0]; // "$$CM+TY,0,+%d$$", ansi_code[0];
"\n"; DocPrint(term.doc, "\n");
ptr++; ptr++;
break; break;
case 'F': case 'F':
// Cursor Previous Line // Cursor Previous Line
SysLog("Cursor Previous Line\n"); SysLog("Cursor Previous Line\n");
"$$CM+LY,0,-%d$$", ansi_code[0]; DocPrint(term.doc, "$$CM+LY,0,-%d$$", ansi_code[0]);
// "\n"; // "\n";
ptr++; ptr++;
break; break;
case 'G': case 'G':
// Cursor Horizontal Absolute // Cursor Horizontal Absolute
SysLog("Cursor Horizontal Absolute\n"); SysLog("Cursor Horizontal Absolute\n");
"$$CM,%d,0$$", ansi_code[0]; DocPrint(term.doc, "$$CM,%d,0$$", ansi_code[0]);
// "\n"; // "\n";
ptr++; ptr++;
break; break;
@ -522,12 +489,12 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
} }
// SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count); // SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count);
if (row > window_height) if (row > term.window_height)
row = window_height-1; row = term.window_height-1;
if (col > window_width) if (col > term.window_width)
col = window_width-1; col = term.window_width-1;
// "$$CM,0,0$$"; // "$$CM,0,0$$";
"$$CM+LX+TY,LE=%d,RE=%d$$", col-1, row-1; DocPrint(term.doc, "$$CM+LX+TY,LE=%d,RE=%d$$", col-1, row-1);
ptr++; ptr++;
break; break;
case 'J': case 'J':
@ -541,7 +508,7 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
// DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE); // DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE);
} else if (ansi_code[0] == 2) { } else if (ansi_code[0] == 2) {
// Erase entire display // Erase entire display
DocClear; DocClear(term.doc);
} }
ptr++; ptr++;
break; break;
@ -582,7 +549,7 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
case 'M': case 'M':
SysLog("Case M\n"); SysLog("Case M\n");
// TODO: is this correct? cursor should go one line up // TODO: is this correct? cursor should go one line up
"$$CM,0,-1$$"; DocPrint(term.doc, "$$CM,0,-1$$");
ptr++; ptr++;
break; break;
case '?': case '?':
@ -595,6 +562,7 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
} }
switch (code) { switch (code) {
case 25: case 25:
// need to specify which doc?
if (*ptr == 'l') DocCursor(OFF); // Hide cursor if (*ptr == 'l') DocCursor(OFF); // Hide cursor
if (*ptr == 'h') DocCursor(ON); // Show cursor if (*ptr == 'h') DocCursor(ON); // Show cursor
ptr++; // Move past 'l' or 'h' ptr++; // Move past 'l' or 'h'
@ -652,15 +620,122 @@ U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
ptr++; ptr++;
} }
} }
} else { } else {
"Error: Connection closed by the remote host.\n"; "Error: Connection closed by the remote host.\n";
break; break;
} }
} }
}
Kill(input_task); U0 Telnet(U8 *host, U16 port=TELNET_PORT) {
TCPSocketClose(sock);
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");
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;
DocClear(Fs->border_doc, TRUE);
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;
// probably should use word wrap?
DocPrint(, "$$WW,1$$");
DocCursor(OFF);
"$$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;
TCPSocketClose(term.sock);
"Telnet connection closed.\n"; "Telnet connection closed.\n";
} }

View file

@ -20,7 +20,6 @@ Cd(__DIR__);;
#include "TelnetNegotiation" #include "TelnetNegotiation"
#include "TelnetHelpers" #include "TelnetHelpers"
CTask *input_task = NULL;
Bool force_disconnect = FALSE; Bool force_disconnect = FALSE;
Bool redraw_needed = FALSE; Bool redraw_needed = FALSE;
@ -74,7 +73,7 @@ U0 HandleControlCodes(U8 ch) {
switch (ch) { switch (ch) {
case 0: // NUL (Null) - Typically ignored case 0: // NUL (Null) - Typically ignored
break; break;
case 7: // BEL (Bell) case 7: // BEL (Bell)d
Beep; Beep;
break; break;
case 8: // BS (Backspace) case 8: // BS (Backspace)
@ -85,9 +84,13 @@ U0 HandleControlCodes(U8 ch) {
break; break;
case 10: // LF (Line Feed) case 10: // LF (Line Feed)
term.cursor_y++; term.cursor_y++;
// if (term.cursor_y >= term.window_height) { if (term.cursor_y >= term.window_height) {
// term.cursor_y = 0; // reset Y position to 0 when it exceeds window height // DocClear(term.doc);
// }
// DCFill(DCAlias,BLACK);
// term.cursor_x = 0;
term.cursor_y = 0; // reset Y position to 0 when it exceeds window height
}
// If the next character is CR, ignore it // If the next character is CR, ignore it
// TODO: dont directly manipulate the buffer // TODO: dont directly manipulate the buffer
// if (*(term.buffer + 1) == 13) term.buffer++; // if (*(term.buffer + 1) == 13) term.buffer++;
@ -96,9 +99,10 @@ U0 HandleControlCodes(U8 ch) {
SysLog("Vertical Tab\n"); SysLog("Vertical Tab\n");
break; break;
case 12: // FF (Form Feed) case 12: // FF (Form Feed)
DocClear(term.doc); // DocClear(term.doc);
// term.cursor_x = 0; // DCFill(DCAlias,BLACK);
// term.cursor_y = 0; term.cursor_x = 0;
term.cursor_y = 0;
break; break;
case 13: // CR (Carriage Return) case 13: // CR (Carriage Return)
term.cursor_x = 0; term.cursor_x = 0;
@ -176,7 +180,8 @@ U0 HandleControlCodes(U8 ch) {
U0 TerminalDrawIt(CTask *task, CDC *dc) U0 TerminalDrawIt(CTask *task, CDC *dc)
{ {
// Clear the document // Clear the document
// DocClear; // DocClear(term.doc);
DCFill(dc,BLUE);
I64 row, col; I64 row, col;
// Loop over the screen array and draw each character // Loop over the screen array and draw each character
@ -196,11 +201,11 @@ U0 TerminalDrawIt(CTask *task, CDC *dc)
} }
} }
// Draw the cursor // Draw the curso
// Note: this draws the cursor as a white rectangle. You may want to customize this. // Note: this draws the cursor as a white rectangle. You may want to customize this.
// term.dc->color = WHITE; // dc->color = WHITE;
// GrRect(term.dc, term.cursor_x * CHAR_WIDTH, term.cursor_y * CHAR_HEIGHT, // GrRect(dc, term.cursor_x * 8, term.cursor_y * 8,
// (term.cursor_x + 1) * CHAR_WIDTH - 1, (term.cursor_y + 1) * CHAR_HEIGHT - 1); // (term.cursor_x + 1) * 8 - 1, (term.cursor_y + 1) * 8 - 1);
} }
U0 TerminalTask() { U0 TerminalTask() {
@ -309,8 +314,7 @@ U0 TerminalTask() {
ptr++; ptr++;
break; break;
case 'm': case 'm':
// colors might be printed in the wrong order? // Set graphics mode (colors)
// like, <Esc>[1;40m and now <Esc>[40m;1m
I64 m; I64 m;
Bool isBright = FALSE; Bool isBright = FALSE;
for (m = 0; m <= ansi_param_count; m++) { for (m = 0; m <= ansi_param_count; m++) {
@ -556,15 +560,13 @@ U0 TerminalTask() {
} }
// SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count); // SysLog("H or f AFTER row:%d, col:%d, cnt:%d\n", row, col, ansi_param_count);
if (row >= term.window_height) if (row > term.window_height)
row = term.window_height; row = term.window_height - 1;
if (col >= term.window_width) if (col > term.window_width)
col = term.window_width; col = term.window_width - 1;
// "$$CM,0,0$$"; // "$$CM,0,0$$";
// term.cursor_x = col-1; term.cursor_x = col-1;
// term.cursor_y = row-1; term.cursor_y = row-1;
term.cursor_x = col;
term.cursor_y = row;
ptr++; ptr++;
break; break;
case 'J': case 'J':
@ -578,9 +580,11 @@ U0 TerminalTask() {
// DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE); // DocDelToEntry(Fs->display_doc, Fs->display_doc->cur_entry, FALSE);
} else if (ansi_code[0] == 2) { } else if (ansi_code[0] == 2) {
// Erase entire display // Erase entire display
DocClear(term.doc); // DocClear(term.doc);
term.cursor_x = 0; // DCFill(dc,BLACK);
term.cursor_y = 0; // term.cursor_x = 0;
// term.cursor_y = 0;
// redraw_needed = TRUE;
} }
ptr++; ptr++;
break; break;
@ -692,10 +696,12 @@ U0 TerminalTask() {
} }
if (redraw_needed) { if (redraw_needed) {
// TerminalDrawIt(term.task, term.task); // TerminalDrawIt(term.task, term.task);
DocClear(term.doc); // DocClear(term.doc);
term.cursor_x = 0;
term.cursor_y = 0; // DCFill(,RED);
redraw_needed = TRUE; // term.cursor_x = 0;
// term.cursor_y = 0;
redraw_needed = FALSE;
} }
} else { } else {
"Error: Connection closed by the remote host.\n"; "Error: Connection closed by the remote host.\n";