char *connv = "OS/2 CONNECT command 5A(103), 16 May 93"; /* C K O C O N -- Kermit connect command for OS/2 systems */ /* Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), Columbia University Academic Information Systems, New York City. Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New York. The C-Kermit software may not be, in whole or in part, licensed or sold for profit as a software product itself, nor may it be included in or distributed with commercial products or otherwise distributed by commercial concerns to their clients or customers without written permission of the Office of Kermit Development and Distribution, Columbia University. This copyright notice must not be removed, altered, or obscured. Originally adapted to OS/2 by Chris Adie (C.Adie@uk.ac.edinburgh), 1988. VT terminal emulator originally by Chris Adie, 1988 ("If the code looks a bit funny sometimes, it's because it was machine translated to C.") Many changes for 5A by Kai Uwe Rommel (rommel@informatik.tu-muenchen.de), 1992-93. And more by Frank da Cruz (fdc@columbia.edu), mostly bug fixes (tabs, cursor/attributes save/restore, keypad modes, etc), hooking into new SET TERMINAL commands, TCP/IP TELNET support, and cosmetic, 1992-93. */ /* * * =============================#includes===================================== */ #include "ckcdeb.h" /* Typedefs, debug formats, etc */ #include "ckcker.h" /* Kermit definitions */ #include "ckcasc.h" /* ASCII character symbols */ #include "ckcxla.h" /* Character set translation */ #include "ckcnet.h" /* Network support */ #include "ckuusr.h" /* For terminal type definitions, etc. */ #include /* Character types */ #include /* File io function declarations */ #include /* Process-control function declarations */ #include /* Standard library declarations */ #include #include #include #include #include #ifndef __32BIT__ #define far _far #define near _near #define pascal _pascal #endif #define INCL_NOPM #define INCL_VIO #define INCL_DOSPROCESS #define INCL_DOSSEMAPHORES #include #undef COMMENT #ifndef min #define min(a,b) ((a) <= (b) ? (a) : (b)) #endif /* * * =============================#defines====================================== */ #ifdef TRUE #undef TRUE #endif /* TRUE */ #define TRUE 1 #ifdef FALSE #undef FALSE #endif /* FALSE */ #define FALSE 0 #define UPWARD 6 #define DOWNWARD 7 #define LBUFSIZE paginginfo.bufsize /* Number of lines in extended buffer (was a constant previosly) */ #define DEFTABS \ "0T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000T0000000\ T0000000T0000000T0000000T0000000T0000000T0000000T0000000T000"; /* * * =============================typedefs====================================== */ typedef char fulstring[256]; typedef int bool; typedef struct ascreen_rec { /* Structure for saving screen info */ unsigned char ox; unsigned char oy; unsigned char att; char *scrncpy; } ascreen; /* * * =============================externals===================================== */ extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set xlate */ extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* functions. */ extern int language; /* Current language. */ extern struct langinfo langs[]; /* Language info. */ extern struct csinfo fcsinfo[]; /* File character set info */ extern int tcsr, tcsl; /* Terminal character sets, remote & local. */ extern int tnlm, tn_nlm; /* Terminal newline mode, ditto for TELNET */ extern int tt_crd; /* Carriage-return display mode */ extern long speed; extern int local, escape, duplex, parity, flow, seslog, sessft, cmdmsk, cmask, sosi, xitsta, debses, mdmtyp, carrier; extern int network, nettype, ttnproto; extern KEY *keymap; extern MACRO *macrotab; extern char ttname[], sesfil[]; extern void cc_trap(); /* * * =============================variables============================== */ #ifdef MONO int colornormal = 0x07; int colorunderline = 0x01; int colorreverse = 0x70; int colorstatus = 0x70; int colorhelp = 0x70; #else int colornormal = 0x30; int colorunderline = 0x3E; int colorreverse = 0x70; int colorstatus = 0x74; int colorhelp = 0x27; #endif int colorcmd; int scrninitialised; static long twochartimes; static char termessage[132]; static FILE *lst = NULL; static bool lstclosed = TRUE; static int xsize = -1, ysize = -1; static ascreen vt100screen, commandscreen, savedscreen; static unsigned char attribute = NUL, savedattribute = NUL, defaultattribute = NUL; static struct { unsigned reversed:1; unsigned blinking:1; unsigned underlined:1; unsigned bold:1; unsigned invisible:1; } attrib, savedattrib; static struct paging_record { int numlines; /* no. of lines in extended display buffer */ int topline; int botline; char *buffer; int bufsize; } paginginfo; static int wherex; /* X-coordinate, 1-based */ static int wherey; /* Y-coordinate, 1-based */ static int margintop = 1; /* Top of scrolling region */ static int marginbot = 24; /* Bottom of scrolling region */ static int active, quitnow, hangnow, inshift, outshift, tcs, langsv; static char answerback[81] = "OS/2 C-Kermit\n"; static char usertext[(132) + 1]; static char exittext[(20) + 1]; static char helptext[(20) + 1]; static char filetext[(20) + 1]; static char hostname[(20) + 1]; static unsigned char graphicset[32] = { 0x20, 0x04, 0xB0, 0x1A, 0x17, 0x1B, 0x19, 0xF8, 0xF1, 0x15, 0x12, 0xD9, 0xBF, 0xDA, 0xC0, 0xC5, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC3, 0xB4, 0xC1, 0xC2, 0xB3, 0xF3, 0xF2, 0xE3, 0x9D, 0x9C, 0xFA }; static char htab[133] = DEFTABS /* Default tab settings */ static VIOCURSORINFO crsr_command; static VIOCURSORINFO crsr_info; static int row = 0; static int column = 0; static int achar; static unsigned char g0 = 'B'; static unsigned char g1 = 'B'; static unsigned char *g0g1 = &g0; static bool printon = FALSE; /* Printer is on */ static bool turnonprinter = FALSE; /* Time to turn on printer */ static bool turnoffprinter = FALSE; /* Time to turn it off */ static bool wrapit; static bool literal = FALSE; static bool screenon = TRUE; static bool cursoron = TRUE; /* For speed, turn off when busy */ static bool relcursor = FALSE; static bool keylock = FALSE; static bool vt52graphics = FALSE; static unsigned char saveg0, saveg1, *saveg0g1; static bool saverelcursor, saved=FALSE; static bool dwl[60]; static bool dwls = FALSE; /* For optimisation */ static bool deccolm = FALSE; static bool decscnm = FALSE; static bool linemode = FALSE; static bool insertmode = FALSE; /* Terminal parameters that can also be set externally by SET commands. Formerly they were declared and initialized here, and had different names, as shown in the comments. Now they are declared and initialized in ckuus7.c. - fdc */ extern int tt_arrow; /* cursorkey = TRUE; */ extern int tt_keypad; /* keypadnum = FALSE; */ extern int tt_wrap; /* autowrap = TRUE; */ extern int tt_type; /* ansi = TRUE; */ extern int tt_cursor; /* cursormode = 0; */ extern int tt_answer; /* answerback = TRUE; */ extern int tt_scrsize; /* screensize */ /* Escape-sequence processing buffer */ static bool escaping = FALSE; static int escnext = 1; static int esclast = 0; static unsigned char escbuffer[129]; static unsigned char sgrcols[8] = {0, 4, 2, 6, 1, 5, 3, 7}; /* Function prototypes */ static CHAR (*sxo)(CHAR); /* Local translation functions */ static CHAR (*rxo)(CHAR); /* for output (sending) terminal chars */ static CHAR (*sxi)(CHAR); /* and for input (receiving) terminal chars. */ static CHAR (*rxi)(CHAR); int ttoci(char c); int line25(void); int lgotoxy(int x, int y); int scroll(int updown, int top, int bottom, int nlines); int clearscreen(int all, int attr); int setmargins(int top, int bot); int sendstr(char *s); int wrtch(char ch); int bleep(void); int movetoscreen(char *source, int x, int y, int len); int savescreen(ascreen *scrn); int restorescreen(ascreen *scrn); int clrtoeoln(void); int killcursor(void); int newcursor(void); int cwrite(unsigned char ch); int toplinetocyclicbuffer(void); int setcursormode(void); int restorecursormode(void); extern int concooked(void); extern int conraw(void); extern int xxesc(char **); /* thread stuff */ #ifdef __32BIT__ HEV threadsem; ULONG semcount; #define THRDSTKSIZ 8192 #else static long int threadsem; /* Semaphore to show thread is running */ #define THRDSTKSIZ 2048 static char stack[THRDSTKSIZ]; /* Stack for second thread */ #endif static TID threadid; /* skip escape sequences */ /* for comments, see ckucon.c, where this code is copied from */ #define ES_NORMAL 0 /* Normal, not in escape sequence */ #define ES_GOTESC 1 /* Current character is ESC */ #define ES_ESCSEQ 2 /* Inside an escape sequence */ #define ES_GOTCSI 3 /* Inside a control sequence */ #define ES_STRING 4 /* Inside DCS,OSC,PM, or APC string */ #define ES_TERMIN 5 /* 1st char of string terminator */ static int iskipesc = 0, /* Skip over ANSI escape sequences */ oskipesc = 0, inesc = ES_NORMAL, /* State of sequence recognizer */ outesc = ES_NORMAL; int chkaes(int esc, char c) { if (c == CAN || c == SUB) /* CAN and SUB cancel any sequence */ esc = ES_NORMAL; else /* Otherwise */ switch (esc) { /* enter state switcher */ case ES_NORMAL: /* NORMAL state */ if (c == ESC) /* Got an ESC */ esc = ES_GOTESC; /* Change state to GOTESC */ break; /* Otherwise stay in NORMAL state */ case ES_GOTESC: /* GOTESC state */ if (c == '[') /* Left bracket after ESC is CSI */ esc = ES_GOTCSI; /* Change to GOTCSI state */ else if (c > 057 && c < 0177) /* Final character '0' thru '~' */ esc = ES_NORMAL; /* Back to normal */ else if (c == 'P' || (c > 0134 && c < 0140)) /* P, [, ^, or _ */ esc = ES_STRING; /* Switch to STRING-absorption state */ else if (c != ESC) /* ESC in an escape sequence... */ esc = ES_ESCSEQ; /* starts a new escape sequence */ break; /* Intermediate or ignored ctrl char */ case ES_ESCSEQ: /* ESCSEQ -- in an escape sequence */ if (c > 057 && c < 0177) /* Final character '0' thru '~' */ esc = ES_NORMAL; /* Return to NORMAL state. */ else if (c == ESC) /* ESC ... */ esc = ES_GOTESC; /* starts a new escape sequence */ break; /* Intermediate or ignored ctrl char */ case ES_GOTCSI: /* GOTCSI -- In a control sequence */ if (c > 077 && c < 0177) /* Final character '@' thru '~' */ esc = ES_NORMAL; /* Return to NORMAL. */ else if (c == ESC) /* ESC ... */ esc = ES_GOTESC; /* starts over. */ break; /* Intermediate or ignored ctrl char */ case ES_STRING: /* Inside a string */ if (c == ESC) /* ESC may be 1st char of terminator */ esc = ES_TERMIN; /* Go see. */ break; /* Absorb all other characters. */ case ES_TERMIN: /* May have a string terminator */ if (c == '\\') /* which must be backslash */ esc = ES_NORMAL; /* If so, back to NORMAL */ else /* Otherwise */ esc = ES_STRING; /* Back to string absorption. */ } return(esc); } /* end code to skip escape sequences */ /* * Send a character to the serial line in immediate mode, checking to avoid * overwriting a character already waiting to be sent. */ sendchar(unsigned char c) { int i=0; while (ttoci(dopar(c))<0 && i++<10) DosSleep(twochartimes); if (i>=10) { active = FALSE; strcpy(termessage,network ? "Cannot transmit to network link.\n" : "Cannot transmit to serial port.\n"); } } /* ------------------------------------------------------------------ */ /* ipadl25 - */ /* ------------------------------------------------------------------ */ ipadl25() { int i, j, n; char *s; if (tt_type == TT_VT102) strcpy(usertext, " C-Kermit VT-102"); else if (tt_type == TT_VT52) strcpy(usertext, " C-Kermit VT-52"); else strcpy(usertext, " C-Kermit"); if ( !network ) sprintf(filetext, "Async %ld", speed); else switch ( nettype ) { case NET_DEC: switch ( ttnproto ) { case NP_LAT: strcpy(filetext, "DECnet LAT"); break; case NP_CTERM: strcpy(filetext, "DECnet CTERM"); break; default: strcpy(filetext, "DECnet"); break; } break; case NET_TCPB: switch ( ttnproto ) { case NP_TELNET: strcpy(filetext, "TCP/IP Telnet"); break; default: strcpy(filetext, "TCP/IP"); break; } break; case NET_PIPE: strcpy(filetext, "Named Pipe"); break; } strcpy(helptext, "Help: Alt-?"); strcpy(exittext, "Return: Alt-X"); strcpy(hostname, ttname); if (!network) strupr(hostname); line25(); } /* ------------------------------------------------------------------ */ /* CursorUp - */ /* ------------------------------------------------------------------ */ static void cursorup() { if ((relcursor ? margintop : 1) != wherey) lgotoxy(wherex, wherey - 1); } /* ------------------------------------------------------------------ */ /* CursorDown - */ /* ------------------------------------------------------------------ */ static void cursordown() { if ((relcursor ? marginbot : ysize) != wherey) lgotoxy(wherex, wherey + 1); } /* ------------------------------------------------------------------ */ /* CursorRight - */ /* ------------------------------------------------------------------ */ static void cursorright() { if (wherex < (dwl[wherey - 1] ? xsize - 1 : xsize)) lgotoxy(wherex + 1, wherey); } /* ------------------------------------------------------------------ */ /* CursorLeft - */ /* ------------------------------------------------------------------ */ static void cursorleft() { if (wherex > 1) lgotoxy(wherex - 1, wherey); } /* ------------------------------------------------------------------ */ /* ReverseScreen */ /* ------------------------------------------------------------------ */ static void reversescreen() { unsigned char back; unsigned char fore; int i, r, c; USHORT n; unsigned char cell[132 * 2]; n = sizeof(cell); for (r = 0; r < ysize; r++) { /* flip row */ VioReadCellStr(cell, &n, r, 0, 0); for (c = 1; c < n; c += 2) { /* do each cell in row */ back = (cell[c] & 0x70) >> 4; fore = (cell[c] & 0x07); if (cell[c] == colorunderline) cell[c] ^= 0x70; else cell[c] = (cell[c] & 0x88) | fore << 4 | back; } VioWrtCellStr(cell, n, r, 0, 0); } } /* ----------------------------------------------------------------- */ /* ClrScreen - */ /* ----------------------------------------------------------------- */ static void clrscreen() { int i, j; int nlines; USHORT n; char cells[132 * 2]; /* copy lines on screen to extended display buffer */ n = xsize * 2; for (i = ysize - 1; i >= 0; i--) { VioReadCellStr((char *) cells, &n, i, 0, 0); for (j = 0; j < xsize; j++) { if (cells[j * 2] != ' ') break; } if (j < xsize) break; } nlines = i; /* no. of nonblank lines-1 */ for (i = 0; i <= nlines; ++i) { paginginfo.botline = (paginginfo.botline + 1) % LBUFSIZE; if (paginginfo.numlines < LBUFSIZE) paginginfo.numlines++; else paginginfo.topline = (paginginfo.topline + 1) % LBUFSIZE; VioReadCellStr((paginginfo.buffer + xsize * 2 * paginginfo.botline), &n, i, 0, 0); } for (i = 0; i < ysize; i++) dwl[i] = FALSE; dwls = FALSE; clearscreen(0, attribute); } static void readmchar_escape() { /* Stores character in achar directly */ if (escnext <= esclast) { achar = escbuffer[escnext]; escnext = escnext + 1; } else achar = 0; } static int pnumber(int *achar) { int num = 0; while (isdigit(*achar)) { /* get number */ num = (num * 10) + (*achar) - 48; readmchar_escape(); } return (num); } static void clreoscr_escape() { char cell[2]; int i; if (wherex == 1 && wherey == 1) { clrscreen(); return; } cell[0] = ' '; cell[1] = attribute; i = (xsize * ysize) - (((wherey - 1) * xsize) + (wherex - 1)); VioWrtNCell(cell, i, wherey - 1, wherex - 1, 0); for (i = wherey - 1; i < ysize; i++) dwl[i] = FALSE; dwls = FALSE; for (i = 0; i < ysize; i++) if (dwl[i]) { dwls = TRUE; break; } } static void clrboscr_escape() { char cell[2]; int i; cell[0] = ' '; cell[1] = attribute; i = ((wherey - 1) * xsize) + wherex; VioWrtNCell(cell, i, 0, 0, 0); for (i = 0; i < wherey; i++) dwl[i] = FALSE; dwls = FALSE; for (i = 0; i < ysize; i++) if (dwl[i]) { dwls = TRUE; break; } } static void clrbol_escape() { char cell[2]; cell[0] = ' '; cell[1] = attribute; VioWrtNCell(cell, wherex, wherey - 1, 0, 0); } static void clrline_escape() { char cell[2]; cell[0] = ' '; cell[1] = attribute; VioWrtNCell(cell, xsize, wherey - 1, 0, 0); } static void decdwl_escape(bool dwlflag) { unsigned char linenumber; unsigned char newx; char cells[132 * 2]; int i; USHORT n; /* Decdwl */ linenumber = wherey - 1; if (dwlflag != dwl[linenumber]) { /* change size */ n = xsize * 2; VioReadCellStr((char *) cells, &n, linenumber, 0, 0); if (dwlflag) { /* make this line double size */ for (i = xsize / 2 - 1; i >= 0; --i) { /* expand */ cells[4 * i] = cells[2 *i]; cells[4 * i + 2] = ' '; } newx = (wherex - 1) * 2 + 1; dwls = TRUE; } else { /* make this line single size */ for (i = 0; i <= xsize / 2 - 1; ++i) cells[2 * i] = cells[4 * i]; for (i = xsize / 2; i < xsize; ++i) cells[2 * i] = ' '; newx = (wherex - 1) / 2 + 1; dwls = FALSE; for (i = 0; i < ysize; i++) if (dwl[i]) { dwls = TRUE; break; } } VioWrtCellStr((char *) cells, n, linenumber, 0, 0); dwl[linenumber] = dwlflag; if (newx >= xsize) newx = xsize - 1; lgotoxy(newx, wherey); } } static void /* Reset the terminal emulator */ doreset() { int i; defaultattribute = colornormal; attribute = defaultattribute; attrib.blinking = FALSE; attrib.bold = FALSE; attrib.invisible = FALSE; attrib.underlined = FALSE; attrib.reversed = FALSE; g0 = g1 = 'A'; g0g1 = &g0; printon = FALSE; screenon = TRUE; vt52graphics = FALSE; saved = FALSE; linemode = FALSE; insertmode = FALSE; tt_arrow = TRUE; tt_keypad = FALSE; tt_wrap = TRUE; tt_type = TT_VT102; keylock = FALSE; deccolm = decscnm = FALSE; for (i = 0; i < ysize; i++) dwl[i] = FALSE; dwls = FALSE; for (i = 1; i < xsize; i++) htab[i] = (i % 8) == 1 ? 'T' : '0'; /* was "== 0" */ relcursor = FALSE; setmargins(1, ysize); clrscreen(); } static void vtescape() { unsigned char j; unsigned char k; unsigned char l; unsigned char blankcell[2]; int i; int pn[11]; bool private; char tempstr[20]; int fore, back; escaping = FALSE; escnext = 1; readmchar_escape(); if (screenon || (achar == '[')) { /* screen escape sequences */ switch (achar) { /* First Level */ case '[': { /* Left square bracket */ readmchar_escape(); switch (achar) { /* Second level */ case 'A': cursorup(); wrapit = FALSE; break; case 'B': cursordown(); wrapit = FALSE; break; case 'C': cursorright(); if (dwl[wherey - 1]) cursorright(); break; case 'D': cursorleft(); if (dwl[wherey - 1]) cursorleft(); break; case 'J': /* Erase End of Display */ clreoscr_escape(); break; case 'K': clrtoeoln(); break; case '?': private = TRUE; readmchar_escape(); goto LB2001; case 'f': case 'H': /* Cursor Home */ lgotoxy(1, relcursor ? margintop : 1); break; case 'g': /* Tab Clear at this position */ htab[wherex] = '0'; break; case '}': case 'm': /* Normal Video - Exit all attribute modes */ attribute = defaultattribute; attrib.blinking = FALSE; attrib.bold = FALSE; attrib.invisible = FALSE; attrib.underlined = FALSE; attrib.reversed = FALSE; break; case 'r': /* Reset Margin */ setmargins(1, ysize); lgotoxy(1, 1); break; case 'c': case 'h': case 'l': case 'n': case 'x': pn[1] = 0; private = FALSE; k = 1; goto LB2003; case ';': pn[1] = 0; private = FALSE; k = 1; goto LB2002; case 'L': case 'M': case '@': case 'P': pn[1] = 1; private = FALSE; k = 1; goto LB2002; default: /* Pn - got a number */ private = FALSE; LB2001: { /* Esc [ Pn...Pn x functions */ pn[1] = pnumber(&achar); k = 1; LB2002: while (achar == ';') { /* get Pn[k] */ readmchar_escape(); k++; if (achar == '?') { readmchar_escape(); } pn[k] = pnumber(&achar); } pn[k + 1] = 1; LB2003: switch (achar) { /* Third level */ case 'A': do { cursorup(); wrapit = FALSE; pn[1] = pn[1] - 1; } while (!(pn[1] <= 0)); break; case 'B': do { cursordown(); wrapit = FALSE; pn[1] = pn[1] - 1; } while (!(pn[1] <= 0)); break; case 'C': do { cursorright(); if (dwl[wherey - 1]) cursorright(); pn[1] = pn[1] - 1; } while (pn[1] > 0); break; case 'D': do { cursorleft(); if (dwl[wherey - 1]) cursorleft(); pn[1] = pn[1] - 1; } while (pn[1] > 0); break; case 'f': case 'H': /* Direct cursor address */ if (pn[1] == 0) pn[1] = 1; if (relcursor) pn[1] += margintop - 1; if (pn[1] > ysize) pn[1] = ysize; if (pn[2] == 0) pn[2] = 1; if (dwl[pn[1] - 1]) { pn[2] = 2 * pn[2] - 1; if (pn[2] > xsize) pn[2] = xsize - 1; } else if (pn[2] > xsize) pn[2] = xsize; wrapit = FALSE; lgotoxy(pn[2], pn[1]); break; case 'c': /* Device Attributes */ if (pn[1] == 0) sendstr("[?6c"); break; case 'g': if (pn[1] == 3) { /* clear all tabs */ for (j = 1; j <=xsize; ++j) htab[j] = '0'; } else if (pn[1] == 0) /* clear tab at current position */ htab[wherex] = '0'; break; case 'h': /* Set Mode */ for (j = 1; j <= k; ++j) if (private) switch (pn[j]) { /* Field specs */ case 1: /* DECCKM */ tt_arrow = TRUE; break; case 2: /* DECANM : ANSI/VT52 */ tt_type = TT_VT102; vt52graphics = FALSE; break; case 3: /* DECCOLM : Col = 132 */ deccolm = TRUE; clrscreen(); break; case 4: /* DECSCLM */ break; case 5: /* DECSCNM */ if (decscnm) break; /* Already set */ decscnm = TRUE; reversescreen(); defaultattribute = colornormal; attribute = defaultattribute; if (attrib.underlined) attribute = colorunderline; if (attrib.reversed) { attribute = colorreverse; if (attrib.underlined) attribute = colorunderline & 0x0F | colorreverse & 0xF0; } if (attrib.blinking) attribute |= 0x80; if (attrib.bold) attribute ^= 8; if (attrib.invisible) { i = (attribute & 0xF8); attribute = i | ((i >> 4) & 7); } break; case 6: /* DECOM : Relative origin */ relcursor = TRUE; lgotoxy(1, margintop); break; case 7: /* DECAWM */ tt_wrap = TRUE; break; case 8: /* DECARM */ break; case 9: /* DECINLM */ break; default: break; } else switch (pn[j]) { case 2: /* Keyboard locked */ keylock = TRUE; break; case 4: /* Ansi insert mode */ insertmode = TRUE; break; case 20: /* Ansi linefeed mode */ linemode = TRUE; break; default: break; } break; case 'l': /* Reset Mode */ for (j = 1; j <= k; ++j) if (private) switch ((pn[j])) { /* Field specs */ case 1: /* DECCKM */ tt_arrow = FALSE; break; case 2: /* DECANM : ANSI/VT52 */ tt_type = TT_VT52; vt52graphics = FALSE; break; case 3: /* DECCOLM : 80 col */ deccolm = FALSE; clrscreen(); break; case 4: /* DECSCLM */ break; case 5: /* DECSCNM */ if (!decscnm) break; decscnm = !decscnm; reversescreen(); defaultattribute = colornormal; attribute = defaultattribute; if (attrib.underlined) attribute = colorunderline; if (attrib.reversed) { attribute = colorreverse; if (attrib.underlined) attribute = colorunderline & 0x0F | colorreverse & 0xF0; } if (attrib.blinking) attribute |= 0x80; if (attrib.bold) attribute ^= 8; if (attrib.invisible) { i = (attribute & 0xF8); attribute = i | ((i >> 4) & 7); } break; case 6: /* DECOM : Relative origin */ relcursor = FALSE; lgotoxy(1, 1); break; case 7: /* DECAWM */ tt_wrap = FALSE; break; case 8: /* DECARM */ break; case 9: /* DECINLM */ break; default: break; } else switch (pn[j]) { case 2: /* Keyboard unlocked */ keylock = FALSE; break; case 4: /* Ansi insert mode */ insertmode = FALSE; break; case 20: /* Ansi linefeed mode */ linemode = FALSE; break; default: break; } break; case 'i': /* Printer Screen on / off */ #ifndef M_I286 /* Not only does this not work, but it causes crashes ("stack overflow"), in the 16-bit version, at least for me -- but maybe that's because I don't have a printer. For now, we'll leave it buggy in the 32-bit version and turn it off completely in the 16-bit version. NEEDS DEBUGGING BY SOMEBODY WHO HAS A PRINTER. */ if (pn[1] == 0) /* Need code here to print whole screen */ break; else if (pn[1] == 1) /* Need code here to print current line */ /* But only if private == TRUE */ break; /* For pn = 4 or 5, we should differentiate here between transparent print (private == FALSE) and autoprint (private == TRUE). As presently coded, we always do transparent print. */ else if (pn[1] == 4) turnoffprinter = TRUE; else if (pn[1] == 5) turnonprinter = TRUE; /* 6 and 7 are not in the VT102 manual. Maybe in the Scottish version? */ else if (pn[1] == 6) screenon = FALSE; else if (pn[1] == 7) screenon = TRUE; #endif /* M_I286 */ break; case 'q': /* Load LEDs */ break; /* (nothing) */ case 'n': if (pn[1] == 5) /* Terminal Status Report */ sendstr("[0n"); /* Terminal is OK */ else if (pn[1] == 6) { /* Cursor position report */ #ifdef M_I286 /* 16-bit version must use a hand-coded in-line version of sprintf to avoid the function call that would crash the program with a stack overflow. Handles numbers 0 - 999. No range checking. - fdc */ int i = 0, j; tempstr[i++] = '['; if ((j = wherey / 100) > 0) tempstr[i++] = (char) (j + 48); if ((j = (wherey % 100) / 10) > 0 || wherey > 99) tempstr[i++] = (char) (j + 48); if ((j = wherey % 10) > 0 || wherey > 9) tempstr[i++] = (char) (j + 48); tempstr[i++] = ';'; if ((j = wherex / 100) > 0) tempstr[i++] = (char) (j + 48); if ((j = (wherex % 100) / 10) > 0 || wherex > 99) tempstr[i++] = (char) (j + 48); if ((j = wherex % 10) > 0 || wherex > 9) tempstr[i++] = (char) (j + 48); tempstr[i++] = 'R'; tempstr[i] = '\0'; sendstr(tempstr); #else /* 32-bit version can call sprintf() here. This is the original code. */ sendstr("["); sprintf(tempstr,"%1d",(int) wherey); /* row */ sendchar(tempstr[0]); if (tempstr[1]) sendchar(tempstr[1]); sendchar(';'); sprintf(tempstr,"%1d",(int) wherex); /* col */ sendchar(tempstr[0]); if (tempstr[1]) sendchar(tempstr[1]); sendchar('R'); #endif /* M_286 */ } break; case 'x': /* Request terminal Parameters */ if (pn[1] > 1) break; tempstr[0] = '['; tempstr[1] = (pn[1] == 0) ? '2' : '3'; tempstr[2] = ';'; switch (parity) { case 'e': tempstr[3] = '5'; tempstr[5] = '2'; break; case 'o': tempstr[3] = '4'; tempstr[5] = '2'; break; case 0: tempstr[3] = '1'; tempstr[5] = '1'; break; default: tempstr[3] = '1'; tempstr[5] = '2'; break; } tempstr[4] = ';'; switch (speed) { case 50: i = 0; break; case 75: i = 8; break; case 110: i = 16; break; case 133: i = 14; break; case 150: i = 32; break; case 200: i = 40; break; case 300: i = 48; break; case 600: i = 56; break; case 1200: i = 64; break; case 1800: i = 72; break; case 2000: i = 80; break; case 2400: i = 88; break; case 3600: i = 96; break; case 4800: i = 104; break; case 9600: i = 112; break; case 19200: i = 120; break; default: i = 128; break; } #ifdef M_I286 /* Hand-coded sprintf() again. - fdc. */ { int x, j; x = i; i = 6; tempstr[i++] = ';'; if ((j = x / 100) > 0) tempstr[i++] = (char) (j + 48); if ((j = (wherey % 100) / 10) > 0 || wherey > 99) tempstr[i++] = (char) (j + 48); if ((j = wherey % 10) > 0 || wherey > 9) tempstr[i++] = (char) (j + 48); tempstr[i++] = ';'; if ((j = x / 100) > 0) tempstr[i++] = (char) (j + 48); if ((j = (wherey % 100) / 10) > 0 || wherey > 99) tempstr[i++] = (char) (j + 48); if ((j = wherey % 10) > 0 || wherey > 9) tempstr[i++] = (char) (j + 48); tempstr[i++] = ';'; tempstr[i++] = '1'; tempstr[i++] = ';'; tempstr[i++] = '0'; tempstr[i++] = 'x'; tempstr[i++] = '\0'; } #else sprintf(&tempstr[6], ";%d;%d;1;0x", i, i); #endif /* M_I286 */ sendstr(tempstr); break; case 'm': /* Select graphic rendition */ case '}': for (j = 1; j <= k; ++j) switch ((pn[j])) { /* Field specs */ case 0: /* normal */ attribute = defaultattribute; attrib.blinking = FALSE; attrib.bold = FALSE; attrib.invisible = FALSE; attrib.underlined = FALSE; attrib.reversed = FALSE; break; case 1: /* bold */ attrib.bold = TRUE; attribute ^= 8; break; case 4: /* underline */ attrib.underlined = TRUE; attribute = colorunderline; break; case 5: /* blink */ attrib.blinking = TRUE; attribute |= 0x80; break; case 7: /* reverse video */ if (attrib.reversed) break; attrib.reversed = TRUE; attribute = colorreverse; if (attrib.underlined) attribute = colorunderline & 0x0F | colorreverse & 0xF0; if (attrib.invisible) attribute = attribute & 0xF0 | (attribute >> 4) & 0x07; break; case 8: /* invisible */ if (attrib.invisible) break; attrib.invisible = TRUE; attribute = attribute & 0xF0 | (attribute >> 4) & 0x07; break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: /* select foreground */ i = (attribute & 0xF8); attribute = (i | sgrcols[pn[j] - 30]); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: /* select back ground */ i = (attribute & 0x8F); l = sgrcols[pn[j] - 40]; attribute = (i | ((l << 4))); break; default: break; } break; case 'r': /* set margin */ if ((k < 2) || (pn[2] == 0)) pn[2] = ysize; if (pn[1] == 0) pn[1] = 1; if ((pn[1] > 0) && (pn[1] < pn[2]) && (pn[2] <= ysize)) { setmargins(pn[1], pn[2]); lgotoxy(1, relcursor ? margintop : 1); } break; case 'J': switch ((pn[1])) { case 0: /* clear to end of screen */ clreoscr_escape(); break; case 1: /* clear to beginning */ clrboscr_escape(); break; case 2: /* clear all of screen */ clrscreen(); break; default: break; } break; case 'K': switch ((pn[1])) { case 0: /* clear to end of line */ clrtoeoln(); break; case 1: /* clear to beginning */ clrbol_escape(); break; case 2: /* clear line */ clrline_escape(); break; default: break; } break; case 'L': /* Insert lines */ for (i = 1; i <= pn[1]; ++i) scroll(DOWNWARD, wherey - 1, marginbot - 1, 1); break; case 'M': /* Delete lines */ for (i = 1; i <= pn[1]; ++i) scroll(UPWARD, wherey - 1, marginbot - 1, 1); break; case '@': /* Insert characters */ blankcell[0] = ' '; blankcell[1] = attribute; pn[1] *= dwl[wherey - 1] ? 2 : 1; if (pn[1] > xsize + 1 - wherex) pn[1] = xsize + 1 - wherex; VioScrollRt(wherey - 1, wherex - 1, wherey - 1, xsize - 1, pn[1], blankcell, 0 ); break; case 'P': /* DeleteChar */ blankcell[0] = ' '; blankcell[1] = attribute; pn[1] *= dwl[wherey - 1] ? 2 : 1; if (pn[1] > xsize + 1 - wherex) pn[1] = xsize + 1 - wherex; VioScrollLf(wherey - 1, wherex - 1, wherey - 1, xsize - 1, pn[1], blankcell, 0 ); break; default: break; } } break; } } /* Left square bracket */ break; case '7': /* Save cursor position and attributes */ saved = TRUE; /* Remember they are saved */ row = wherey; /* Current row (absolute) */ column = wherex; /* Current column (absolute) */ savedattribute = attribute; /* Current attributes */ savedattrib = attrib; /* Character attributes structure */ saverelcursor = relcursor; /* Cursor addressing mode */ saveg0 = g0; /* Character sets */ saveg1 = g1; saveg0g1 = g0g1; break; case '8': /* Restore Cursor Position and attributes */ if (saved == FALSE) { /* Nothing saved, home the cursor */ lgotoxy(1, relcursor ? margintop : 1); break; } #ifdef COMMENT /* Wrong! Restoring the saved parameters does not unsave them. -fdc */ saved = FALSE; #endif /* COMMENT */ lgotoxy(column, row); /* Goto saved position */ attribute = savedattribute; /* Restore saved attributes */ attrib = savedattrib; relcursor = saverelcursor; /* Restore cursor addressing mode */ g0 = saveg0; /* Restore character sets */ g1 = saveg1; g0g1 = saveg0g1; break; case 'A': if (tt_type == TT_VT52) /* VT52 control */ cursorup(); break; case 'B': if (tt_type == TT_VT52) /* VT52 control */ cursordown(); break; case 'C': if (tt_type == TT_VT52) /* VT52 control */ cursorright(); break; case 'D': if (tt_type == TT_VT52) /* VT52 control */ cursorleft(); else { /* Index */ if (wherey == marginbot) scroll(UPWARD, margintop - 1, marginbot - 1, 1); else cursordown(); } break; case 'E': /* Next Line */ wrtch(13); wrtch(10); break; case 'F': if (tt_type == TT_VT52) /* VT52 control */ vt52graphics = TRUE; break; case 'G': if (tt_type == TT_VT52) /* VT52 control */ vt52graphics = FALSE; break; case 'H': if (tt_type == TT_VT102) { /* Set Tab Stop */ htab[wherex] = 'T'; } /* Set Tab Stop */ else lgotoxy(1, 1); /* VT52 control */ break; case 'I': if (tt_type == TT_VT52) { /* VT52 control */ if ((margintop < wherey)) cursorup(); else scroll(DOWNWARD, margintop - 1, marginbot - 1, 1); } break; case 'J': if (tt_type == TT_VT52) /* VT52 control */ clreoscr_escape(); break; case 'K': if (tt_type == TT_VT52) /* VT52 control */ clrtoeoln(); break; case 'M': /* Reverse Index */ if (margintop == wherey) /* "==", not ">="! - fdc */ scroll(DOWNWARD, margintop - 1, marginbot - 1, 1); else cursorup(); break; case 'Y': if (tt_type == TT_VT52) { /* VT52 control */ /* direct cursor address */ readmchar_escape(); row = achar - 31; readmchar_escape(); column = achar - 31; lgotoxy(column, row); } /* direct cursor address */ break; case 'Z': if (tt_type == TT_VT102) { /* Device Attributes */ /* Send Esc[?6c */ /* (was "ESC [ ? 6 ; 2 c" - fdc) */ sendstr("[?6c"); } /* Device Attributes */ else /* VT52 control */ sendstr("/Z"); break; case 'c': /* Reset */ doreset(); break; case '#': /* Esc # sequence */ readmchar_escape(); switch (achar) { case '3': decdwl_escape(TRUE); break; case '4': decdwl_escape(TRUE); break; case '5': decdwl_escape(FALSE); break; case '6': decdwl_escape(TRUE); break; case '8': { char cell[2]; cell[0] = 'E'; cell[1] = 7; /* Self Test */ VioWrtNCell(cell, 1920, 0, 0, 0); setmargins(1, ysize); lgotoxy(1, 1); } break; /* Self Test */ default: break; } break; /* Esc # sequence */ case '=': tt_keypad = FALSE; break; case '>': tt_keypad = TRUE; break; case '<': /* VT52 control */ tt_type = TT_VT102; break; case '(': readmchar_escape(); g0 = achar; break; case ')': readmchar_escape(); g1 = achar; break; default: if (achar == 12) { lgotoxy(1, 1); clrscreen(); } break; } /* First Level Case */ } /* Screen escape sequences */ /* Host said to turn off the printer. */ if (turnoffprinter) { turnoffprinter = FALSE; if (lst && !lstclosed) fclose(lst); lstclosed = TRUE; printon = FALSE; } /* If printer is on, print this escape sequence. */ if (printon) { fprintf(lst, "%c", 27); if (esclast > 0) { /* print esc sequence */ for (i = 1; i <= esclast; ++i) fprintf(lst, "%c", escbuffer[i]); } } /* If we just got a "printer on" directive, turn on the printer now. This way, the "printer on" directive itself is not printed. */ if (turnonprinter) { /* Last command was "printer on" */ turnonprinter = FALSE; if (lstclosed || !lst) /* Open printer device */ lst = fopen("prn", "w"); if (lst) { /* Open OK? */ lstclosed = FALSE; /* So not closed */ printon = TRUE; /* and printer is on. */ } } } /* ================================================================== */ /* VT100 emulate a DEC VT100 terminal writing a character */ /* ================================================================== */ static void vt100(unsigned char vtch) { int i, j; char *s, str[2]; /* vt100 */ if (screenon) { if (vtch < 32) { /* Control Character */ achar = vtch; /* Let the rest of this module see the value */ switch (achar) { case LF: if (linemode) wherex=1; wrtch((char) achar); break; case CR: wrtch((char) achar); break; /* ESC */ case 27: vtescape(); break; case 14: /* SO */ g0g1 = &g1; break; /* SI */ case 15: g0g1 = &g0; break; /* BS */ case 8: wrtch((char) achar); break; case 12: /* FF */ case 11: /* VT */ /* take as lf */ achar = 10; wrtch(10); break; case 7: /* BEL */ bleep(); break; case 5: /* ENQ */ if (tt_answer) { s = answerback; while (*s) sendchar(*s++); } break; case 9: /* tab character */ j = dwl[wherey - 1] ? 2 : 1; i = wherex; if (j == 2 && htab[(i - 1) / j + 1] == 'T') { i++; cursorright(); } if (i < xsize) do { i++; cursorright(); } while ((htab[(i - 1) / j + 1] != 'T') && (i <= xsize - j)); break; default: /* ignore it */ break; } /* end of Control Character */ } else { if (vtch != DEL) { /* Normal char */ if (tt_type == TT_VT102) { if (*g0g1 == 'A') { /* UK ascii set */ /* if (vtch == 35) vtch = 156; */ } else if ((*g0g1 == '0') && (95 <= vtch) && (vtch <= 126)) { literal = TRUE; vtch = graphicset[vtch - 95]; } } else { if (vt52graphics && (95 <= vtch) && (vtch <= 126)) { literal = TRUE; vtch = graphicset[vtch - 95]; } } if (wherex != (dwl[wherey - 1] ? xsize - 1 : xsize)) { wrtch(vtch); if (dwl[wherey - 1]) wrtch(' '); wrapit = FALSE; } else { if (wrapit) { /* Next line */ if (marginbot <= wherey) { /* Scroll up */ scroll(UPWARD, margintop - 1, marginbot - 1, 1); lgotoxy(1, wherey); } else lgotoxy(1, wherey + 1); wrtch(vtch); if (dwl[wherey - 1]) wrtch(' '); wrapit = FALSE; } else { /* put char on last column */ i = dwl[wherey - 1] ? 2 : 1; str[0] = vtch; str[1] = ' '; VioWrtCharStrAtt(&vtch, i, wherey - 1, xsize - i, &attribute, 0); literal = FALSE; if ((tt_wrap && !deccolm)) wrapit = TRUE; } } } /* Normal char */ } } if (printon && (vtch != 27)) fprintf(lst, "%c", vtch); } /* save current status of screen */ savescreen(ascreen *scrn) { USHORT n = xsize * (ysize + 1) * 2; scrn->ox = wherex; scrn->oy = wherey; scrn->att = attribute; VioReadCellStr((char *) (scrn->scrncpy), &n, 0, 0, 0); } /* restore state of screen */ restorescreen(ascreen *scrn) { movetoscreen(scrn->scrncpy, 1, 1, xsize * (ysize + 1) * 2); attribute = scrn->att; wherey = scrn->oy; wherex = scrn->ox; lgotoxy(wherex, wherey); } #ifdef M_I286 /* Avoid 16-bit stack overflows */ #define logchar(c) zchout(ZSFILE,c) #else void logchar(char c) { if (zchout(ZSFILE,c) < 0) { conoll(""); conoll("ERROR WRITING SESSION LOG, LOG CLOSED!"); seslog = 0; } } #endif /* M_I286 */ sendcharduplex(unsigned char key) { unsigned char csave; key &= cmdmsk; /* Do any requested masking */ csave = key; if (outesc == ES_NORMAL) { /* If not inside escape seq.. */ /* Translate character sets */ if (sxo) key = (*sxo)(key); /* Local to intermediate. */ if (rxo) key = (*rxo)(key); /* Intermediate to remote. */ } if (oskipesc) outesc = chkaes(outesc, key); /* Check escape sequence status */ if (sosi) { /* Shift-In/Out selected? */ if (cmask == 0177) { /* In 7-bit environment? */ if (key & 0200) { /* 8-bit character? */ if (outshift == 0) { /* If not shifted, */ sendchar(SO); /* shift. */ outshift = 1; } } else { if (outshift == 1) { /* 7-bit character */ sendchar(SI); /* If shifted, */ outshift = 0; /* unshift. */ } } } if (key == SO) outshift = 1; /* User typed SO */ if (key == SI) outshift = 0; /* User typed SI */ } key &= cmask; /* Apply Kermit-to-host mask now. */ if (key == '\015') { /* Handle TERMINAL NEWLINE */ if ( tnlm #ifdef TNCODE /* And for TELNET... */ || (network && ttnproto == NP_TELNET) #endif /* TNCODE */ ) { sendchar(dopar('\015')); /* Send the CR */ if (duplex) { /* If local echoing... */ cwrite('\015'); /* echo to screen */ if (seslog) /* and if logging */ logchar(csave); /* log it */ } #ifdef TNCODE if (network && !tn_nlm && ttnproto == NP_TELNET) key = '\0'; else #endif /* TNCODE */ key = '\012'; /* Now insert a linefeed */ csave = key; } } #ifdef TNCODE /* If user types the 0xff character (TELNET IAC), it must be doubled. */ else if (key == IAC && network && ttnproto == NP_TELNET) ttoc((char)IAC); /* and the other one just below. */ #endif /* TNCODE */ sendchar(key); if (duplex) { cwrite(csave); if (seslog) logchar(csave); } } sendstrduplex(unsigned char *s, int escape) { if (escape) sendcharduplex(27); for ( ; *s; s++ ) sendcharduplex(*s); } void scrollback(int key) { int linesleft, nextline, nlines, i, il, nolblines; savescreen(&savedscreen); killcursor(); linesleft = paginginfo.numlines; nextline = paginginfo.botline; do { if ((key & 0xFF) == 71 || (key & 0xFF) == 73 || (key & 0xFF) == 132) { /* Page Up or Home */ if (linesleft == 0) bleep(); else { /* scroll up a page */ nlines = (key & 0xFF) == 73 ? ysize : (key & 0xFF) == 71 ? linesleft : 1; if (nlines > linesleft) nlines = linesleft; if (nlines >= ysize) { if (nlines > ysize) nextline = paginginfo.topline + ysize - 1; for (il = ysize; il >= 1; il--) { movetoscreen(paginginfo.buffer + xsize * 2 * nextline, 1, il, xsize * 2); if (nextline == 0) nextline = LBUFSIZE - 1; else nextline--; } } else { scroll(DOWNWARD, 0, ysize - 1, nlines); for (il = 1; il <= nlines; il++) { movetoscreen(paginginfo.buffer + xsize * 2 * nextline, 1, nlines - il + 1, xsize * 2); if (nextline == 0) nextline = LBUFSIZE - 1; else nextline--; } } linesleft = linesleft - nlines; } } else if ((key & 0xFF) == 81 || (key & 0xFF) == 118) { nlines = (key & 0xFF) == 81 ? ysize : 1; /* Page Down */ if (nlines > paginginfo.numlines - linesleft) nlines = paginginfo.numlines - linesleft; if (nlines < ysize) scroll(UPWARD, 0, ysize - 1, nlines); do { if (++nextline >= LBUFSIZE) nextline = 0; linesleft++; /* lines of ext display above top of the screen */ nolblines = paginginfo.numlines - linesleft; /* no. of ext disp buffer lines on screen */ if (nolblines >= ysize) { i = nextline + ysize; if (i >= LBUFSIZE) i -= LBUFSIZE; /* move from buffer */ movetoscreen(paginginfo.buffer + xsize * 2 * i, 1, ysize - nlines + 1, xsize * 2); } else { /* move from the screen copy */ movetoscreen(&(savedscreen.scrncpy [(ysize - 1 - nolblines) * xsize * 2]), 1, ysize - nlines + 1, xsize * 2); } nlines--; } while (nlines > 0); } else linesleft = paginginfo.numlines; if (linesleft != paginginfo.numlines) { sprintf(usertext, " Scroll: %d/%d", paginginfo.numlines - linesleft, paginginfo.numlines); strcpy(helptext, "[^]PageUp/Dn"); strcpy(exittext, "Home/End"); line25(); if ( (key = keymap[congks(0)]) < 0x100 ) key = 32; } } while (linesleft != paginginfo.numlines); restorescreen(&savedscreen); newcursor(); ipadl25(); } void vt100key(int key) { void doesc(int); int helpconnect(int); char str[3]; int prt, st; if ( macrotab[key] ) { sendstrduplex(macrotab[key], 0); return; } key = keymap[key]; if (key < 0x100) { sendcharduplex((char) key); if (key == CR && linemode) sendcharduplex(LF); return; } switch (key & 0xFF) { case 72: /* up */ if (tt_type == TT_VT102) { if (tt_arrow) sendstrduplex("OA", 1); else sendstrduplex("[A", 1); } else sendstrduplex("A", 1); break; case 75: /* left */ if (tt_type == TT_VT102) { if (tt_arrow) sendstrduplex("OD", 1); else sendstrduplex("[D", 1); } else sendstrduplex("D", 1); break; case 77: /* right */ if (tt_type == TT_VT102) { if (tt_arrow) sendstrduplex("OC", 1); else sendstrduplex("[C", 1); } else sendstrduplex("C", 1); break; case 80: /* down */ if (tt_type == TT_VT102) { if (tt_arrow) sendstrduplex("OB", 1); else sendstrduplex("[B", 1); } else sendstrduplex("B", 1); break; case 15: /* Backtab */ /* backspace */ sendcharduplex(8); break; case 83: /* DEL */ /* delete */ sendcharduplex(127); break; case 59: /* F1 */ /* PF1 */ if (tt_type == TT_VT102) sendstrduplex("OP", 1); else sendstrduplex("P", 1); break; case 60: /* F2 */ /* PF2 */ if (tt_type == TT_VT102) sendstrduplex("OQ", 1); else sendstrduplex("Q", 1); break; case 61: /* PF3 */ /* F3 */ if (tt_type == TT_VT102) sendstrduplex("OR", 1); else sendstrduplex("R", 1); break; case 62: /* F4 */ /* PF4 */ if (tt_type == TT_VT102) sendstrduplex("OS", 1); else sendstrduplex("S", 1); break; case 120: /* Alt-1 ... Alt-9 */ case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: /* This one is Alt-0 */ /* numeric 1-9,0 */ if (tt_keypad) { /* Keypad digits in numeric mode*/ if (key == 129) key = 48; /* Watch out for zero */ else key -= 71; sendcharduplex((unsigned char)key); /* send digit */ } else { key = 'q' + (key & 0xFF) - 120; if (key == 'z') key = 'p'; /* alt 0 */ if (tt_type == TT_VT102) strcpy(str, "O "); else strcpy(str, "? "); str[1] = key; sendstrduplex(str, 1); } break; case 63: /* Keypad minus = F5 or ... */ case 64: /* F6 */ if (tt_keypad) /* Keypad in numeric mode */ sendcharduplex('-'); else if (tt_type == TT_VT102) /* Application mode, VT102 */ sendstrduplex("Om", 1); else /* Application mode, VT52 */ sendstrduplex("?m", 1); break; case 65: /* Keypad comma = F7 or ... */ case 66: /* F8 */ if (tt_keypad) sendcharduplex(','); else if (tt_type == TT_VT102) sendstrduplex("Ol", 1); else sendstrduplex("?l", 1); break; case 67: /* Keypad period = F9 */ if (tt_keypad) sendcharduplex('.'); else if (tt_type == TT_VT102) sendstrduplex("On", 1); else sendstrduplex("?n", 1); break; case 68: /* Keypad Enter = F10 */ if (tt_keypad) { sendcharduplex('\015'); /* Numeric mode, send CR */ if (tnlm) sendcharduplex('\012'); /* Newline mode, send LF too */ } else if (tt_type == TT_VT102) sendstrduplex("OM", 1); else sendstrduplex("?M", 1); break; case 255: /* Scroll-Lock */ { strcpy(usertext, " Scroll-Lock "); *exittext = '\0'; *helptext = '\0'; line25(); while (keymap[congks(0)] != 0x1FF) ; ipadl25(); } break; case 81: /* Page-Down */ case 118: /* Control-Page-Down */ bleep(); /* since not in extended display mode */ break; case 71: /* Home enter extended display mode */ case 73: /* Page-Up */ case 132: /* Control-Page-Up */ if (paginginfo.numlines == 0) bleep(); else scrollback(key); break; case 16: /* Alt-Q = Quit */ doesc('Q'); break; case 45: /* Alt-X = Return to prompt */ doesc('C'); break; case 48: /* Alt-B = Send BREAK */ doesc('B'); break; case 38: /* Alt-L = Send Long BREAK */ doesc('L'); break; case 35: /* Alt-H = Hangup */ doesc('H'); break; case 131: /* Alt-= is Reset */ doreset(); #ifdef COMMENT clearscreen(0, attribute); savescreen(&vt100screen); #endif /* COMMENT */ break; case 53: /* Alt-? or Alt-/ = Help */ strcpy(usertext, " Press any key to restore the screen"); exittext[0] = '\0'; helptext[0] = '\0'; line25(); helpconnect(1); ipadl25(); break; default: /* Others, ignore */ break; } /* of case */ } /* ------------------------------------------------------------------ */ /* cwrite */ /* ------------------------------------------------------------------ */ cwrite(unsigned char ch) { { /* check and process escape sequence */ /* escape */ if (ch == 27) { escaping = TRUE; esclast = 0; } else { if (!(escaping)) { /* can send it to vt100 to be processed */ vt100(ch); } else { /* in the middle of an escape sequence */ if (((ch == 24) || (ch == 26))) /* cancelled */ escaping = FALSE; else { if (ch < 32) { if (ch == 8) { /* Backspace */ if (esclast >= 1) esclast--; } } else { /* add to control string */ if (esclast < 128) { /* add to buffer */ esclast = esclast + 1; escbuffer[esclast] = ch; } /* now check to see if sequence complete */ { if (tt_type == TT_VT102) { if (escbuffer[1] != '[') { char c = escbuffer[1]; if ((c != '#' && c != '(' && c != ')' && c != 'O' && c != '?') || esclast >= 2) { if ((escbuffer[1] != 'Y')) vtescape(); else { if ((esclast == 3)) vtescape(); } } } else { /* check for terminating character */ if ((((64 <= ch) && (ch <= 126)) && (esclast > 1))) vtescape(); } } else { /* vt52 mode */ if ((escbuffer[1] != 'Y')) vtescape(); else { if (esclast == 3) vtescape(); } } } } } } } } } /*---------------------------------------------------------------------------*/ /* scrninit */ /*---------------------------------------------------------------------------*/ scrninit() { if ( paginginfo.bufsize != tt_scrsize ) { if ( paginginfo.buffer != NULL ) free(paginginfo.buffer); paginginfo.buffer = NULL; scrninitialised = 0; } if (!scrninitialised) { scrninitialised = 1; defaultattribute = colornormal; attribute = defaultattribute; /* Initialise paging info */ if ( paginginfo.buffer == NULL ) { paginginfo.bufsize = tt_scrsize; paginginfo.buffer = malloc(tt_scrsize * xsize * 2); } assert(paginginfo.buffer != NULL); paginginfo.numlines = 0; paginginfo.topline = 0; paginginfo.botline = LBUFSIZE - 1; clearscreen(0, attribute); savescreen(&vt100screen); } } /*---------------------------------------------------------------------------*/ /* bleep */ /*---------------------------------------------------------------------------*/ bleep() { DosBeep(880, 50); } /*---------------------------------------------------------------------------*/ /* wrtch */ /*---------------------------------------------------------------------------*/ wrtch(char ch) { char cell[2]; if (ch >= ' ' || literal) { /* Normal character */ if ((tt_type == TT_VT102) && insertmode) { cell[0] = ch; cell[1] = attribute; VioScrollRt(wherey - 1, wherex - 1, wherey - 1, xsize - 1, 1, cell, 0); } else VioWrtCharStrAtt(&ch, 1, wherey - 1, wherex - 1, &attribute, 0); literal = FALSE; if (++wherex > xsize) { wherex = 1; wrtch(LF); } } else { /* Control character */ switch (ch) { case LF: if (wherey == marginbot) { if (margintop == 1) toplinetocyclicbuffer(); scroll(UPWARD, margintop - 1, marginbot - 1, 1); } else { wherey++; if (wherey == ysize + 1) wherey--; } break; case CR: wherex = 1; break; case BS: if (wherex > 1) wherex--; break; case 12: if (wherex < xsize) wherex++; break; case BEL: DosBeep(440, 100); break; default:{ /* Ignore */ } } } if (cursoron) VioSetCurPos(wherey - 1, wherex - 1, 0); } /*---------------------------------------------------------------------------*/ /* clearscreen */ /*---------------------------------------------------------------------------*/ clearscreen(int all, int attr) { char cell[2]; cell[0] = ' '; cell[1] = attr; VioWrtNCell(cell, xsize * ysize + (all ? xsize : 0), 0, 0, 0); lgotoxy(1, 1); } /*---------------------------------------------------------------------------*/ /* lgotoxy */ /*---------------------------------------------------------------------------*/ lgotoxy(int x, int y) { wherex = x; wherey = y; if (cursoron) VioSetCurPos(wherey - 1, wherex - 1, 0); } /*---------------------------------------------------------------------------*/ /* scroll */ /*---------------------------------------------------------------------------*/ scroll(int updown, int top, int bottom, int nlines) { char blankcell[2]; int i; blankcell[0] = ' '; blankcell[1] = attribute; switch (updown) { case UPWARD: VioScrollUp(top, 0, bottom, xsize - 1, nlines, blankcell, 0); VioShowBuf(0, xsize * 2, 0); /* There is a bug in early OS/2 2.0 8514/A PM drivers that causes * wrong screen update after a scroll operation. We just force * a correct screen update of the line in question here. */ if (dwls) { for (i = top; i <= bottom - nlines; i++) dwl[i] = dwl[i + nlines]; for (i = bottom - nlines + 1; i <= bottom; i++) dwl[i] = FALSE; } break; case DOWNWARD: VioScrollDn(top, 0, bottom, xsize - 1, nlines, blankcell, 0); VioShowBuf(xsize * 2, xsize * 2, 0); if (dwls) { for (i = bottom; i >= top + nlines; i--) dwl[i] = dwl[i - nlines]; for (i = top + nlines - 1; i >= top; i--) dwl[i] = FALSE; } break; default: /* ignore */ ; } if (dwls) { dwls = FALSE; for (i = 0; i < ysize; i++) if (dwl[i]) { dwls = TRUE; break; } } } /*---------------------------------------------------------------------------*/ /* movetoscreen */ /*---------------------------------------------------------------------------*/ movetoscreen(char *source, int x, int y, int len) { VioWrtCellStr(source, len, y - 1, x - 1, 0); } /*---------------------------------------------------------------------------*/ /* toplinetocyclicbuffer */ /*---------------------------------------------------------------------------*/ toplinetocyclicbuffer() { USHORT n = xsize * 2; if (paginginfo.numlines == LBUFSIZE) { if (++paginginfo.topline == LBUFSIZE) paginginfo.topline = 0; } else paginginfo.numlines++; if (++paginginfo.botline == LBUFSIZE) paginginfo.botline = 0; VioReadCellStr((paginginfo.buffer + xsize * 2 * paginginfo.botline), &n, 0, 0, 0); } /*---------------------------------------------------------------------------*/ /* cleartoeol */ /*---------------------------------------------------------------------------*/ clrtoeoln() { char cell[2]; cell[0] = ' '; cell[1] = attribute; VioWrtNCell(cell, xsize + 1 - wherex, wherey - 1, wherex - 1, 0); } /*---------------------------------------------------------------------------*/ /* setmargins */ /*---------------------------------------------------------------------------*/ setmargins(int top, int bot) { margintop = top; marginbot = bot; } /*---------------------------------------------------------------------------*/ /* killcursor */ /*---------------------------------------------------------------------------*/ killcursor() { VIOCURSORINFO nocursor; if (!cursoron) return 0; VioGetCurType(&crsr_info, 0); /* Store current cursor type */ nocursor = crsr_info; /* MS C allows this */ nocursor.attr = -1; VioSetCurType(&nocursor, 0);/* Hide cursor */ } /*---------------------------------------------------------------------------*/ /* newcursor */ /*---------------------------------------------------------------------------*/ newcursor() { VioSetCurType(&crsr_info, 0); VioSetCurPos(wherey - 1, wherex - 1, 0); cursoron = TRUE; } /*---------------------------------------------------------------------------*/ /* line25 */ /*---------------------------------------------------------------------------*/ strinsert(char *d, char *s) { while (*s) *d++ = *s++; } line25() { char s[132]; int i; char attr; for (i = 0; i < xsize; i++) s[i] = ' '; strinsert(&s[00], usertext); strinsert(&s[20], helptext); strinsert(&s[33], exittext); strinsert(&s[52], hostname); strinsert(&s[65], filetext); attr = colorstatus; VioWrtCharStrAtt(s, xsize, ysize, 0, &attr, 0); } sendstr(char * s) { sendchar(27); while (*s) sendchar(*s++); } /* * RDSERWRTSCR -- Read the comms line and write to the screen. * This function is executed by a separate thread. */ int ckcgetc(int dummy) { return ttinc(1); } #ifdef __32BIT__ long FAR rdserwrtscr(long param) #else void FAR rdserwrtscr() #endif { int c, tx; DosSetPrty(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0); #ifdef __32BIT__ DosPostEventSem(threadsem); #else DosSemClear(&threadsem); /* Let him know we've started */ #endif while (active) { c = ttinc(-50); if (!active) break; if (c >= 0) { #ifdef TNCODE /* Handle TELNET negotiations here */ if (c == IAC && network && ttnproto == NP_TELNET) { if ((tx = tn_doop((CHAR)(c & 0xff),duplex,ckcgetc)) == 0) { continue; } else if (tx == -1) { /* I/O error */ strcpy(termessage, "Connection closed.\n"); active = FALSE; break; } else if ((tx == 1) && (!duplex)) { /* ECHO change */ duplex = 1; } else if ((tx == 2) && (duplex)) { /* ECHO change */ duplex = 0; } else if (tx == 3) { /* Quoted IAC */ c = 255; } else continue; /* Negotiation OK, get next char. */ } #endif /* TNCODE */ DosEnterCritSec(); if (cursoron) if (ttchk() > 20) { killcursor(); cursoron = FALSE; } c &= cmask; if (sosi) { /* Handle SI/SO */ if (c == SO) { /* Shift Out */ inshift = 1; goto cont; } else if (c == SI) { /* Shift In */ inshift = 0; goto cont; } if (inshift) c |= 0200; } /* Translate character sets */ if (inesc == ES_NORMAL) { /* Translate character sets */ if (sxi) c = (*sxi)((CHAR)c); if (rxi) c = (*rxi)((CHAR)c); } if (iskipesc) inesc = chkaes(inesc, (CHAR)c); /* Adjust escape sequence status */ c &= cmdmsk; /* Apply command mask. */ if (c == CR && tt_crd) { /* SET TERM CR-DISPLAY CRLF ? */ cwrite((char) c); /* Yes, output CR */ if (seslog) logchar((char) c); c = LF; /* and insert a linefeed */ } cwrite((char) c); if (seslog) logchar((char) c); cont: DosExitCritSec(); } else if (c == -2) { active = FALSE; strcpy(termessage, "Connection closed.\n"); /* link broken */ } else if (!cursoron) { DosEnterCritSec(); newcursor(); DosExitCritSec(); } } #ifndef __32BIT__ DosEnterCritSec(); /* Stop thread 1 discarding our stack before * we've gone */ DosSemClear(&threadsem); /* Tell him we're going to die */ #endif DosExit(EXIT_THREAD, 0); } /* HELPCONNECT -- Give help message for connect. */ static int helpcol, helprow; static int helpwidth; void helpstart(int w, int h) { unsigned char cell[2]; cell[1] = colorhelp; helpwidth = w; helpcol = (xsize - w) / 2; helprow = (ysize - h) / 2 - 1; cell[0] = 201; /* Top left corner */ VioWrtNCell(cell, 1, helprow, helpcol, 0); cell[0] = 205; /* Horizontal */ VioWrtNCell(cell, helpwidth, helprow, helpcol + 1, 0); cell[0] = 187; /* Top right corner */ VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0); } void helpline(char *s) { unsigned char cell[2]; int i; i = strlen(s); helprow++; cell[1] = colorhelp; cell[0] = 186; /* Vertical */ VioWrtNCell(cell, 1, helprow, helpcol, 0); VioWrtCharStrAtt(s, i, helprow, helpcol + 1, &cell[1], 0); cell[0] = ' '; VioWrtNCell(cell, helpwidth - i, helprow, helpcol + 1 + i, 0); cell[0] = 186; /* Vertical */ VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0); } void helpend() { unsigned char cell[2]; helprow++; cell[1] = colorhelp; cell[0] = 200; /* Bottom left corner */ VioWrtNCell(cell, 1, helprow, helpcol, 0); cell[0] = 205; /* Horizontal */ VioWrtNCell(cell, helpwidth, helprow, helpcol + 1, 0); cell[0] = 188; /* Bottom right corner */ VioWrtNCell(cell, 1, helprow, helpcol + helpwidth + 1, 0); } int helpconnect(int x) { int c, n; char line[80]; static char *hlpmsg[] = { "", " Command: (SPACE to cancel)", "", " C to return to the C-Kermit prompt", " H to hangup and return to the prompt", " Q to hangup and quit C-Kermit", " ! to enter an OS/2 command processor", "", " 0 (zero) to send a null", " ^%c to send the escape character", " B to send a BREAK", " L to send a LONG BREAK", "", #ifdef TNCODE " I to interrupt process (TELNET)", " A to send 'are you there' (TELNET)", "", #endif /* TNCODE */ " \\ backslash escape (end with ENTER):", " \\nnn decimal code", " \\Onnn octal code", " \\Xhh hexadecimal code", ""}; #define HELPSIZE (sizeof(hlpmsg)/sizeof(char *)) static char *altmsg[] = { "", " Alt-X to return to the C-Kermit prompt", " Alt-H to hangup and return to the prompt", " Alt-Q to hangup and quit Kermit", " Alt-B to send a BREAK", " Alt-L to send a Long BREAK", " Alt-= to reset terminal emulator", "", " or the CONNECT-mode escape character Ctrl-%c", " followed by ? for additional commands", ""}; #define ALTSIZE (sizeof(altmsg)/sizeof(char *)) n = x ? ALTSIZE : HELPSIZE; savescreen(&savedscreen); killcursor(); helpstart(47, n); for (c = 0; c < n; c++) if (strchr(x ? altmsg[c] : hlpmsg[c], '%')) { sprintf(line, x ? altmsg[c] : hlpmsg[c], ctl(escape)); helpline(line); } else helpline(x ? altmsg[c] : hlpmsg[c]); helpend(); c = keymap[congks(0)]; newcursor(); restorescreen(&savedscreen); return (c); } /* CHSTR -- Make a printable string out of a character */ char* chstr(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); } /* DOESC -- Process an escape character argument */ void esc25(int h) { strcpy(usertext, " Command:"); strcpy(exittext, h ? "" : "Return: c"); strcpy(helptext, h ? "" : "Help: ?"); line25(); } void doesc(int c) { CHAR d, temp[8]; VIOMODEINFO mi; while (1) { if (c == escape) { /* Send escape character */ sendchar((char)c); return; } else /* Or else look it up below. */ if (isupper(c)) c = tolower(c); switch (c) { case 'c': /* return to command mode */ case '\03': active = 0; return; case 'h': /* Hangup and return to command mode */ /* case '\010': */ /* Too dangerous! */ hangnow = 1; active = 0; strcpy(termessage, "Hangup.\n"); return; case 'q': /* Hangup and quit */ /* case '\021': */ /* Too dangerous! */ active = 0; hangnow = 1; quitnow = 1; strcpy(termessage, "Hangup and quit.\n"); return; case '!': savescreen(&savedscreen); mi.cb = sizeof(mi); VioGetMode(&mi, 0); concooked(); clearscreen(1, colorcmd); restorecursormode(); puts("Enter EXIT to return to C-Kermit."); zshcmd(""); conraw(); connoi(); VioSetMode(&mi, 0); setcursormode(); restorescreen(&savedscreen); return; case 'b': /* Send a BREAK signal */ case '\02': ttsndb(); return; case 'l': /* Send a LONG BREAK signal */ case '\014': ttsndlb(); return; case '0': /* Send a null */ c = '\0'; sendchar((char)c); return; #ifdef NETCONN #ifdef TCPSOCKET case 'i': /* Send Interrupt */ if (network && ttnproto == NP_TELNET) { /* TELNET */ temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) IP; /* Interrupt Process */ temp[2] = NUL; ttol((CHAR *)temp,2); } else conoc(BEL); return; case 'a': /* "Are You There?" */ if (network && ttnproto == NP_TELNET) { temp[0] = (CHAR) IAC; /* I Am a Command */ temp[1] = (CHAR) AYT; /* Are You There? */ temp[2] = NUL; ttol((CHAR *)temp,2); } else conoc(BEL); return; #endif /* TCPSOCKET */ #endif /* NETCONN */ case '\\': { char kbuf[32]; char *kbp = kbuf, *text = usertext + 2; *kbp++ = c; strcpy(usertext, " \\"); strcpy(exittext,"Exit: ENTER"); helptext[0] = 0; line25(); while (((c = (coninc(0) & cmdmsk)) != '\r') && (c != '\n')) { if ( c == '\b' ) { if ( kbp > kbuf + 1 ) { *--kbp = 0; *--text = 0; } } else if ( kbp - kbuf < sizeof(kbuf) - 2 ) { *kbp++ = c; *text++ = c; *text = 0; } line25(); } *kbp = 0; kbp = kbuf; c = xxesc(&kbp); /* Interpret it */ if (c >= 0) { sendcharduplex((char)c); return; } else { /* Invalid backslash code. */ conoc(BEL); return; } } return; case SP: /* Space, ignore */ return; default: /* Other */ conoc(BEL); return; /* Invalid esc arg, beep */ } } } /* CHECKSCREENMODE -- Make sure we are in a usable mode */ checkscreenmode() { VIOMODEINFO m; VIOINTENSITY vi; vi.cb = sizeof(vi); vi.type = 2; vi.fs = 1; VioSetState(&vi, 0); m.cb = sizeof(m); assert(VioGetMode(&m, 0) == 0); if ( xsize != min(132, m.col) || ysize != min(60, m.row) - 1 ) { scrninitialised = 0; if ( paginginfo.buffer ) free(paginginfo.buffer); paginginfo.buffer = NULL; if ( vt100screen.scrncpy ) free(vt100screen.scrncpy); vt100screen.scrncpy = NULL; if ( commandscreen.scrncpy ) free(commandscreen.scrncpy); commandscreen.scrncpy = NULL; if ( savedscreen.scrncpy ) free(savedscreen.scrncpy); savedscreen.scrncpy = NULL; } xsize = min(132, m.col); ysize = min(60, m.row) - 1; marginbot = ysize; if ( !vt100screen.scrncpy ) vt100screen.scrncpy = malloc(xsize * (ysize + 1) * 2); assert(vt100screen.scrncpy != NULL); if ( !commandscreen.scrncpy ) commandscreen.scrncpy = malloc(xsize * (ysize + 1) * 2); assert(commandscreen.scrncpy != NULL); if ( !savedscreen.scrncpy ) savedscreen.scrncpy = malloc(xsize * (ysize + 1) * 2); assert(savedscreen.scrncpy != NULL); } setcursormode() { VIOMODEINFO vmi; VIOCURSORINFO vci; int cell, bottom, top; vmi.cb = sizeof(vmi); VioGetMode(&vmi, 0); cell = vmi.vres / vmi.row; VioGetCurType(&vci, 0); crsr_command = vci; vci.cEnd = cell - 1; vci.yStart = (tt_cursor == 0) ? cell - 2 : cell - 1 - (cell - 2) * tt_cursor / 2; VioSetCurType(&vci, 0); } restorecursormode() { VioSetCurType(&crsr_command, 0); } /* CONECT -- Perform terminal connection */ int conect() { USHORT len, x, y; int c, cm; /* c is a character, but must be signed * integer to pass thru -1, which is the * modem disconnection signal, and is * different from the character 0377 */ char errmsg[50], *erp, ac, bc, ss[132]; if (!network && speed < 0) { printf("Sorry, you must set speed first.\n"); return (0); } twochartimes = network ? 1 : 22000L / speed; if ((escape < 0) || (escape > 0177)) { printf("Your escape character is not ASCII - %d\n", escape); return (0); } if (ttopen(ttname, &local, network ? -nettype : mdmtyp, 0) < 0) { erp = errmsg; sprintf(erp, "Sorry, can't open %s", ttname); perror(errmsg); return (0); } /* Condition console terminal and communication line */ if (ttvt(speed, flow) < 0) { printf("Sorry, Can't condition communication line\n"); return (0); } if (!network && carrier != CAR_OFF && (ttgmdm() & BM_DCD) == 0) { printf("No carrier detected.\n"); return (0); } #ifdef TNCODE if (network && ttnproto == NP_TELNET) tn_ini(); #endif /* TNCODE */ outshift = inshift = 0; /* Initial shift state. */ tcs = TC_1LATIN; langsv = language; language = L_USASCII; if (tcsr == tcsl) { /* Remote and local sets the same? */ sxo = rxo = NULL; /* If so, no translation. */ sxi = rxi = NULL; } else { /* Otherwise, set up */ sxo = xls[tcs][tcsl]; /* translation function */ rxo = xlr[tcs][tcsr]; /* pointers for output functions */ sxi = xls[tcs][tcsr]; /* and for input functions. */ rxi = xlr[tcs][tcsl]; } iskipesc = oskipesc = (tcs != TC_TRANSP) && /* Not transparent */ (fcsinfo[tcsl].size == 128 || fcsinfo[tcsr].size == 128) && /* 7 bits */ (fcsinfo[tcsl].code != FC_USASCII); inesc = outesc = ES_NORMAL; /* Initial state of recognizer */ checkscreenmode(); setcursormode(); VioGetCurPos(&y, &x, 0); wherex = x + 1; wherey = y + 1; savescreen(&commandscreen); colorcmd = commandscreen.scrncpy[(x + y * xsize) * 2 + 1]; scrninit(); restorescreen(&vt100screen); conraw(); connoi(); ipadl25(); /* Create a thread to read the comms line and write to the screen */ active = 1; /* So thread 2 doesn't end at once */ quitnow = 0; hangnow = 0; termessage[0] = 0; #ifdef __32BIT__ DosOpenEventSem(NULL, &threadsem); DosResetEventSem(threadsem, &semcount); if (DosCreateThread(&threadid, (PFNTHREAD)rdserwrtscr, 0, 0, THRDSTKSIZ)) { printf("Sorry, can't create thread\n"); return (0); } DosWaitEventSem(threadsem, -1L); #else DosSemSet(&threadsem); /* Thread 2 will clear this when it starts */ if (DosCreateThread(rdserwrtscr, &threadid, (PBYTE)(stack + THRDSTKSIZ))) { printf("Sorry, can't create thread\n"); return (0); } DosSemWait(&threadsem, -1L);/* Wait for thread to start */ DosSemSet(&threadsem); /* Thread 2 will clear this on termination */ #endif while (active) { /* Read the keyboard and write to comms line */ c = congks(2); if (!active) break; if (c == -1) { active = network || (carrier == CAR_OFF) || (ttgmdm() & BM_DCD) != 0; if (!active) strcpy(termessage, "Carrier lost.\n"); continue; } cm = keymap[c]; DosEnterCritSec(); /* Protect the run time library */ if (cm == escape) { /* Look for escape char */ esc25(0); c = keymap[congks(0)]; /* Got esc, get its arg */ if (c == '?') { esc25(1); c = helpconnect(0); } doesc(c); /* And process it */ ipadl25(); } else { /* Ordinary character */ if (!keylock) vt100key(c); } DosExitCritSec(); /* Let other guy use run time library */ } /* while (active) */ #ifdef __32BIT__ DosWaitThread(&threadid, 0); DosCloseEventSem(threadsem); #else DosSemWait(&threadsem, -1L);/* Wait for other thread to terminate */ #endif language = langsv; /* Restore language */ concooked(); savescreen(&vt100screen); cursoron = TRUE; restorescreen(&commandscreen); restorecursormode(); if (termessage[0]!='\0') printf(termessage); if (hangnow) { #ifndef NODIAL if (mdmhup() < 1) #endif /* NODIAL */ tthang(); } if (quitnow) doexit(GOOD_EXIT,0); return (1); }