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*34311Sminshall static char sccsid[] = "@(#)tn3270.c 1.10 (Berkeley) 05/15/88"; 1533686Sbostic #endif /* not lint */ 1633686Sbostic 1733801Sminshall #include <sys/types.h> 1833801Sminshall #include <arpa/telnet.h> 1933801Sminshall 2034305Sminshall #include "general.h" 2134305Sminshall 2233801Sminshall #include "defines.h" 2333801Sminshall #include "ring.h" 2433801Sminshall #include "externs.h" 2532657Sminshall #include "fdset.h" 2632657Sminshall 2732185Sminshall #if defined(TN3270) 2832185Sminshall 2933801Sminshall #include "../ctlr/screen.h" 3033801Sminshall #include "../general/globals.h" 3132185Sminshall 3233801Sminshall #if defined(unix) 3333801Sminshall char tline[200]; 3433801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 3533801Sminshall #endif /* defined(unix) */ 3632531Sminshall 3733801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 3832531Sminshall 3932531Sminshall static char sb_terminal[] = { IAC, SB, 4032531Sminshall TELOPT_TTYPE, TELQUAL_IS, 4132531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 4232531Sminshall IAC, SE }; 4332531Sminshall #define SBTERMMODEL 13 4432531Sminshall 4532531Sminshall static int 4632531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 4732531Sminshall 4833801Sminshall #endif /* defined(TN3270) */ 4932531Sminshall 5033801Sminshall 5133801Sminshall void 5234303Sminshall init_3270() 5332551Sminshall { 5433801Sminshall #if defined(TN3270) 5533801Sminshall Sent3270TerminalType = 0; 5633801Sminshall Ifrontp = Ibackp = Ibuf; 5733801Sminshall init_ctlr(); /* Initialize some things */ 5833801Sminshall init_keyboard(); 5933801Sminshall init_screen(); 6033801Sminshall init_system(); 6133801Sminshall #endif /* defined(TN3270) */ 6232551Sminshall } 6332551Sminshall 6433801Sminshall 6533801Sminshall #if defined(TN3270) 6633801Sminshall 6732185Sminshall /* 6832185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 6932185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 7032185Sminshall * don't call us with "done" until you want that done...) 7132185Sminshall * 7232185Sminshall * We actually do send all the data to the network buffer, since our 7332185Sminshall * only client needs for us to do that. 7432185Sminshall */ 7532185Sminshall 7632185Sminshall int 7732185Sminshall DataToNetwork(buffer, count, done) 7832185Sminshall register char *buffer; /* where the data is */ 7932185Sminshall register int count; /* how much to send */ 8032185Sminshall int done; /* is this the last of a logical block */ 8132185Sminshall { 8233801Sminshall register int loop, c; 8332185Sminshall int origCount; 8432185Sminshall 8532185Sminshall origCount = count; 8632185Sminshall 8732185Sminshall while (count) { 8834303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 8933801Sminshall if (NETROOM() < 6) { 9033801Sminshall fd_set o; 9133801Sminshall 9233801Sminshall FD_ZERO(&o); 9332185Sminshall netflush(); 9433801Sminshall while (NETROOM() < 6) { 9532185Sminshall FD_SET(net, &o); 9632185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 9732185Sminshall (struct timeval *) 0); 9832185Sminshall netflush(); 9932185Sminshall } 10032185Sminshall } 10134303Sminshall c = ring_empty_count(&netoring); 10234303Sminshall if (c > count) { 10334303Sminshall c = count; 10434303Sminshall } 10534303Sminshall loop = c; 10633801Sminshall while (loop) { 107*34311Sminshall if (((unsigned char)*buffer) == IAC) { 10833801Sminshall break; 10933801Sminshall } 11033801Sminshall buffer++; 11133801Sminshall loop--; 11232185Sminshall } 11333801Sminshall if ((c = c-loop)) { 11433801Sminshall ring_supply_data(&netoring, buffer-c, c); 11533801Sminshall count -= c; 11633801Sminshall } 11733801Sminshall if (loop) { 11833801Sminshall NET2ADD(IAC, IAC); 11933801Sminshall count--; 12034303Sminshall buffer++; 12133801Sminshall } 12232185Sminshall } 12332185Sminshall 12433801Sminshall if (done) { 12534303Sminshall NET2ADD(IAC, EOR); 12632185Sminshall netflush(); /* try to move along as quickly as ... */ 12732185Sminshall } 12832185Sminshall return(origCount - count); 12932185Sminshall } 13032185Sminshall 13132185Sminshall 13232185Sminshall #if defined(unix) 13333801Sminshall void 13432185Sminshall inputAvailable() 13532185Sminshall { 13632185Sminshall HaveInput = 1; 13732185Sminshall } 13832185Sminshall #endif /* defined(unix) */ 13932185Sminshall 14032185Sminshall void 14132185Sminshall outputPurge() 14232185Sminshall { 14332257Sminshall ttyflush(1); 14432185Sminshall } 14532185Sminshall 14632185Sminshall 14732185Sminshall /* 14832185Sminshall * The following routines are places where the various tn3270 14932185Sminshall * routines make calls into telnet.c. 15032185Sminshall */ 15132185Sminshall 15234303Sminshall /* 15334303Sminshall * DataToTerminal - queue up some data to go to terminal. 15434303Sminshall * 15534303Sminshall * Note: there are people who call us and depend on our processing 15634303Sminshall * *all* the data at one time (thus the select). 15734303Sminshall */ 15832185Sminshall 15932185Sminshall int 16032185Sminshall DataToTerminal(buffer, count) 16132185Sminshall register char *buffer; /* where the data is */ 16232185Sminshall register int count; /* how much to send */ 16332185Sminshall { 16433801Sminshall register int loop, c; 16532185Sminshall int origCount; 16632185Sminshall 16732185Sminshall origCount = count; 16832185Sminshall 16932185Sminshall while (count) { 17033801Sminshall if (TTYROOM() == 0) { 17132185Sminshall #if defined(unix) 17233801Sminshall fd_set o; 17333801Sminshall 17433801Sminshall FD_ZERO(&o); 17533801Sminshall #endif /* defined(unix) */ 17633801Sminshall ttyflush(); 17733801Sminshall while (TTYROOM() == 0) { 17833801Sminshall #if defined(unix) 17932185Sminshall FD_SET(tout, &o); 18032185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 18132185Sminshall (struct timeval *) 0); 18232185Sminshall #endif /* defined(unix) */ 18333801Sminshall ttyflush(); 18432185Sminshall } 18532185Sminshall } 18634303Sminshall c = TTYROOM(); 18734303Sminshall if (c > count) { 18834303Sminshall c = count; 18933801Sminshall } 19034303Sminshall ring_supply_data(&ttyoring, buffer, c); 19134303Sminshall count -= c; 19234303Sminshall buffer += c; 19332185Sminshall } 19434303Sminshall return(origCount); 19532185Sminshall } 19632185Sminshall 19732185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 19832185Sminshall * Note that we consider the buffer to run all the 19932185Sminshall * way to the kernel (thus the select). 20032185Sminshall */ 20132185Sminshall 20232185Sminshall void 20332185Sminshall EmptyTerminal() 20432185Sminshall { 20532185Sminshall #if defined(unix) 20632185Sminshall fd_set o; 20732185Sminshall 20832185Sminshall FD_ZERO(&o); 20932185Sminshall #endif /* defined(unix) */ 21032185Sminshall 21134303Sminshall if (TTYBYTES() == 0) { 21232185Sminshall #if defined(unix) 21332185Sminshall FD_SET(tout, &o); 21432185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 21532185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 21632185Sminshall #endif /* defined(unix) */ 21732185Sminshall } else { 21833801Sminshall while (TTYBYTES()) { 21932257Sminshall ttyflush(0); 22032185Sminshall #if defined(unix) 22132185Sminshall FD_SET(tout, &o); 22232185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 22332185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 22432185Sminshall #endif /* defined(unix) */ 22532185Sminshall } 22632185Sminshall } 22732185Sminshall } 22832185Sminshall 22932185Sminshall 23032185Sminshall /* 23132185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 23232185Sminshall */ 23332185Sminshall 23433801Sminshall int 23532185Sminshall Push3270() 23632185Sminshall { 23733801Sminshall int save = ring_full_count(&netiring); 23832185Sminshall 23933801Sminshall if (save) { 24033801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 24132185Sminshall if (Ibackp != Ibuf) { 24232185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 24332185Sminshall Ifrontp -= (Ibackp-Ibuf); 24432185Sminshall Ibackp = Ibuf; 24532185Sminshall } 24632185Sminshall } 24733801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 24832185Sminshall telrcv(); 24932185Sminshall } 25032185Sminshall } 25133801Sminshall return save != ring_full_count(&netiring); 25232185Sminshall } 25332185Sminshall 25432185Sminshall 25532185Sminshall /* 25632185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 25732185Sminshall * before quitting. 25832185Sminshall */ 25932185Sminshall 26033801Sminshall void 26132185Sminshall Finish3270() 26232185Sminshall { 26332185Sminshall while (Push3270() || !DoTerminalOutput()) { 26432185Sminshall #if defined(unix) 26532185Sminshall HaveInput = 0; 26632185Sminshall #endif /* defined(unix) */ 26732185Sminshall ; 26832185Sminshall } 26932185Sminshall } 27032185Sminshall 27132185Sminshall 27232185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 27332185Sminshall 27432185Sminshall void 27532185Sminshall StringToTerminal(s) 27632185Sminshall char *s; 27732185Sminshall { 27832185Sminshall int count; 27932185Sminshall 28032185Sminshall count = strlen(s); 28132185Sminshall if (count) { 28232185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 28332185Sminshall } 28432185Sminshall } 28532185Sminshall 28632185Sminshall 28732185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 28832185Sminshall /* _putchar - output a single character to the terminal. This name is so that 28932185Sminshall * curses(3x) can call us to send out data. 29032185Sminshall */ 29132185Sminshall 29232185Sminshall void 29332185Sminshall _putchar(c) 29432185Sminshall char c; 29532185Sminshall { 29633801Sminshall if (TTYBYTES()) { 29732185Sminshall (void) DataToTerminal(&c, 1); 29832185Sminshall } else { 29933801Sminshall TTYADD(c); 30032185Sminshall } 30132185Sminshall } 30232185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 30332185Sminshall 30432531Sminshall void 30532531Sminshall SetForExit() 30632531Sminshall { 30732531Sminshall setconnmode(); 30832531Sminshall if (In3270) { 30932531Sminshall Finish3270(); 31032531Sminshall } 31132531Sminshall setcommandmode(); 31232531Sminshall fflush(stdout); 31332531Sminshall fflush(stderr); 31432531Sminshall if (In3270) { 31532531Sminshall StopScreen(1); 31632531Sminshall } 31732531Sminshall setconnmode(); 31832531Sminshall setcommandmode(); 31932531Sminshall } 32032531Sminshall 32132531Sminshall void 32232531Sminshall Exit(returnCode) 32332531Sminshall int returnCode; 32432531Sminshall { 32532531Sminshall SetForExit(); 32632531Sminshall exit(returnCode); 32732531Sminshall } 32832531Sminshall 32932531Sminshall void 33032531Sminshall ExitString(string, returnCode) 33132531Sminshall char *string; 33232531Sminshall int returnCode; 33332531Sminshall { 33432531Sminshall SetForExit(); 33532531Sminshall fwrite(string, 1, strlen(string), stderr); 33632531Sminshall exit(returnCode); 33732531Sminshall } 33832531Sminshall 33932531Sminshall void 34032531Sminshall ExitPerror(string, returnCode) 34132531Sminshall char *string; 34232531Sminshall int returnCode; 34332531Sminshall { 34432531Sminshall SetForExit(); 34532531Sminshall perror(string); 34632531Sminshall exit(returnCode); 34732531Sminshall } 34832531Sminshall 34932531Sminshall void 35032531Sminshall SetIn3270() 35132531Sminshall { 35232531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 35332531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 35432531Sminshall if (!In3270) { 35532531Sminshall In3270 = 1; 35632531Sminshall Init3270(); /* Initialize 3270 functions */ 35732531Sminshall /* initialize terminal key mapping */ 35832531Sminshall InitTerminal(); /* Start terminal going */ 35932531Sminshall setconnmode(); 36032531Sminshall } 36132531Sminshall } else { 36232531Sminshall if (In3270) { 36332531Sminshall StopScreen(1); 36432531Sminshall In3270 = 0; 36532531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 36632531Sminshall setconnmode(); 36732531Sminshall } 36832531Sminshall } 36932531Sminshall } 37032531Sminshall 37132531Sminshall /* 37232531Sminshall * tn3270_ttype() 37332531Sminshall * 37432531Sminshall * Send a response to a terminal type negotiation. 37532531Sminshall * 37632531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 37732531Sminshall */ 37832531Sminshall 37932531Sminshall int 38032531Sminshall tn3270_ttype() 38132531Sminshall { 38232531Sminshall /* 38332531Sminshall * Try to send a 3270 type terminal name. Decide which one based 38432531Sminshall * on the format of our screen, and (in the future) color 38532531Sminshall * capaiblities. 38632531Sminshall */ 38732531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 38832531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 38932531Sminshall Sent3270TerminalType = 1; 39032531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 39132531Sminshall MaxNumberLines = 27; 39232531Sminshall MaxNumberColumns = 132; 39332531Sminshall sb_terminal[SBTERMMODEL] = '5'; 39432531Sminshall } else if (MaxNumberLines >= 43) { 39532531Sminshall MaxNumberLines = 43; 39632531Sminshall MaxNumberColumns = 80; 39732531Sminshall sb_terminal[SBTERMMODEL] = '4'; 39832531Sminshall } else if (MaxNumberLines >= 32) { 39932531Sminshall MaxNumberLines = 32; 40032531Sminshall MaxNumberColumns = 80; 40132531Sminshall sb_terminal[SBTERMMODEL] = '3'; 40232531Sminshall } else { 40332531Sminshall MaxNumberLines = 24; 40432531Sminshall MaxNumberColumns = 80; 40532531Sminshall sb_terminal[SBTERMMODEL] = '2'; 40632531Sminshall } 40732531Sminshall NumberLines = 24; /* before we start out... */ 40832531Sminshall NumberColumns = 80; 40932531Sminshall ScreenSize = NumberLines*NumberColumns; 41032531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 41132531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 41232531Sminshall 1); 41332531Sminshall /*NOTREACHED*/ 41432531Sminshall } 41532531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 41632531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 41732531Sminshall return 1; 41832531Sminshall } else { 41932531Sminshall return 0; 42032531Sminshall } 42132531Sminshall } 42233801Sminshall 42333801Sminshall #if defined(unix) 42433801Sminshall settranscom(argc, argv) 42533801Sminshall int argc; 42633801Sminshall char *argv[]; 42733801Sminshall { 42833801Sminshall int i, len = 0; 42933801Sminshall 43033801Sminshall if (argc == 1 && transcom) { 43133801Sminshall transcom = 0; 43233801Sminshall } 43333801Sminshall if (argc == 1) { 43433801Sminshall return; 43533801Sminshall } 43633801Sminshall for (i = 1; i < argc; ++i) { 43733801Sminshall len += 1 + strlen(argv[1]); 43833801Sminshall } 43933801Sminshall transcom = tline; 44033801Sminshall (void) strcpy(transcom, argv[1]); 44133801Sminshall for (i = 2; i < argc; ++i) { 44233801Sminshall (void) strcat(transcom, " "); 44333801Sminshall (void) strcat(transcom, argv[i]); 44433801Sminshall } 44533801Sminshall } 44633801Sminshall #endif /* defined(unix) */ 44733801Sminshall 44832185Sminshall #endif /* defined(TN3270) */ 449