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 633686Sbostic * provided that this notice is preserved and that due credit is given 733686Sbostic * to the University of California at Berkeley. The name of the University 833686Sbostic * may not be used to endorse or promote products derived from this 933686Sbostic * software without specific prior written permission. This software 1033686Sbostic * is provided ``as is'' without express or implied warranty. 1133686Sbostic */ 1233686Sbostic 1333686Sbostic #ifndef lint 14*34303Sminshall static char sccsid[] = "@(#)tn3270.c 1.8 (Berkeley) 05/15/88"; 1533686Sbostic #endif /* not lint */ 1633686Sbostic 1733801Sminshall #include <sys/types.h> 1833801Sminshall #include <arpa/telnet.h> 1933801Sminshall 2033801Sminshall #include "defines.h" 2133801Sminshall #include "ring.h" 2233801Sminshall #include "externs.h" 2332657Sminshall #include "fdset.h" 2432657Sminshall 2532185Sminshall #if defined(TN3270) 2632185Sminshall 2733801Sminshall #include "../ctlr/screen.h" 2833801Sminshall #include "../general/globals.h" 2932185Sminshall 3033801Sminshall #if defined(unix) 3133801Sminshall char tline[200]; 3233801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 3333801Sminshall #endif /* defined(unix) */ 3432531Sminshall 3533801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 3632531Sminshall 3732531Sminshall static char sb_terminal[] = { IAC, SB, 3832531Sminshall TELOPT_TTYPE, TELQUAL_IS, 3932531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 4032531Sminshall IAC, SE }; 4132531Sminshall #define SBTERMMODEL 13 4232531Sminshall 4332531Sminshall static int 4432531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 4532531Sminshall 4633801Sminshall #endif /* defined(TN3270) */ 4732531Sminshall 4833801Sminshall 4933801Sminshall void 50*34303Sminshall init_3270() 5132551Sminshall { 5233801Sminshall #if defined(TN3270) 5333801Sminshall Sent3270TerminalType = 0; 5433801Sminshall Ifrontp = Ibackp = Ibuf; 5533801Sminshall init_ctlr(); /* Initialize some things */ 5633801Sminshall init_keyboard(); 5733801Sminshall init_screen(); 5833801Sminshall init_system(); 5933801Sminshall #endif /* defined(TN3270) */ 6032551Sminshall } 6132551Sminshall 6233801Sminshall 6333801Sminshall #if defined(TN3270) 6433801Sminshall 6532185Sminshall /* 6632185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 6732185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 6832185Sminshall * don't call us with "done" until you want that done...) 6932185Sminshall * 7032185Sminshall * We actually do send all the data to the network buffer, since our 7132185Sminshall * only client needs for us to do that. 7232185Sminshall */ 7332185Sminshall 7432185Sminshall int 7532185Sminshall DataToNetwork(buffer, count, done) 7632185Sminshall register char *buffer; /* where the data is */ 7732185Sminshall register int count; /* how much to send */ 7832185Sminshall int done; /* is this the last of a logical block */ 7932185Sminshall { 8033801Sminshall register int loop, c; 8132185Sminshall int origCount; 8232185Sminshall 8332185Sminshall origCount = count; 8432185Sminshall 8532185Sminshall while (count) { 86*34303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 8733801Sminshall if (NETROOM() < 6) { 8833801Sminshall fd_set o; 8933801Sminshall 9033801Sminshall FD_ZERO(&o); 9132185Sminshall netflush(); 9233801Sminshall while (NETROOM() < 6) { 9332185Sminshall FD_SET(net, &o); 9432185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 9532185Sminshall (struct timeval *) 0); 9632185Sminshall netflush(); 9732185Sminshall } 9832185Sminshall } 99*34303Sminshall c = ring_empty_count(&netoring); 100*34303Sminshall if (c > count) { 101*34303Sminshall c = count; 102*34303Sminshall } 103*34303Sminshall loop = c; 10433801Sminshall while (loop) { 10533801Sminshall if (*buffer == IAC) { 10633801Sminshall break; 10733801Sminshall } 10833801Sminshall buffer++; 10933801Sminshall loop--; 11032185Sminshall } 11133801Sminshall if ((c = c-loop)) { 11233801Sminshall ring_supply_data(&netoring, buffer-c, c); 11333801Sminshall count -= c; 11433801Sminshall } 11533801Sminshall if (loop) { 11633801Sminshall NET2ADD(IAC, IAC); 11733801Sminshall count--; 118*34303Sminshall buffer++; 11933801Sminshall } 12032185Sminshall } 12132185Sminshall 12233801Sminshall if (done) { 123*34303Sminshall NET2ADD(IAC, EOR); 12432185Sminshall netflush(); /* try to move along as quickly as ... */ 12532185Sminshall } 12632185Sminshall return(origCount - count); 12732185Sminshall } 12832185Sminshall 12932185Sminshall 13032185Sminshall #if defined(unix) 13133801Sminshall void 13232185Sminshall inputAvailable() 13332185Sminshall { 13432185Sminshall HaveInput = 1; 13532185Sminshall } 13632185Sminshall #endif /* defined(unix) */ 13732185Sminshall 13832185Sminshall void 13932185Sminshall outputPurge() 14032185Sminshall { 14132257Sminshall ttyflush(1); 14232185Sminshall } 14332185Sminshall 14432185Sminshall 14532185Sminshall /* 14632185Sminshall * The following routines are places where the various tn3270 14732185Sminshall * routines make calls into telnet.c. 14832185Sminshall */ 14932185Sminshall 150*34303Sminshall /* 151*34303Sminshall * DataToTerminal - queue up some data to go to terminal. 152*34303Sminshall * 153*34303Sminshall * Note: there are people who call us and depend on our processing 154*34303Sminshall * *all* the data at one time (thus the select). 155*34303Sminshall */ 15632185Sminshall 15732185Sminshall int 15832185Sminshall DataToTerminal(buffer, count) 15932185Sminshall register char *buffer; /* where the data is */ 16032185Sminshall register int count; /* how much to send */ 16132185Sminshall { 16233801Sminshall register int loop, c; 16332185Sminshall int origCount; 16432185Sminshall 16532185Sminshall origCount = count; 16632185Sminshall 16732185Sminshall while (count) { 16833801Sminshall if (TTYROOM() == 0) { 16932185Sminshall #if defined(unix) 17033801Sminshall fd_set o; 17133801Sminshall 17233801Sminshall FD_ZERO(&o); 17333801Sminshall #endif /* defined(unix) */ 17433801Sminshall ttyflush(); 17533801Sminshall while (TTYROOM() == 0) { 17633801Sminshall #if defined(unix) 17732185Sminshall FD_SET(tout, &o); 17832185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 17932185Sminshall (struct timeval *) 0); 18032185Sminshall #endif /* defined(unix) */ 18133801Sminshall ttyflush(); 18232185Sminshall } 18332185Sminshall } 184*34303Sminshall c = TTYROOM(); 185*34303Sminshall if (c > count) { 186*34303Sminshall c = count; 18733801Sminshall } 188*34303Sminshall ring_supply_data(&ttyoring, buffer, c); 189*34303Sminshall count -= c; 190*34303Sminshall buffer += c; 19132185Sminshall } 192*34303Sminshall return(origCount); 19332185Sminshall } 19432185Sminshall 19532185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 19632185Sminshall * Note that we consider the buffer to run all the 19732185Sminshall * way to the kernel (thus the select). 19832185Sminshall */ 19932185Sminshall 20032185Sminshall void 20132185Sminshall EmptyTerminal() 20232185Sminshall { 20332185Sminshall #if defined(unix) 20432185Sminshall fd_set o; 20532185Sminshall 20632185Sminshall FD_ZERO(&o); 20732185Sminshall #endif /* defined(unix) */ 20832185Sminshall 209*34303Sminshall if (TTYBYTES() == 0) { 21032185Sminshall #if defined(unix) 21132185Sminshall FD_SET(tout, &o); 21232185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 21332185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 21432185Sminshall #endif /* defined(unix) */ 21532185Sminshall } else { 21633801Sminshall while (TTYBYTES()) { 21732257Sminshall ttyflush(0); 21832185Sminshall #if defined(unix) 21932185Sminshall FD_SET(tout, &o); 22032185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 22132185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 22232185Sminshall #endif /* defined(unix) */ 22332185Sminshall } 22432185Sminshall } 22532185Sminshall } 22632185Sminshall 22732185Sminshall 22832185Sminshall /* 22932185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 23032185Sminshall */ 23132185Sminshall 23233801Sminshall int 23332185Sminshall Push3270() 23432185Sminshall { 23533801Sminshall int save = ring_full_count(&netiring); 23632185Sminshall 23733801Sminshall if (save) { 23833801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 23932185Sminshall if (Ibackp != Ibuf) { 24032185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 24132185Sminshall Ifrontp -= (Ibackp-Ibuf); 24232185Sminshall Ibackp = Ibuf; 24332185Sminshall } 24432185Sminshall } 24533801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 24632185Sminshall telrcv(); 24732185Sminshall } 24832185Sminshall } 24933801Sminshall return save != ring_full_count(&netiring); 25032185Sminshall } 25132185Sminshall 25232185Sminshall 25332185Sminshall /* 25432185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 25532185Sminshall * before quitting. 25632185Sminshall */ 25732185Sminshall 25833801Sminshall void 25932185Sminshall Finish3270() 26032185Sminshall { 26132185Sminshall while (Push3270() || !DoTerminalOutput()) { 26232185Sminshall #if defined(unix) 26332185Sminshall HaveInput = 0; 26432185Sminshall #endif /* defined(unix) */ 26532185Sminshall ; 26632185Sminshall } 26732185Sminshall } 26832185Sminshall 26932185Sminshall 27032185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 27132185Sminshall 27232185Sminshall void 27332185Sminshall StringToTerminal(s) 27432185Sminshall char *s; 27532185Sminshall { 27632185Sminshall int count; 27732185Sminshall 27832185Sminshall count = strlen(s); 27932185Sminshall if (count) { 28032185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 28132185Sminshall } 28232185Sminshall } 28332185Sminshall 28432185Sminshall 28532185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 28632185Sminshall /* _putchar - output a single character to the terminal. This name is so that 28732185Sminshall * curses(3x) can call us to send out data. 28832185Sminshall */ 28932185Sminshall 29032185Sminshall void 29132185Sminshall _putchar(c) 29232185Sminshall char c; 29332185Sminshall { 29433801Sminshall if (TTYBYTES()) { 29532185Sminshall (void) DataToTerminal(&c, 1); 29632185Sminshall } else { 29733801Sminshall TTYADD(c); 29832185Sminshall } 29932185Sminshall } 30032185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 30132185Sminshall 30232531Sminshall void 30332531Sminshall SetForExit() 30432531Sminshall { 30532531Sminshall setconnmode(); 30632531Sminshall if (In3270) { 30732531Sminshall Finish3270(); 30832531Sminshall } 30932531Sminshall setcommandmode(); 31032531Sminshall fflush(stdout); 31132531Sminshall fflush(stderr); 31232531Sminshall if (In3270) { 31332531Sminshall StopScreen(1); 31432531Sminshall } 31532531Sminshall setconnmode(); 31632531Sminshall setcommandmode(); 31732531Sminshall } 31832531Sminshall 31932531Sminshall void 32032531Sminshall Exit(returnCode) 32132531Sminshall int returnCode; 32232531Sminshall { 32332531Sminshall SetForExit(); 32432531Sminshall exit(returnCode); 32532531Sminshall } 32632531Sminshall 32732531Sminshall void 32832531Sminshall ExitString(string, returnCode) 32932531Sminshall char *string; 33032531Sminshall int returnCode; 33132531Sminshall { 33232531Sminshall SetForExit(); 33332531Sminshall fwrite(string, 1, strlen(string), stderr); 33432531Sminshall exit(returnCode); 33532531Sminshall } 33632531Sminshall 33732531Sminshall void 33832531Sminshall ExitPerror(string, returnCode) 33932531Sminshall char *string; 34032531Sminshall int returnCode; 34132531Sminshall { 34232531Sminshall SetForExit(); 34332531Sminshall perror(string); 34432531Sminshall exit(returnCode); 34532531Sminshall } 34632531Sminshall 34732531Sminshall void 34832531Sminshall SetIn3270() 34932531Sminshall { 35032531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 35132531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 35232531Sminshall if (!In3270) { 35332531Sminshall In3270 = 1; 35432531Sminshall Init3270(); /* Initialize 3270 functions */ 35532531Sminshall /* initialize terminal key mapping */ 35632531Sminshall InitTerminal(); /* Start terminal going */ 35732531Sminshall setconnmode(); 35832531Sminshall } 35932531Sminshall } else { 36032531Sminshall if (In3270) { 36132531Sminshall StopScreen(1); 36232531Sminshall In3270 = 0; 36332531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 36432531Sminshall setconnmode(); 36532531Sminshall } 36632531Sminshall } 36732531Sminshall } 36832531Sminshall 36932531Sminshall /* 37032531Sminshall * tn3270_ttype() 37132531Sminshall * 37232531Sminshall * Send a response to a terminal type negotiation. 37332531Sminshall * 37432531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 37532531Sminshall */ 37632531Sminshall 37732531Sminshall int 37832531Sminshall tn3270_ttype() 37932531Sminshall { 38032531Sminshall /* 38132531Sminshall * Try to send a 3270 type terminal name. Decide which one based 38232531Sminshall * on the format of our screen, and (in the future) color 38332531Sminshall * capaiblities. 38432531Sminshall */ 38532531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 38632531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 38732531Sminshall Sent3270TerminalType = 1; 38832531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 38932531Sminshall MaxNumberLines = 27; 39032531Sminshall MaxNumberColumns = 132; 39132531Sminshall sb_terminal[SBTERMMODEL] = '5'; 39232531Sminshall } else if (MaxNumberLines >= 43) { 39332531Sminshall MaxNumberLines = 43; 39432531Sminshall MaxNumberColumns = 80; 39532531Sminshall sb_terminal[SBTERMMODEL] = '4'; 39632531Sminshall } else if (MaxNumberLines >= 32) { 39732531Sminshall MaxNumberLines = 32; 39832531Sminshall MaxNumberColumns = 80; 39932531Sminshall sb_terminal[SBTERMMODEL] = '3'; 40032531Sminshall } else { 40132531Sminshall MaxNumberLines = 24; 40232531Sminshall MaxNumberColumns = 80; 40332531Sminshall sb_terminal[SBTERMMODEL] = '2'; 40432531Sminshall } 40532531Sminshall NumberLines = 24; /* before we start out... */ 40632531Sminshall NumberColumns = 80; 40732531Sminshall ScreenSize = NumberLines*NumberColumns; 40832531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 40932531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 41032531Sminshall 1); 41132531Sminshall /*NOTREACHED*/ 41232531Sminshall } 41332531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 41432531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 41532531Sminshall return 1; 41632531Sminshall } else { 41732531Sminshall return 0; 41832531Sminshall } 41932531Sminshall } 42033801Sminshall 42133801Sminshall #if defined(unix) 42233801Sminshall settranscom(argc, argv) 42333801Sminshall int argc; 42433801Sminshall char *argv[]; 42533801Sminshall { 42633801Sminshall int i, len = 0; 42733801Sminshall 42833801Sminshall if (argc == 1 && transcom) { 42933801Sminshall transcom = 0; 43033801Sminshall } 43133801Sminshall if (argc == 1) { 43233801Sminshall return; 43333801Sminshall } 43433801Sminshall for (i = 1; i < argc; ++i) { 43533801Sminshall len += 1 + strlen(argv[1]); 43633801Sminshall } 43733801Sminshall transcom = tline; 43833801Sminshall (void) strcpy(transcom, argv[1]); 43933801Sminshall for (i = 2; i < argc; ++i) { 44033801Sminshall (void) strcat(transcom, " "); 44133801Sminshall (void) strcat(transcom, argv[i]); 44233801Sminshall } 44333801Sminshall } 44433801Sminshall #endif /* defined(unix) */ 44533801Sminshall 44632185Sminshall #endif /* defined(TN3270) */ 447