marlene/fctelnet.c

383 lines
6.8 KiB
C

#include <tcpip.h>
#include <Locator.h>
#include <Memory.h>
#include <texttool.h>
#include <gsos.h>
#include <Event.h>
#include <fcntl.h>
#include <sgtty.h>
#include <errno.h>
#include <gno/gno.h>
#include <gno/kerntool.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/ioctl.compat.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "telnet.h"
extern void ClearScreen(void);
extern pascal void GrafOn(void) inline(0x0a04, dispatcher);
extern pascal void GrafOff(void) inline(0x0b04, dispatcher);
extern pascal void SetColorTable(Word, ColorTable) inline(0x0E04,dispatcher);
extern pascal void SysBeep2(Word) inline(0x3803,dispatcher);
extern pascal void SetAllSCBs(Word) inline(0x1404,dispatcher);
extern pascal void SetMasterSCB(Word) inline(0x1604,dispatcher);
extern pascal void InitColorTable(ColorTable) inline(0x0D04,dispatcher);
Word ResolveHost(const char *name, cvtRecPtr cvt);
int WaitForStatus(word ipid, word status);
void display_pstr(const char *);
void display_cstr(const char *);
void display_err(Word);
extern void telnet_init(void);
extern void telnet_process(void);
extern void vt100_init(void);
extern void vt100_process(const unsigned char *buffer, unsigned buffer_size);
extern void vt100_event(EventRecord *event);
Word MyID;
Word __gno;
#define ESC "\x1b"
#pragma databank 1
/*
* called to print connect/disconnect messages from
* Marinetti. msg is a pstring.
*/
void printCallBack(const char *msg) {
if (msg && *msg) {
display_cstr(ESC "\n\r[1m"); // bold on
display_pstr(msg); // show the string
display_cstr(ESC "[0m\n\r"); // bold off
}
}
#pragma databank 0
static void screen_init(void) {
#define WHITE 0x0fff
#define YELLOW 0x0ff0
#define BLACK 0x0000
#define BLUE 0x000f
#define GREEN 0x00f0
#define RED 0x0f00
static ColorTable ct =
{
BLACK, // background
RED, // underline / blink
BLUE, // bold
GREEN, // foreground
BLACK,
RED,
BLUE,
GREEN,
BLACK,
RED,
BLUE,
GREEN,
BLACK,
RED,
BLUE,
GREEN,
};
unsigned i;
// linearize memory, disable shadowing.
asm
{
lda #0x00C1
sep #0x20
ora >0xe0c029
sta >0xe0c029
rep #0x20
lda #0x0008
sep #0x20
ora >0xe0c035
sta >0xe0c035
rep #0x20
}
SetMasterSCB(0xc080);
SetAllSCBs(0xc080);
//InitColorTable(ct);
for (i = 0; i < 16; i++)
SetColorTable(i, ct);
ClearScreen();
GrafOn();
}
static char out_buffer[1024];
static char out_buffer_size = 0;
static word ipid = -1;
static void flush(void) {
if (out_buffer_size) {
TCPIPWriteTCP(ipid, out_buffer, out_buffer_size, true, false);
out_buffer_size = 0;
}
}
void send(char *data, unsigned size) {
if (out_buffer_size + size > sizeof(out_buffer)) {
flush();
}
if (size > sizeof(out_buffer) / 2) {
TCPIPWriteTCP(ipid, data, size, true, false);
return;
}
memcpy(out_buffer + out_buffer_size, data, size);
out_buffer_size += size;
}
unsigned buffer_size;
unsigned char buffer[2048]; // 1500 is normal MTU size?
int main(int argc, char **argv) {
static EventRecord event;
static rrBuff rr;
static char str[16];
static cvtRec cvt;
static QuitRecGS qDCB = {2, 0, 0x4000};
Word iLoaded;
Word iConnected;
Word iStarted;
Handle dp;
Word err;
int ok;
iLoaded = iStarted = iConnected = false;
__gno = false;
ipid = -1;
MyID = MMStartUp();
kernStatus();
if (!_toolErr) __gno = true;
TextStartUp();
SetOutputDevice(1,3);
SetOutGlobals(0x7f, 0);
dp = NewHandle(0x0100, MyID,
attrBank | attrPage |attrNoCross | attrFixed | attrLocked,
0x000000);
EMStartUp((Word)*dp, 0x14, 0, 0, 0, 0, MyID);
// todo: -vt52 -> start in vt52 mode (DECANM = 0)
// todo:keypad flag of some sort?
if (argc != 2) {
ErrWriteCString("Usage: marlene host[:port]\r\n");
goto _exit;
}
screen_init();
vt100_init();
TCPIPStatus();
if (_toolErr) {
display_cstr("Loading Marinetti...\n\r");
LoadOneTool(0x36, 0x200); //load Marinetti
if (_toolErr) {
display_cstr("Unable to load Marinetti.\r\n");
goto _exit;
}
iLoaded = true;
}
// Marinetti now loaded
if (!TCPIPStatus()) {
display_cstr("Starting Marinetti...\n\r");
TCPIPStartUp();
iStarted = true;
}
if (!TCPIPGetConnectStatus()) {
display_cstr("Connecting Marinetti...\n\r");
TCPIPConnect(printCallBack);
if (_toolErr) {
display_cstr("Unable to establish network connection.\r\n");
goto _exit;
}
iConnected = true;
}
// marinetti is now connected
if (!ResolveHost(argv[1], &cvt)) {
display_cstr("Unable to resolve address.\r\n");
goto _exit;
}
if (!cvt.cvtPort) cvt.cvtPort = 23;
ipid = TCPIPLogin(MyID, cvt.cvtIPAddress, cvt.cvtPort, 0, 0x0040);
TCPIPConvertIPToCASCII(cvt.cvtIPAddress, str, 0);
display_cstr("Connecting to ");
display_cstr(str);
display_cstr("...\n\r");
TCPIPOpenTCP(ipid);
// wait for the connection to occur.
ok = WaitForStatus(ipid, TCPSESTABLISHED);
if (ok > 0) display_err(ok);
if (ok != 0) goto _exit2;
display_cstr("Connected.\n\r");
telnet_init();
//fd = open ("tcp.log", O_TRUNC | O_WRONLY | O_CREAT, 0777);
for(;;) {
static rrBuff rr;
TCPIPPoll();
rr.rrBuffCount = 0;
err = TCPIPReadTCP(ipid, 0, (Ref)buffer, sizeof(buffer), &rr);
// tcperrConClosing and tcperrClosing aren't fatal.
buffer_size = rr.rrBuffCount;
if (buffer_size) err = 0;
if (err) {
if (err == tcperrConClosing || err == tcperrClosing)
display_cstr("\r\nTCP Connection Closed.\r\n");
else
display_err(err);
goto _exit1;
}
if (buffer_size) {
telnet_process();
}
if (buffer_size) {
vt100_process(buffer, buffer_size);
}
GetNextEvent(keyDownMask | autoKeyMask, &event);
if (event.what == keyDownEvt) {
unsigned char key = event.message;
if (event.modifiers & appleKey) {
switch (key) {
case 'Q': // quit
case 'q':
goto _exit1;
break;
case 'V': // paste...
case 'v':
break;
case 'Z': // suspend (gnome)
case 'z':
if (__gno) {
static struct sgttyb sb;
static int err;
gtty(1,&sb);
sb.sg_flags &= ~RAW;
stty(1,&sb);
GrafOff();
Kkill(Kgetpid(), SIGSTOP, &err);
sb.sg_flags |= RAW;
stty(1,&sb);
GrafOn();
}
break;
}
} else {
vt100_event(&event);
}
}
flush();
}
_exit1:
flush();
display_cstr("\n\rClosing TCP Connection...\n\r");
TCPIPCloseTCP(ipid);
WaitForStatus(ipid, TCPSCLOSED);
_exit2:
_exit:
if (ipid != -1) TCPIPLogout(ipid);
if (iConnected)
TCPIPDisconnect(false, printCallBack);
if (iStarted)
TCPIPShutDown();
if (iLoaded)
UnloadOneTool(0x36);
// flush q
while (GetNextEvent(keyDownMask | autoKeyMask, &event)) ;
display_cstr("\n\rPress any key to exit.\n\r");
while (!GetNextEvent(keyDownMask | autoKeyMask, &event)) ;
EMShutDown();
DisposeHandle(dp);
GrafOff();
TextShutDown();
QuitGS(&qDCB);
return 0;
}