133686Sbostic /* 233686Sbostic * Copyright (c) 1988 Regents of the University of California. 333686Sbostic * All rights reserved. 433686Sbostic * 533686Sbostic * Redistribution and use in source and binary forms are permitted 634898Sbostic * provided that the above copyright notice and this paragraph are 734898Sbostic * duplicated in all such forms and that any documentation, 834898Sbostic * advertising materials, and other materials related to such 934898Sbostic * distribution and use acknowledge that the software was developed 1034898Sbostic * by the University of California, Berkeley. The name of the 1134898Sbostic * University may not be used to endorse or promote products derived 1234898Sbostic * from this software without specific prior written permission. 1334898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633686Sbostic */ 1733686Sbostic 1833686Sbostic #ifndef lint 19*36240Sminshall static char sccsid[] = "@(#)tn3270.c 1.15 (Berkeley) 11/18/88"; 2033686Sbostic #endif /* not lint */ 2133686Sbostic 2233801Sminshall #include <sys/types.h> 2333801Sminshall #include <arpa/telnet.h> 2433801Sminshall 2534305Sminshall #include "general.h" 2634305Sminshall 2733801Sminshall #include "defines.h" 2833801Sminshall #include "ring.h" 2933801Sminshall #include "externs.h" 3032657Sminshall #include "fdset.h" 3132657Sminshall 3232185Sminshall #if defined(TN3270) 3332185Sminshall 3433801Sminshall #include "../ctlr/screen.h" 3533801Sminshall #include "../general/globals.h" 3632185Sminshall 3735417Sminshall #include "../telextrn.h" 3835417Sminshall #include "../ctlr/externs.h" 3935417Sminshall 4033801Sminshall #if defined(unix) 41*36240Sminshall int 42*36240Sminshall HaveInput, /* There is input available to scan */ 43*36240Sminshall sigiocount; /* Number of times we got a SIGIO */ 44*36240Sminshall 4533801Sminshall char tline[200]; 4633801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 4733801Sminshall #endif /* defined(unix) */ 4832531Sminshall 4933801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 5032531Sminshall 5132531Sminshall static char sb_terminal[] = { IAC, SB, 5232531Sminshall TELOPT_TTYPE, TELQUAL_IS, 5332531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 5432531Sminshall IAC, SE }; 5532531Sminshall #define SBTERMMODEL 13 5632531Sminshall 5732531Sminshall static int 5832531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 5932531Sminshall 6033801Sminshall #endif /* defined(TN3270) */ 6132531Sminshall 6233801Sminshall 6333801Sminshall void 6434303Sminshall init_3270() 6532551Sminshall { 6633801Sminshall #if defined(TN3270) 67*36240Sminshall #if defined(unix) 68*36240Sminshall HaveInput = 0; 69*36240Sminshall sigiocount = 0; 70*36240Sminshall #endif /* defined(unix) */ 7133801Sminshall Sent3270TerminalType = 0; 7233801Sminshall Ifrontp = Ibackp = Ibuf; 7333801Sminshall init_ctlr(); /* Initialize some things */ 7433801Sminshall init_keyboard(); 7533801Sminshall init_screen(); 7633801Sminshall init_system(); 7733801Sminshall #endif /* defined(TN3270) */ 7832551Sminshall } 7932551Sminshall 8033801Sminshall 8133801Sminshall #if defined(TN3270) 8233801Sminshall 8332185Sminshall /* 8432185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 8532185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 8632185Sminshall * don't call us with "done" until you want that done...) 8732185Sminshall * 8832185Sminshall * We actually do send all the data to the network buffer, since our 8932185Sminshall * only client needs for us to do that. 9032185Sminshall */ 9132185Sminshall 9232185Sminshall int 9332185Sminshall DataToNetwork(buffer, count, done) 9432185Sminshall register char *buffer; /* where the data is */ 9532185Sminshall register int count; /* how much to send */ 9632185Sminshall int done; /* is this the last of a logical block */ 9732185Sminshall { 9833801Sminshall register int loop, c; 9932185Sminshall int origCount; 10032185Sminshall 10132185Sminshall origCount = count; 10232185Sminshall 10332185Sminshall while (count) { 10434303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 10533801Sminshall if (NETROOM() < 6) { 10633801Sminshall fd_set o; 10733801Sminshall 10833801Sminshall FD_ZERO(&o); 10932185Sminshall netflush(); 11033801Sminshall while (NETROOM() < 6) { 11132185Sminshall FD_SET(net, &o); 11232185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 11332185Sminshall (struct timeval *) 0); 11432185Sminshall netflush(); 11532185Sminshall } 11632185Sminshall } 11734303Sminshall c = ring_empty_count(&netoring); 11834303Sminshall if (c > count) { 11934303Sminshall c = count; 12034303Sminshall } 12134303Sminshall loop = c; 12233801Sminshall while (loop) { 12334311Sminshall if (((unsigned char)*buffer) == IAC) { 12433801Sminshall break; 12533801Sminshall } 12633801Sminshall buffer++; 12733801Sminshall loop--; 12832185Sminshall } 12933801Sminshall if ((c = c-loop)) { 13033801Sminshall ring_supply_data(&netoring, buffer-c, c); 13133801Sminshall count -= c; 13233801Sminshall } 13333801Sminshall if (loop) { 13433801Sminshall NET2ADD(IAC, IAC); 13533801Sminshall count--; 13634303Sminshall buffer++; 13733801Sminshall } 13832185Sminshall } 13932185Sminshall 14033801Sminshall if (done) { 14134303Sminshall NET2ADD(IAC, EOR); 14232185Sminshall netflush(); /* try to move along as quickly as ... */ 14332185Sminshall } 14432185Sminshall return(origCount - count); 14532185Sminshall } 14632185Sminshall 14732185Sminshall 14832185Sminshall #if defined(unix) 14933801Sminshall void 15032185Sminshall inputAvailable() 15132185Sminshall { 15232185Sminshall HaveInput = 1; 153*36240Sminshall sigiocount++; 15432185Sminshall } 15532185Sminshall #endif /* defined(unix) */ 15632185Sminshall 15732185Sminshall void 15832185Sminshall outputPurge() 15932185Sminshall { 16032257Sminshall ttyflush(1); 16132185Sminshall } 16232185Sminshall 16332185Sminshall 16432185Sminshall /* 16532185Sminshall * The following routines are places where the various tn3270 16632185Sminshall * routines make calls into telnet.c. 16732185Sminshall */ 16832185Sminshall 16934303Sminshall /* 17034303Sminshall * DataToTerminal - queue up some data to go to terminal. 17134303Sminshall * 17234303Sminshall * Note: there are people who call us and depend on our processing 17334303Sminshall * *all* the data at one time (thus the select). 17434303Sminshall */ 17532185Sminshall 17632185Sminshall int 17732185Sminshall DataToTerminal(buffer, count) 17832185Sminshall register char *buffer; /* where the data is */ 17932185Sminshall register int count; /* how much to send */ 18032185Sminshall { 18135417Sminshall register int c; 18232185Sminshall int origCount; 18332185Sminshall 18432185Sminshall origCount = count; 18532185Sminshall 18632185Sminshall while (count) { 18733801Sminshall if (TTYROOM() == 0) { 18832185Sminshall #if defined(unix) 18933801Sminshall fd_set o; 19033801Sminshall 19133801Sminshall FD_ZERO(&o); 19233801Sminshall #endif /* defined(unix) */ 19335417Sminshall ttyflush(0); 19433801Sminshall while (TTYROOM() == 0) { 19533801Sminshall #if defined(unix) 19632185Sminshall FD_SET(tout, &o); 19732185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 19832185Sminshall (struct timeval *) 0); 19932185Sminshall #endif /* defined(unix) */ 20035417Sminshall ttyflush(0); 20132185Sminshall } 20232185Sminshall } 20334303Sminshall c = TTYROOM(); 20434303Sminshall if (c > count) { 20534303Sminshall c = count; 20633801Sminshall } 20734303Sminshall ring_supply_data(&ttyoring, buffer, c); 20834303Sminshall count -= c; 20934303Sminshall buffer += c; 21032185Sminshall } 21134303Sminshall return(origCount); 21232185Sminshall } 21332185Sminshall 21432185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 21532185Sminshall * Note that we consider the buffer to run all the 21632185Sminshall * way to the kernel (thus the select). 21732185Sminshall */ 21832185Sminshall 21932185Sminshall void 22032185Sminshall EmptyTerminal() 22132185Sminshall { 22232185Sminshall #if defined(unix) 22332185Sminshall fd_set o; 22432185Sminshall 22532185Sminshall FD_ZERO(&o); 22632185Sminshall #endif /* defined(unix) */ 22732185Sminshall 22834303Sminshall if (TTYBYTES() == 0) { 22932185Sminshall #if defined(unix) 23032185Sminshall FD_SET(tout, &o); 23135417Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 23232185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 23332185Sminshall #endif /* defined(unix) */ 23432185Sminshall } else { 23533801Sminshall while (TTYBYTES()) { 23632257Sminshall ttyflush(0); 23732185Sminshall #if defined(unix) 23832185Sminshall FD_SET(tout, &o); 23935417Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 24032185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 24132185Sminshall #endif /* defined(unix) */ 24232185Sminshall } 24332185Sminshall } 24432185Sminshall } 24532185Sminshall 24632185Sminshall 24732185Sminshall /* 24832185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 24932185Sminshall */ 25032185Sminshall 25133801Sminshall int 25232185Sminshall Push3270() 25332185Sminshall { 25433801Sminshall int save = ring_full_count(&netiring); 25532185Sminshall 25633801Sminshall if (save) { 25733801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 25832185Sminshall if (Ibackp != Ibuf) { 25932185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 26032185Sminshall Ifrontp -= (Ibackp-Ibuf); 26132185Sminshall Ibackp = Ibuf; 26232185Sminshall } 26332185Sminshall } 26433801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 26532185Sminshall telrcv(); 26632185Sminshall } 26732185Sminshall } 26833801Sminshall return save != ring_full_count(&netiring); 26932185Sminshall } 27032185Sminshall 27132185Sminshall 27232185Sminshall /* 27332185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 27432185Sminshall * before quitting. 27532185Sminshall */ 27632185Sminshall 27733801Sminshall void 27832185Sminshall Finish3270() 27932185Sminshall { 28032185Sminshall while (Push3270() || !DoTerminalOutput()) { 28132185Sminshall #if defined(unix) 28232185Sminshall HaveInput = 0; 28332185Sminshall #endif /* defined(unix) */ 28432185Sminshall ; 28532185Sminshall } 28632185Sminshall } 28732185Sminshall 28832185Sminshall 28932185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 29032185Sminshall 29132185Sminshall void 29232185Sminshall StringToTerminal(s) 29332185Sminshall char *s; 29432185Sminshall { 29532185Sminshall int count; 29632185Sminshall 29732185Sminshall count = strlen(s); 29832185Sminshall if (count) { 29932185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 30032185Sminshall } 30132185Sminshall } 30232185Sminshall 30332185Sminshall 30432185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 30532185Sminshall /* _putchar - output a single character to the terminal. This name is so that 30632185Sminshall * curses(3x) can call us to send out data. 30732185Sminshall */ 30832185Sminshall 30932185Sminshall void 31032185Sminshall _putchar(c) 31132185Sminshall char c; 31232185Sminshall { 31336201Sminshall #if defined(sun) /* SunOS 4.0 bug */ 31436201Sminshall c &= 0x7f; 31536201Sminshall #endif /* defined(sun) */ 316*36240Sminshall if (!TTYROOM()) { 31732185Sminshall (void) DataToTerminal(&c, 1); 31832185Sminshall } else { 31933801Sminshall TTYADD(c); 32032185Sminshall } 32132185Sminshall } 32232185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 32332185Sminshall 32432531Sminshall void 32532531Sminshall SetForExit() 32632531Sminshall { 32732531Sminshall setconnmode(); 32832531Sminshall if (In3270) { 32932531Sminshall Finish3270(); 33032531Sminshall } 33132531Sminshall setcommandmode(); 33232531Sminshall fflush(stdout); 33332531Sminshall fflush(stderr); 33432531Sminshall if (In3270) { 33532531Sminshall StopScreen(1); 33632531Sminshall } 33732531Sminshall setconnmode(); 33832531Sminshall setcommandmode(); 33932531Sminshall } 34032531Sminshall 34132531Sminshall void 34232531Sminshall Exit(returnCode) 34332531Sminshall int returnCode; 34432531Sminshall { 34532531Sminshall SetForExit(); 34632531Sminshall exit(returnCode); 34732531Sminshall } 34832531Sminshall 34932531Sminshall void 35032531Sminshall ExitString(string, returnCode) 35132531Sminshall char *string; 35232531Sminshall int returnCode; 35332531Sminshall { 35432531Sminshall SetForExit(); 35532531Sminshall fwrite(string, 1, strlen(string), stderr); 35632531Sminshall exit(returnCode); 35732531Sminshall } 35832531Sminshall 35935417Sminshall #if defined(MSDOS) 36032531Sminshall void 36132531Sminshall ExitPerror(string, returnCode) 36232531Sminshall char *string; 36332531Sminshall int returnCode; 36432531Sminshall { 36532531Sminshall SetForExit(); 36632531Sminshall perror(string); 36732531Sminshall exit(returnCode); 36832531Sminshall } 36935417Sminshall #endif /* defined(MSDOS) */ 37032531Sminshall 37132531Sminshall void 37232531Sminshall SetIn3270() 37332531Sminshall { 37432531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 37532531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 37632531Sminshall if (!In3270) { 37732531Sminshall In3270 = 1; 37832531Sminshall Init3270(); /* Initialize 3270 functions */ 37932531Sminshall /* initialize terminal key mapping */ 38032531Sminshall InitTerminal(); /* Start terminal going */ 38132531Sminshall setconnmode(); 38232531Sminshall } 38332531Sminshall } else { 38432531Sminshall if (In3270) { 38532531Sminshall StopScreen(1); 38632531Sminshall In3270 = 0; 38732531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 38832531Sminshall setconnmode(); 38932531Sminshall } 39032531Sminshall } 39132531Sminshall } 39232531Sminshall 39332531Sminshall /* 39432531Sminshall * tn3270_ttype() 39532531Sminshall * 39632531Sminshall * Send a response to a terminal type negotiation. 39732531Sminshall * 39832531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 39932531Sminshall */ 40032531Sminshall 40132531Sminshall int 40232531Sminshall tn3270_ttype() 40332531Sminshall { 40432531Sminshall /* 40532531Sminshall * Try to send a 3270 type terminal name. Decide which one based 40632531Sminshall * on the format of our screen, and (in the future) color 40732531Sminshall * capaiblities. 40832531Sminshall */ 40932531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 41032531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 41132531Sminshall Sent3270TerminalType = 1; 41232531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 41332531Sminshall MaxNumberLines = 27; 41432531Sminshall MaxNumberColumns = 132; 41532531Sminshall sb_terminal[SBTERMMODEL] = '5'; 41632531Sminshall } else if (MaxNumberLines >= 43) { 41732531Sminshall MaxNumberLines = 43; 41832531Sminshall MaxNumberColumns = 80; 41932531Sminshall sb_terminal[SBTERMMODEL] = '4'; 42032531Sminshall } else if (MaxNumberLines >= 32) { 42132531Sminshall MaxNumberLines = 32; 42232531Sminshall MaxNumberColumns = 80; 42332531Sminshall sb_terminal[SBTERMMODEL] = '3'; 42432531Sminshall } else { 42532531Sminshall MaxNumberLines = 24; 42632531Sminshall MaxNumberColumns = 80; 42732531Sminshall sb_terminal[SBTERMMODEL] = '2'; 42832531Sminshall } 42932531Sminshall NumberLines = 24; /* before we start out... */ 43032531Sminshall NumberColumns = 80; 43132531Sminshall ScreenSize = NumberLines*NumberColumns; 43232531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 43332531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 43432531Sminshall 1); 43532531Sminshall /*NOTREACHED*/ 43632531Sminshall } 43732531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 43832531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 43932531Sminshall return 1; 44032531Sminshall } else { 44132531Sminshall return 0; 44232531Sminshall } 44332531Sminshall } 44433801Sminshall 44533801Sminshall #if defined(unix) 44633801Sminshall settranscom(argc, argv) 44733801Sminshall int argc; 44833801Sminshall char *argv[]; 44933801Sminshall { 45035417Sminshall int i; 45133801Sminshall 45233801Sminshall if (argc == 1 && transcom) { 45333801Sminshall transcom = 0; 45433801Sminshall } 45533801Sminshall if (argc == 1) { 45633801Sminshall return; 45733801Sminshall } 45833801Sminshall transcom = tline; 45933801Sminshall (void) strcpy(transcom, argv[1]); 46033801Sminshall for (i = 2; i < argc; ++i) { 46133801Sminshall (void) strcat(transcom, " "); 46233801Sminshall (void) strcat(transcom, argv[i]); 46333801Sminshall } 46433801Sminshall } 46533801Sminshall #endif /* defined(unix) */ 46633801Sminshall 46732185Sminshall #endif /* defined(TN3270) */ 468