/* -> c.ckacon */ char *connv = "Arthur Connect Command (based on C-Kermit V4C(010)) 19 Dec 85"; /* C K A C O N -- Smart terminal emulation to remote system, for Arthur */ /* Author: Frank da Cruz (SY.FDC@CU20B), Columbia University Center for Computing Activities, January 1985. Copyright (C) 1985, Trustees of Columbia University in the City of New York. Permission is granted to any individual or institution to use, copy, or redistribute this software so long as it is not sold for profit, provided this copyright notice is retained. Arthur version: Richard Cownie/Acorn VLSI Tools Group (c) Acorn Computers Plc 1985 */ #include "ckcdeb.h" #include #include "ckcker.h" #ifdef ANSI #include "ckatio.h" #include "ckafio.h" #include "ckamis.h" #endif #ifdef ARTHUR #include "arthur.h" #include "plib.h" #include "tty.h" #endif /* parameters to be tuned for performance (NB may blow up if you go wrong) */ #define BUFSZ 2048 /* buffer up to BUFSZ chars */ #define BUFHI 1280 /* send ^S when we have this many chars pending */ #define BSIZE 32 /* grab <= BSIZE chars at a time from rs423 input */ #define LOTS 128 /* send ^S when rs423 buf contains > LOTS */ #define FEW 64 /* send ^Q when rs423 buf contains < FEW */ #define VSIZE 4 /* give <= VSIZE chars at a time to protocol handler */ #define keybf 0 #define rs423inbf 1 #define rs423outbf 2 #define CTRL_S 19 #define CTRL_Q 17 /* No buffering on output */ #define send(c) putinbf(rs423outbf, c) /* Current speed setting */ extern int speed; /* Current session log file descriptor and name */ extern int seslog; extern char sesfil[]; /****************************************************/ /* Procedures to do Unix termcap functions on ACW */ /****************************************************/ int rawvdu = -1; int lrawkb = -1; #ifdef ANSI void #endif vdus(s) char *s; { while(*s) XSWriteByte(rawvdu, *s++); } #undef vdu #define vdu(c) XSWriteByte(rawvdu, c) #ifdef ANSI void #endif bbc_wipe(lx,ly,ux,uy) int lx,ly,ux,uy; { if (lx > ux) return; if (ly < uy) return; vdu(28); vdu(lx); vdu(ly); vdu(ux); vdu(uy); vdu(12); vdu(26); } #ifdef ANSI void #endif term_cl() { vdu(12); } #ifdef ANSI void #endif term_bs() { vdu(8); } #ifdef ANSI void #endif term_cm(row,col) int row,col; { vdu(31); vdu(col); vdu(row); } #ifdef ANSI void #endif term_nd() { vdu(9); } #ifdef ANSI void #endif term_up() { vdu(11); } #ifdef ANSI void #endif term_ce() { /* clear to end of line: non-trivial */ int x, y; get_posn(&x, &y); bbc_wipe(x,y,79,y); term_cm(y,x); } #ifdef ANSI void #endif term_cd() { int x, y; get_posn(&x, &y); bbc_wipe(x,y,79,y); if (y < 31) bbc_wipe(0,31,79,y+1); term_cm(y,x); } #ifdef ANSI void #endif term_ta() { int x, y; get_posn(&x, &y); vdu(' '); while ((++x) % 8) vdu(' '); } #ifdef ANSI void #endif term_ho() { vdu(30); } #ifdef ANSI void #endif term_so() { vdu(17); vdu(0); vdu(17); vdu(129); } #ifdef ANSI void #endif term_se() { vdu(17); vdu(1); vdu(17); vdu(128); } /****************************************************/ /* State machine to filter VDU stream & tweak vdu */ /****************************************************/ #ifdef ANSI #undef NULL #endif #define NULL 0 /* initial state for the state machine */ static int emul_state, emul_x, emul_y, emul_len; static char emul_seq[32]; #ifdef ANSI void #endif emul_start() /* initialise terminal emulator */ { int j; reg_set rs; error *ret; /* * Open the kb as a stream, but bypass the stream library * and access it directly! */ lrawkb = XFindInput("RAWKB:",6); rawvdu = XFindOutput("RAWVDU:", 7); #ifdef VT52 mode(3); #endif /* set register 10 of 6845 video chip to 0 for big non-flashing cursor */ vdu(23); vdu(0); vdu(10); vdu(0x0); for (j = 0; j < 6; ++j) vdu(0); vdu(23); vdu(0); vdu(11); vdu(0x7); for (j = 0; j < 6; ++j) vdu(0); emul_state = NULL; emul_len = 0; /* Disable rs423 as output stream */ rs.r[0] = 3; rs.r[1] = 0; ret = osbyte( &rs ); /* Enable kb and rs423 as input */ rs.r[0] = 2; rs.r[1] = 2; ret = osbyte( &rs ); /* Set line speed */ setbaud( speed ); /* disable cursor editing and fn key nums to cursor and copy keys */ rs.r[0] = 4; rs.r[1] = 2; ret = osbyte( &rs ); /* Disable escape */ rs.r[0] = 229; rs.r[1] = 1; ret = osbyte( &rs ); rsintercept(); } #ifdef ANSI #undef CR #undef LF #undef ESC #endif #define CR 13 #define LF 10 #define ESC 27 #ifdef ANSI void #endif putseq() /* put an aborted sequence to vdu in readable form */ { int j,x; char c; for (j = 0; j < emul_len; j++) { c = emul_seq[j]; x = c; if (c < ' ') printf("[%x]", x); else vdu(c); } } #define next(s) { emul_state = s; return; } #define abort { putseq(); emul_len = 0; emul_state = NULL; return; } #define done { emul_len = 0; emul_state = NULL; return; } #define isdigit(c) (('0' <= c) && (c <= '9')) /*************************************/ /* A simple dumb terminal emulator */ /*************************************/ #ifdef DUMB #ifdef ANSI void #endif emul_inch(c) char c; /* deal with character received from line: dumb terminal */ { if (c >= 128) c -= 128; switch(c) { case 8: term_bs(); break; case 9: term_ta(); break; case CR: break; case LF: vdu(CR); vdu(LF); break; default: if (c >= ' ') vdu(c); } } #ifdef ANSI void #endif emul_outch(c) int c; /* send sequence corresponding to key press c on ACW keyboard */ /* sends ESC-0,..,ESC-9 for the function keys, ESC-A,...,ESC-D for the */ /* cursor keys, with control & shift adding an extra ESC- prefix each. */ { char *code = "0123456789 ]DCBA"; if (c < 128) { send(c); return; } while ( c >= 0x144 ) { send(ESC); c -= 16; } send(ESC); send(code[c-128]); inter(); } #endif /*************************************/ /* End of dumb terminal emulator */ /*************************************/ #ifdef VT52 #define emul_inch VT52_inch #define emul_outch VT52_outch /********************************************************************/ /* An example of a smart terminal emulator, for those who want to */ /* hack emulators for the terminal of their choice. This one does */ /* a subset of VT52 as defined by the BSD 4.2 Unix termcap file, */ /* together with inverse video highlighting. */ /********************************************************************/ /* First define states of the machine to be used to interpret codes */ #define SESC 1 #define SBRA 2 #define SO1 3 #define GETY 4 #define GETX 5 #define CL1 6 #define CL2 7 /* Respond to UNIX ttytype */ void answer(void) { sendchar(ESC); sendchar('/'); sendchar('Z'); inter(); } /* Now the interpreter itself */ #ifdef ANSI void #endif VT52_inch(c) char c; /* deal with char c received from line: VT52 emulation */ { if (c >= 128) c -= 128; emul_seq[emul_len++] = c; switch(emul_state) { case NULL: switch(c) { case ESC: next(SESC); case 9: term_ta(); done; default: vdu(c); if(seslog) zchout(ZSFILE,c); /* session logging */ done; } case SESC: switch(c) { case 'A': term_up(); done; case 'C': term_nd(); done; case 'J': term_cd(); done; case 'K': term_ce(); done; case 'H': next(CL1); case 'Y': next(GETY); case '[': next(SBRA); case '>': term_ce(); done; default: abort; } case SBRA: switch(c) { case '4': case '7': next(SO1); case 'c': answer(); case 'm': term_se(); done; default : abort; } case SO1: if (c == 'm') { term_so(); done; } else abort; case GETY: emul_y = (c - ' '); next(GETX); case GETX: emul_x = (c - ' '); term_cm(emul_y, emul_x); done; case CL1: if (c == ESC) { next(CL2); } else abort; case CL2: if (c == 'J') { term_cl(); done; } else abort; default: abort; } } void linebreak(void) { reg_set rs; error *ret; rs.r[0] = 156; rs.r[1] = 0x60; rs.r[2] = 0x9f; ret = osbyte( &rs ); rs.r[0] = 19; ret = osbyte( &rs ); ret = osbyte( &rs ); ret = osbyte( &rs ); rs.r[0] = 156; rs.r[1] = 0x20; rs.r[2] = 0x9f; ret = osbyte( &rs ); } #ifdef ANSI void #endif VT52_outch(c) int c; /* send sequence corresponding to key press c */ /* this generates some bizarre non-standard escape sequences copied */ /* from a terminal ROM developed for in-house use at ACORN. */ { char *code = "<>,.45O78J ]DCBA"; if( c == 169 ) { /* CTL-F9 Sends a line break */ linebreak(); return; } if (c < 128) { send(c); return; } while (c >= 144) { send(ESC); c -= 16; } send(ESC); if( c != 128 ) send(code[c-128]); inter(); } /**************************/ /* End of VT52 emulator */ /**************************/ #endif #ifdef ANSI void #endif emul_finish() /* finish terminal emulation & tidy up */ { #ifdef ARTHUR int j; reg_set rs; error *ret; /* set register 10 of 6845 video chip to 0 for big non-flashing cursor */ vdu(23); vdu(0); vdu(10); vdu(0x67); for (j = 0; j < 6; ++j) vdu(0); rs.r[0] = 2; rs.r[1] = 0; ret = osbyte( &rs ); rs.r[0] = 4; rs.r[1] = 0; ret = osbyte( &rs ); /* enable cursor editing and fn key nums to cursor and copy keys */ rs.r[0] = 4; rs.r[1] = 0; ret = osbyte( &rs ); /* Disable escape */ rs.r[0] = 229; rs.r[1] = 0; ret = osbyte( &rs ); rsrelease(); mode(0); XCloseStream( rawvdu ); XCloseStream( lrawkb ); #endif } /**************************************************/ /* C O N E C T -- Perform terminal connection */ /**************************************************/ #define END_KEY 161 /* Key value to end terminal session */ #ifdef ANSI int #endif conect() { int key,max,min,block,doneCtrlS,ok,userok; int head = 0, tail = 0, size = 0; char buf[BUFSZ]; printf("\nYou are now connected to your host computer\n"); printf("Press F1 to return to local kermit\n\n"); if(seslog) printf("(Session logged to %s)\n",sesfil); initrs(); emul_start(); send(CR); inter(); doneCtrlS = 1; ok = userok = 1; max = min = 0; for (;;) { if (doneCtrlS) { if (min+size < FEW) ok = 1; if (ok && userok) { send(CTRL_Q); inter(); doneCtrlS = 0; } } else if ((min+size == 0) || (max > FEW)) { min = nrsbuf(); if ((min > LOTS) || (size > BUFHI)) ok = 0; if (! (ok && userok)) { send(CTRL_S); inter(); doneCtrlS = 1; } } block = min; if (block > BSIZE) block = BSIZE; while (block--) { /* get chars from rs423 buffer */ testbf(rs423inbf, &key); min--; buf[tail] = key; ++size; if (++tail >= BUFSZ) tail = 0; } block = size; if (block > VSIZE) block = VSIZE; max = min + LOTS; /* chars may be coming */ while (block--) { /* hand chars to protocol interpreter */ emul_inch(buf[head]); --size; if (++head >= BUFSZ) head = 0; } if (testbf(keybf, &key)) { /* have a key press */ if (key == END_KEY) { termrs(); emul_finish(); printf("\nReturn to Arthur-Kermit.\n"); return(1); } else if (key == CTRL_S) userok = 0; else if (key == CTRL_Q) userok = 1; else if (key >= 127) emul_outch(key); else send(key); inter(); } } } /*****************************************************/ /* H C O N N E -- Give help message for connect. */ /*****************************************************/ #ifdef ANSI int #endif hconne() { int c; static char *hlpmsg[] = { "\r\n C to close the connection, or:", "\r\n S for status", "\r\n ? for help", "\r\n B to send a BREAK", "\r\n 0 to send a null", "\r\n escape character twice to send the escape character.\r\n\r\n", "" }; conola(hlpmsg); /* Print the help message. */ conol("Command> "); /* Prompt for command. */ c = coninc(0); conoc(c); /* Echo it. */ conoll(""); c &= 0177; /* Strip any parity. */ return(c); /* Return it. */ } /***************************************************************/ /* C H S T R -- Make a printable string out of a character */ /***************************************************************/ char * chstr(c) int c; { static char s[8]; char *cp = s; if (c < SP) { sprintf(cp,"CTRL-%c",ctl(c)); } else sprintf(cp,"'%c'\n",c); cp = s; return(cp); } /*********************************************************/ /* D O E S C -- Process an escape character argument */ /*********************************************************/ #ifdef ANSI void #endif doesc(c) char c; {}