133686Sbostic /* 233686Sbostic * Copyright (c) 1988 Regents of the University of California. 333686Sbostic * All rights reserved. 433686Sbostic * 5*42770Sbostic * %sccs.include.redist.c% 633686Sbostic */ 733686Sbostic 833686Sbostic #ifndef lint 9*42770Sbostic static char sccsid[] = "@(#)tn3270.c 1.20 (Berkeley) 06/01/90"; 1033686Sbostic #endif /* not lint */ 1133686Sbostic 1233801Sminshall #include <sys/types.h> 1333801Sminshall #include <arpa/telnet.h> 1433801Sminshall 1534305Sminshall #include "general.h" 1634305Sminshall 1733801Sminshall #include "defines.h" 1833801Sminshall #include "ring.h" 1933801Sminshall #include "externs.h" 2032657Sminshall #include "fdset.h" 2132657Sminshall 2232185Sminshall #if defined(TN3270) 2332185Sminshall 2433801Sminshall #include "../ctlr/screen.h" 2533801Sminshall #include "../general/globals.h" 2632185Sminshall 2735417Sminshall #include "../telextrn.h" 2835417Sminshall #include "../ctlr/externs.h" 2935417Sminshall 3033801Sminshall #if defined(unix) 3136240Sminshall int 3236240Sminshall HaveInput, /* There is input available to scan */ 3338208Sminshall cursesdata, /* Do we dump curses data? */ 3436240Sminshall sigiocount; /* Number of times we got a SIGIO */ 3536240Sminshall 3633801Sminshall char tline[200]; 3733801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 3833801Sminshall #endif /* defined(unix) */ 3932531Sminshall 4033801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 4132531Sminshall 4232531Sminshall static char sb_terminal[] = { IAC, SB, 4332531Sminshall TELOPT_TTYPE, TELQUAL_IS, 4432531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 4532531Sminshall IAC, SE }; 4632531Sminshall #define SBTERMMODEL 13 4732531Sminshall 4832531Sminshall static int 4932531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 5032531Sminshall 5133801Sminshall #endif /* defined(TN3270) */ 5232531Sminshall 5333801Sminshall 5433801Sminshall void 5534303Sminshall init_3270() 5632551Sminshall { 5733801Sminshall #if defined(TN3270) 5836240Sminshall #if defined(unix) 5936240Sminshall HaveInput = 0; 6036240Sminshall sigiocount = 0; 6136240Sminshall #endif /* defined(unix) */ 6233801Sminshall Sent3270TerminalType = 0; 6333801Sminshall Ifrontp = Ibackp = Ibuf; 6433801Sminshall init_ctlr(); /* Initialize some things */ 6533801Sminshall init_keyboard(); 6633801Sminshall init_screen(); 6733801Sminshall init_system(); 6833801Sminshall #endif /* defined(TN3270) */ 6932551Sminshall } 7032551Sminshall 7133801Sminshall 7233801Sminshall #if defined(TN3270) 7333801Sminshall 7432185Sminshall /* 7532185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 7632185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 7732185Sminshall * don't call us with "done" until you want that done...) 7832185Sminshall * 7932185Sminshall * We actually do send all the data to the network buffer, since our 8032185Sminshall * only client needs for us to do that. 8132185Sminshall */ 8232185Sminshall 8332185Sminshall int 8432185Sminshall DataToNetwork(buffer, count, done) 8532185Sminshall register char *buffer; /* where the data is */ 8632185Sminshall register int count; /* how much to send */ 8732185Sminshall int done; /* is this the last of a logical block */ 8832185Sminshall { 8933801Sminshall register int loop, c; 9032185Sminshall int origCount; 9132185Sminshall 9232185Sminshall origCount = count; 9332185Sminshall 9432185Sminshall while (count) { 9534303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 9633801Sminshall if (NETROOM() < 6) { 9733801Sminshall fd_set o; 9833801Sminshall 9933801Sminshall FD_ZERO(&o); 10032185Sminshall netflush(); 10133801Sminshall while (NETROOM() < 6) { 10232185Sminshall FD_SET(net, &o); 10332185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 10432185Sminshall (struct timeval *) 0); 10532185Sminshall netflush(); 10632185Sminshall } 10732185Sminshall } 10834303Sminshall c = ring_empty_count(&netoring); 10934303Sminshall if (c > count) { 11034303Sminshall c = count; 11134303Sminshall } 11234303Sminshall loop = c; 11333801Sminshall while (loop) { 11434311Sminshall if (((unsigned char)*buffer) == IAC) { 11533801Sminshall break; 11633801Sminshall } 11733801Sminshall buffer++; 11833801Sminshall loop--; 11932185Sminshall } 12033801Sminshall if ((c = c-loop)) { 12133801Sminshall ring_supply_data(&netoring, buffer-c, c); 12233801Sminshall count -= c; 12333801Sminshall } 12433801Sminshall if (loop) { 12533801Sminshall NET2ADD(IAC, IAC); 12633801Sminshall count--; 12734303Sminshall buffer++; 12833801Sminshall } 12932185Sminshall } 13032185Sminshall 13133801Sminshall if (done) { 13234303Sminshall NET2ADD(IAC, EOR); 13332185Sminshall netflush(); /* try to move along as quickly as ... */ 13432185Sminshall } 13532185Sminshall return(origCount - count); 13632185Sminshall } 13732185Sminshall 13832185Sminshall 13932185Sminshall #if defined(unix) 14033801Sminshall void 14132185Sminshall inputAvailable() 14232185Sminshall { 14332185Sminshall HaveInput = 1; 14436240Sminshall sigiocount++; 14532185Sminshall } 14632185Sminshall #endif /* defined(unix) */ 14732185Sminshall 14832185Sminshall void 14932185Sminshall outputPurge() 15032185Sminshall { 15132257Sminshall ttyflush(1); 15232185Sminshall } 15332185Sminshall 15432185Sminshall 15532185Sminshall /* 15632185Sminshall * The following routines are places where the various tn3270 15732185Sminshall * routines make calls into telnet.c. 15832185Sminshall */ 15932185Sminshall 16034303Sminshall /* 16134303Sminshall * DataToTerminal - queue up some data to go to terminal. 16234303Sminshall * 16334303Sminshall * Note: there are people who call us and depend on our processing 16434303Sminshall * *all* the data at one time (thus the select). 16534303Sminshall */ 16632185Sminshall 16732185Sminshall int 16832185Sminshall DataToTerminal(buffer, count) 16932185Sminshall register char *buffer; /* where the data is */ 17032185Sminshall register int count; /* how much to send */ 17132185Sminshall { 17235417Sminshall register int c; 17332185Sminshall int origCount; 17432185Sminshall 17532185Sminshall origCount = count; 17632185Sminshall 17732185Sminshall while (count) { 17833801Sminshall if (TTYROOM() == 0) { 17932185Sminshall #if defined(unix) 18033801Sminshall fd_set o; 18133801Sminshall 18233801Sminshall FD_ZERO(&o); 18333801Sminshall #endif /* defined(unix) */ 18435417Sminshall ttyflush(0); 18533801Sminshall while (TTYROOM() == 0) { 18633801Sminshall #if defined(unix) 18732185Sminshall FD_SET(tout, &o); 18832185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 18932185Sminshall (struct timeval *) 0); 19032185Sminshall #endif /* defined(unix) */ 19135417Sminshall ttyflush(0); 19232185Sminshall } 19332185Sminshall } 19434303Sminshall c = TTYROOM(); 19534303Sminshall if (c > count) { 19634303Sminshall c = count; 19733801Sminshall } 19834303Sminshall ring_supply_data(&ttyoring, buffer, c); 19934303Sminshall count -= c; 20034303Sminshall buffer += c; 20132185Sminshall } 20234303Sminshall return(origCount); 20332185Sminshall } 20432185Sminshall 20532185Sminshall 20632185Sminshall /* 20732185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 20832185Sminshall */ 20932185Sminshall 21033801Sminshall int 21132185Sminshall Push3270() 21232185Sminshall { 21333801Sminshall int save = ring_full_count(&netiring); 21432185Sminshall 21533801Sminshall if (save) { 21633801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 21732185Sminshall if (Ibackp != Ibuf) { 21832185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 21932185Sminshall Ifrontp -= (Ibackp-Ibuf); 22032185Sminshall Ibackp = Ibuf; 22132185Sminshall } 22232185Sminshall } 22333801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 22432185Sminshall telrcv(); 22532185Sminshall } 22632185Sminshall } 22733801Sminshall return save != ring_full_count(&netiring); 22832185Sminshall } 22932185Sminshall 23032185Sminshall 23132185Sminshall /* 23232185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 23332185Sminshall * before quitting. 23432185Sminshall */ 23532185Sminshall 23633801Sminshall void 23732185Sminshall Finish3270() 23832185Sminshall { 23932185Sminshall while (Push3270() || !DoTerminalOutput()) { 24032185Sminshall #if defined(unix) 24132185Sminshall HaveInput = 0; 24232185Sminshall #endif /* defined(unix) */ 24332185Sminshall ; 24432185Sminshall } 24532185Sminshall } 24632185Sminshall 24732185Sminshall 24832185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 24932185Sminshall 25032185Sminshall void 25132185Sminshall StringToTerminal(s) 25232185Sminshall char *s; 25332185Sminshall { 25432185Sminshall int count; 25532185Sminshall 25632185Sminshall count = strlen(s); 25732185Sminshall if (count) { 25832185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 25932185Sminshall } 26032185Sminshall } 26132185Sminshall 26232185Sminshall 26332185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 26432185Sminshall /* _putchar - output a single character to the terminal. This name is so that 26532185Sminshall * curses(3x) can call us to send out data. 26632185Sminshall */ 26732185Sminshall 26832185Sminshall void 26932185Sminshall _putchar(c) 27032185Sminshall char c; 27132185Sminshall { 27236201Sminshall #if defined(sun) /* SunOS 4.0 bug */ 27336201Sminshall c &= 0x7f; 27436201Sminshall #endif /* defined(sun) */ 27538208Sminshall if (cursesdata) { 27638208Sminshall Dump('>', &c, 1); 27738208Sminshall } 27836240Sminshall if (!TTYROOM()) { 27932185Sminshall (void) DataToTerminal(&c, 1); 28032185Sminshall } else { 28133801Sminshall TTYADD(c); 28232185Sminshall } 28332185Sminshall } 28432185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 28532185Sminshall 28632531Sminshall void 28732531Sminshall SetIn3270() 28832531Sminshall { 28938690Sborman if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY) 29038690Sborman && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) { 29132531Sminshall if (!In3270) { 29232531Sminshall In3270 = 1; 29332531Sminshall Init3270(); /* Initialize 3270 functions */ 29432531Sminshall /* initialize terminal key mapping */ 29532531Sminshall InitTerminal(); /* Start terminal going */ 29638690Sborman setconnmode(0); 29732531Sminshall } 29832531Sminshall } else { 29932531Sminshall if (In3270) { 30032531Sminshall StopScreen(1); 30132531Sminshall In3270 = 0; 30232531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 30338690Sborman setconnmode(0); 30432531Sminshall } 30532531Sminshall } 30632531Sminshall } 30732531Sminshall 30832531Sminshall /* 30932531Sminshall * tn3270_ttype() 31032531Sminshall * 31132531Sminshall * Send a response to a terminal type negotiation. 31232531Sminshall * 31332531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 31432531Sminshall */ 31532531Sminshall 31632531Sminshall int 31732531Sminshall tn3270_ttype() 31832531Sminshall { 31932531Sminshall /* 32032531Sminshall * Try to send a 3270 type terminal name. Decide which one based 32132531Sminshall * on the format of our screen, and (in the future) color 32232531Sminshall * capaiblities. 32332531Sminshall */ 32432531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 32532531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 32632531Sminshall Sent3270TerminalType = 1; 32732531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 32832531Sminshall MaxNumberLines = 27; 32932531Sminshall MaxNumberColumns = 132; 33032531Sminshall sb_terminal[SBTERMMODEL] = '5'; 33132531Sminshall } else if (MaxNumberLines >= 43) { 33232531Sminshall MaxNumberLines = 43; 33332531Sminshall MaxNumberColumns = 80; 33432531Sminshall sb_terminal[SBTERMMODEL] = '4'; 33532531Sminshall } else if (MaxNumberLines >= 32) { 33632531Sminshall MaxNumberLines = 32; 33732531Sminshall MaxNumberColumns = 80; 33832531Sminshall sb_terminal[SBTERMMODEL] = '3'; 33932531Sminshall } else { 34032531Sminshall MaxNumberLines = 24; 34132531Sminshall MaxNumberColumns = 80; 34232531Sminshall sb_terminal[SBTERMMODEL] = '2'; 34332531Sminshall } 34432531Sminshall NumberLines = 24; /* before we start out... */ 34532531Sminshall NumberColumns = 80; 34632531Sminshall ScreenSize = NumberLines*NumberColumns; 34732531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 34832531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 34932531Sminshall 1); 35032531Sminshall /*NOTREACHED*/ 35132531Sminshall } 35238690Sborman printsub('>', sb_terminal+2, sizeof sb_terminal-2); 35332531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 35432531Sminshall return 1; 35532531Sminshall } else { 35632531Sminshall return 0; 35732531Sminshall } 35832531Sminshall } 35933801Sminshall 36033801Sminshall #if defined(unix) 36133801Sminshall settranscom(argc, argv) 36233801Sminshall int argc; 36333801Sminshall char *argv[]; 36433801Sminshall { 36535417Sminshall int i; 36633801Sminshall 36733801Sminshall if (argc == 1 && transcom) { 36833801Sminshall transcom = 0; 36933801Sminshall } 37033801Sminshall if (argc == 1) { 37133801Sminshall return; 37233801Sminshall } 37333801Sminshall transcom = tline; 37433801Sminshall (void) strcpy(transcom, argv[1]); 37533801Sminshall for (i = 2; i < argc; ++i) { 37633801Sminshall (void) strcat(transcom, " "); 37733801Sminshall (void) strcat(transcom, argv[i]); 37833801Sminshall } 37933801Sminshall } 38033801Sminshall #endif /* defined(unix) */ 38133801Sminshall 38232185Sminshall #endif /* defined(TN3270) */ 383