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 6*34898Sbostic * provided that the above copyright notice and this paragraph are 7*34898Sbostic * duplicated in all such forms and that any documentation, 8*34898Sbostic * advertising materials, and other materials related to such 9*34898Sbostic * distribution and use acknowledge that the software was developed 10*34898Sbostic * by the University of California, Berkeley. The name of the 11*34898Sbostic * University may not be used to endorse or promote products derived 12*34898Sbostic * from this software without specific prior written permission. 13*34898Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34898Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34898Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633686Sbostic */ 1733686Sbostic 1833686Sbostic #ifndef lint 19*34898Sbostic static char sccsid[] = "@(#)tn3270.c 1.12 (Berkeley) 06/29/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 3733801Sminshall #if defined(unix) 3833801Sminshall char tline[200]; 3933801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 4033801Sminshall #endif /* defined(unix) */ 4132531Sminshall 4233801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 4332531Sminshall 4432531Sminshall static char sb_terminal[] = { IAC, SB, 4532531Sminshall TELOPT_TTYPE, TELQUAL_IS, 4632531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 4732531Sminshall IAC, SE }; 4832531Sminshall #define SBTERMMODEL 13 4932531Sminshall 5032531Sminshall static int 5132531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 5232531Sminshall 5333801Sminshall #endif /* defined(TN3270) */ 5432531Sminshall 5533801Sminshall 5633801Sminshall void 5734303Sminshall init_3270() 5832551Sminshall { 5933801Sminshall #if defined(TN3270) 6033801Sminshall Sent3270TerminalType = 0; 6133801Sminshall Ifrontp = Ibackp = Ibuf; 6233801Sminshall init_ctlr(); /* Initialize some things */ 6333801Sminshall init_keyboard(); 6433801Sminshall init_screen(); 6533801Sminshall init_system(); 6633801Sminshall #endif /* defined(TN3270) */ 6732551Sminshall } 6832551Sminshall 6933801Sminshall 7033801Sminshall #if defined(TN3270) 7133801Sminshall 7232185Sminshall /* 7332185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 7432185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 7532185Sminshall * don't call us with "done" until you want that done...) 7632185Sminshall * 7732185Sminshall * We actually do send all the data to the network buffer, since our 7832185Sminshall * only client needs for us to do that. 7932185Sminshall */ 8032185Sminshall 8132185Sminshall int 8232185Sminshall DataToNetwork(buffer, count, done) 8332185Sminshall register char *buffer; /* where the data is */ 8432185Sminshall register int count; /* how much to send */ 8532185Sminshall int done; /* is this the last of a logical block */ 8632185Sminshall { 8733801Sminshall register int loop, c; 8832185Sminshall int origCount; 8932185Sminshall 9032185Sminshall origCount = count; 9132185Sminshall 9232185Sminshall while (count) { 9334303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 9433801Sminshall if (NETROOM() < 6) { 9533801Sminshall fd_set o; 9633801Sminshall 9733801Sminshall FD_ZERO(&o); 9832185Sminshall netflush(); 9933801Sminshall while (NETROOM() < 6) { 10032185Sminshall FD_SET(net, &o); 10132185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 10232185Sminshall (struct timeval *) 0); 10332185Sminshall netflush(); 10432185Sminshall } 10532185Sminshall } 10634303Sminshall c = ring_empty_count(&netoring); 10734303Sminshall if (c > count) { 10834303Sminshall c = count; 10934303Sminshall } 11034303Sminshall loop = c; 11133801Sminshall while (loop) { 11234311Sminshall if (((unsigned char)*buffer) == IAC) { 11333801Sminshall break; 11433801Sminshall } 11533801Sminshall buffer++; 11633801Sminshall loop--; 11732185Sminshall } 11833801Sminshall if ((c = c-loop)) { 11933801Sminshall ring_supply_data(&netoring, buffer-c, c); 12033801Sminshall count -= c; 12133801Sminshall } 12233801Sminshall if (loop) { 12333801Sminshall NET2ADD(IAC, IAC); 12433801Sminshall count--; 12534303Sminshall buffer++; 12633801Sminshall } 12732185Sminshall } 12832185Sminshall 12933801Sminshall if (done) { 13034303Sminshall NET2ADD(IAC, EOR); 13132185Sminshall netflush(); /* try to move along as quickly as ... */ 13232185Sminshall } 13332185Sminshall return(origCount - count); 13432185Sminshall } 13532185Sminshall 13632185Sminshall 13732185Sminshall #if defined(unix) 13833801Sminshall void 13932185Sminshall inputAvailable() 14032185Sminshall { 14132185Sminshall HaveInput = 1; 14232185Sminshall } 14332185Sminshall #endif /* defined(unix) */ 14432185Sminshall 14532185Sminshall void 14632185Sminshall outputPurge() 14732185Sminshall { 14832257Sminshall ttyflush(1); 14932185Sminshall } 15032185Sminshall 15132185Sminshall 15232185Sminshall /* 15332185Sminshall * The following routines are places where the various tn3270 15432185Sminshall * routines make calls into telnet.c. 15532185Sminshall */ 15632185Sminshall 15734303Sminshall /* 15834303Sminshall * DataToTerminal - queue up some data to go to terminal. 15934303Sminshall * 16034303Sminshall * Note: there are people who call us and depend on our processing 16134303Sminshall * *all* the data at one time (thus the select). 16234303Sminshall */ 16332185Sminshall 16432185Sminshall int 16532185Sminshall DataToTerminal(buffer, count) 16632185Sminshall register char *buffer; /* where the data is */ 16732185Sminshall register int count; /* how much to send */ 16832185Sminshall { 16933801Sminshall register int loop, c; 17032185Sminshall int origCount; 17132185Sminshall 17232185Sminshall origCount = count; 17332185Sminshall 17432185Sminshall while (count) { 17533801Sminshall if (TTYROOM() == 0) { 17632185Sminshall #if defined(unix) 17733801Sminshall fd_set o; 17833801Sminshall 17933801Sminshall FD_ZERO(&o); 18033801Sminshall #endif /* defined(unix) */ 18133801Sminshall ttyflush(); 18233801Sminshall while (TTYROOM() == 0) { 18333801Sminshall #if defined(unix) 18432185Sminshall FD_SET(tout, &o); 18532185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 18632185Sminshall (struct timeval *) 0); 18732185Sminshall #endif /* defined(unix) */ 18833801Sminshall ttyflush(); 18932185Sminshall } 19032185Sminshall } 19134303Sminshall c = TTYROOM(); 19234303Sminshall if (c > count) { 19334303Sminshall c = count; 19433801Sminshall } 19534303Sminshall ring_supply_data(&ttyoring, buffer, c); 19634303Sminshall count -= c; 19734303Sminshall buffer += c; 19832185Sminshall } 19934303Sminshall return(origCount); 20032185Sminshall } 20132185Sminshall 20232185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 20332185Sminshall * Note that we consider the buffer to run all the 20432185Sminshall * way to the kernel (thus the select). 20532185Sminshall */ 20632185Sminshall 20732185Sminshall void 20832185Sminshall EmptyTerminal() 20932185Sminshall { 21032185Sminshall #if defined(unix) 21132185Sminshall fd_set o; 21232185Sminshall 21332185Sminshall FD_ZERO(&o); 21432185Sminshall #endif /* defined(unix) */ 21532185Sminshall 21634303Sminshall if (TTYBYTES() == 0) { 21732185Sminshall #if defined(unix) 21832185Sminshall FD_SET(tout, &o); 21932185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 22032185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 22132185Sminshall #endif /* defined(unix) */ 22232185Sminshall } else { 22333801Sminshall while (TTYBYTES()) { 22432257Sminshall ttyflush(0); 22532185Sminshall #if defined(unix) 22632185Sminshall FD_SET(tout, &o); 22732185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 22832185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 22932185Sminshall #endif /* defined(unix) */ 23032185Sminshall } 23132185Sminshall } 23232185Sminshall } 23332185Sminshall 23432185Sminshall 23532185Sminshall /* 23632185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 23732185Sminshall */ 23832185Sminshall 23933801Sminshall int 24032185Sminshall Push3270() 24132185Sminshall { 24233801Sminshall int save = ring_full_count(&netiring); 24332185Sminshall 24433801Sminshall if (save) { 24533801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 24632185Sminshall if (Ibackp != Ibuf) { 24732185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 24832185Sminshall Ifrontp -= (Ibackp-Ibuf); 24932185Sminshall Ibackp = Ibuf; 25032185Sminshall } 25132185Sminshall } 25233801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 25332185Sminshall telrcv(); 25432185Sminshall } 25532185Sminshall } 25633801Sminshall return save != ring_full_count(&netiring); 25732185Sminshall } 25832185Sminshall 25932185Sminshall 26032185Sminshall /* 26132185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 26232185Sminshall * before quitting. 26332185Sminshall */ 26432185Sminshall 26533801Sminshall void 26632185Sminshall Finish3270() 26732185Sminshall { 26832185Sminshall while (Push3270() || !DoTerminalOutput()) { 26932185Sminshall #if defined(unix) 27032185Sminshall HaveInput = 0; 27132185Sminshall #endif /* defined(unix) */ 27232185Sminshall ; 27332185Sminshall } 27432185Sminshall } 27532185Sminshall 27632185Sminshall 27732185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 27832185Sminshall 27932185Sminshall void 28032185Sminshall StringToTerminal(s) 28132185Sminshall char *s; 28232185Sminshall { 28332185Sminshall int count; 28432185Sminshall 28532185Sminshall count = strlen(s); 28632185Sminshall if (count) { 28732185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 28832185Sminshall } 28932185Sminshall } 29032185Sminshall 29132185Sminshall 29232185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 29332185Sminshall /* _putchar - output a single character to the terminal. This name is so that 29432185Sminshall * curses(3x) can call us to send out data. 29532185Sminshall */ 29632185Sminshall 29732185Sminshall void 29832185Sminshall _putchar(c) 29932185Sminshall char c; 30032185Sminshall { 30133801Sminshall if (TTYBYTES()) { 30232185Sminshall (void) DataToTerminal(&c, 1); 30332185Sminshall } else { 30433801Sminshall TTYADD(c); 30532185Sminshall } 30632185Sminshall } 30732185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 30832185Sminshall 30932531Sminshall void 31032531Sminshall SetForExit() 31132531Sminshall { 31232531Sminshall setconnmode(); 31332531Sminshall if (In3270) { 31432531Sminshall Finish3270(); 31532531Sminshall } 31632531Sminshall setcommandmode(); 31732531Sminshall fflush(stdout); 31832531Sminshall fflush(stderr); 31932531Sminshall if (In3270) { 32032531Sminshall StopScreen(1); 32132531Sminshall } 32232531Sminshall setconnmode(); 32332531Sminshall setcommandmode(); 32432531Sminshall } 32532531Sminshall 32632531Sminshall void 32732531Sminshall Exit(returnCode) 32832531Sminshall int returnCode; 32932531Sminshall { 33032531Sminshall SetForExit(); 33132531Sminshall exit(returnCode); 33232531Sminshall } 33332531Sminshall 33432531Sminshall void 33532531Sminshall ExitString(string, returnCode) 33632531Sminshall char *string; 33732531Sminshall int returnCode; 33832531Sminshall { 33932531Sminshall SetForExit(); 34032531Sminshall fwrite(string, 1, strlen(string), stderr); 34132531Sminshall exit(returnCode); 34232531Sminshall } 34332531Sminshall 34432531Sminshall void 34532531Sminshall ExitPerror(string, returnCode) 34632531Sminshall char *string; 34732531Sminshall int returnCode; 34832531Sminshall { 34932531Sminshall SetForExit(); 35032531Sminshall perror(string); 35132531Sminshall exit(returnCode); 35232531Sminshall } 35332531Sminshall 35432531Sminshall void 35532531Sminshall SetIn3270() 35632531Sminshall { 35732531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 35832531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 35932531Sminshall if (!In3270) { 36032531Sminshall In3270 = 1; 36132531Sminshall Init3270(); /* Initialize 3270 functions */ 36232531Sminshall /* initialize terminal key mapping */ 36332531Sminshall InitTerminal(); /* Start terminal going */ 36432531Sminshall setconnmode(); 36532531Sminshall } 36632531Sminshall } else { 36732531Sminshall if (In3270) { 36832531Sminshall StopScreen(1); 36932531Sminshall In3270 = 0; 37032531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 37132531Sminshall setconnmode(); 37232531Sminshall } 37332531Sminshall } 37432531Sminshall } 37532531Sminshall 37632531Sminshall /* 37732531Sminshall * tn3270_ttype() 37832531Sminshall * 37932531Sminshall * Send a response to a terminal type negotiation. 38032531Sminshall * 38132531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 38232531Sminshall */ 38332531Sminshall 38432531Sminshall int 38532531Sminshall tn3270_ttype() 38632531Sminshall { 38732531Sminshall /* 38832531Sminshall * Try to send a 3270 type terminal name. Decide which one based 38932531Sminshall * on the format of our screen, and (in the future) color 39032531Sminshall * capaiblities. 39132531Sminshall */ 39232531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 39332531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 39432531Sminshall Sent3270TerminalType = 1; 39532531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 39632531Sminshall MaxNumberLines = 27; 39732531Sminshall MaxNumberColumns = 132; 39832531Sminshall sb_terminal[SBTERMMODEL] = '5'; 39932531Sminshall } else if (MaxNumberLines >= 43) { 40032531Sminshall MaxNumberLines = 43; 40132531Sminshall MaxNumberColumns = 80; 40232531Sminshall sb_terminal[SBTERMMODEL] = '4'; 40332531Sminshall } else if (MaxNumberLines >= 32) { 40432531Sminshall MaxNumberLines = 32; 40532531Sminshall MaxNumberColumns = 80; 40632531Sminshall sb_terminal[SBTERMMODEL] = '3'; 40732531Sminshall } else { 40832531Sminshall MaxNumberLines = 24; 40932531Sminshall MaxNumberColumns = 80; 41032531Sminshall sb_terminal[SBTERMMODEL] = '2'; 41132531Sminshall } 41232531Sminshall NumberLines = 24; /* before we start out... */ 41332531Sminshall NumberColumns = 80; 41432531Sminshall ScreenSize = NumberLines*NumberColumns; 41532531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 41632531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 41732531Sminshall 1); 41832531Sminshall /*NOTREACHED*/ 41932531Sminshall } 42032531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 42132531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 42232531Sminshall return 1; 42332531Sminshall } else { 42432531Sminshall return 0; 42532531Sminshall } 42632531Sminshall } 42733801Sminshall 42833801Sminshall #if defined(unix) 42933801Sminshall settranscom(argc, argv) 43033801Sminshall int argc; 43133801Sminshall char *argv[]; 43233801Sminshall { 43333801Sminshall int i, len = 0; 43433801Sminshall 43533801Sminshall if (argc == 1 && transcom) { 43633801Sminshall transcom = 0; 43733801Sminshall } 43833801Sminshall if (argc == 1) { 43933801Sminshall return; 44033801Sminshall } 44133801Sminshall for (i = 1; i < argc; ++i) { 44233801Sminshall len += 1 + strlen(argv[1]); 44333801Sminshall } 44433801Sminshall transcom = tline; 44533801Sminshall (void) strcpy(transcom, argv[1]); 44633801Sminshall for (i = 2; i < argc; ++i) { 44733801Sminshall (void) strcat(transcom, " "); 44833801Sminshall (void) strcat(transcom, argv[i]); 44933801Sminshall } 45033801Sminshall } 45133801Sminshall #endif /* defined(unix) */ 45233801Sminshall 45332185Sminshall #endif /* defined(TN3270) */ 454