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*35417Sminshall static char sccsid[] = "@(#)tn3270.c 1.13 (Berkeley) 08/28/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 37*35417Sminshall #include "../telextrn.h" 38*35417Sminshall #include "../ctlr/externs.h" 39*35417Sminshall 4033801Sminshall #if defined(unix) 4133801Sminshall char tline[200]; 4233801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 4333801Sminshall #endif /* defined(unix) */ 4432531Sminshall 4533801Sminshall char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; 4632531Sminshall 4732531Sminshall static char sb_terminal[] = { IAC, SB, 4832531Sminshall TELOPT_TTYPE, TELQUAL_IS, 4932531Sminshall 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', 5032531Sminshall IAC, SE }; 5132531Sminshall #define SBTERMMODEL 13 5232531Sminshall 5332531Sminshall static int 5432531Sminshall Sent3270TerminalType; /* Have we said we are a 3270? */ 5532531Sminshall 5633801Sminshall #endif /* defined(TN3270) */ 5732531Sminshall 5833801Sminshall 5933801Sminshall void 6034303Sminshall init_3270() 6132551Sminshall { 6233801Sminshall #if defined(TN3270) 6333801Sminshall Sent3270TerminalType = 0; 6433801Sminshall Ifrontp = Ibackp = Ibuf; 6533801Sminshall init_ctlr(); /* Initialize some things */ 6633801Sminshall init_keyboard(); 6733801Sminshall init_screen(); 6833801Sminshall init_system(); 6933801Sminshall #endif /* defined(TN3270) */ 7032551Sminshall } 7132551Sminshall 7233801Sminshall 7333801Sminshall #if defined(TN3270) 7433801Sminshall 7532185Sminshall /* 7632185Sminshall * DataToNetwork - queue up some data to go to network. If "done" is set, 7732185Sminshall * then when last byte is queued, we add on an IAC EOR sequence (so, 7832185Sminshall * don't call us with "done" until you want that done...) 7932185Sminshall * 8032185Sminshall * We actually do send all the data to the network buffer, since our 8132185Sminshall * only client needs for us to do that. 8232185Sminshall */ 8332185Sminshall 8432185Sminshall int 8532185Sminshall DataToNetwork(buffer, count, done) 8632185Sminshall register char *buffer; /* where the data is */ 8732185Sminshall register int count; /* how much to send */ 8832185Sminshall int done; /* is this the last of a logical block */ 8932185Sminshall { 9033801Sminshall register int loop, c; 9132185Sminshall int origCount; 9232185Sminshall 9332185Sminshall origCount = count; 9432185Sminshall 9532185Sminshall while (count) { 9634303Sminshall /* If not enough room for EORs, IACs, etc., wait */ 9733801Sminshall if (NETROOM() < 6) { 9833801Sminshall fd_set o; 9933801Sminshall 10033801Sminshall FD_ZERO(&o); 10132185Sminshall netflush(); 10233801Sminshall while (NETROOM() < 6) { 10332185Sminshall FD_SET(net, &o); 10432185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 10532185Sminshall (struct timeval *) 0); 10632185Sminshall netflush(); 10732185Sminshall } 10832185Sminshall } 10934303Sminshall c = ring_empty_count(&netoring); 11034303Sminshall if (c > count) { 11134303Sminshall c = count; 11234303Sminshall } 11334303Sminshall loop = c; 11433801Sminshall while (loop) { 11534311Sminshall if (((unsigned char)*buffer) == IAC) { 11633801Sminshall break; 11733801Sminshall } 11833801Sminshall buffer++; 11933801Sminshall loop--; 12032185Sminshall } 12133801Sminshall if ((c = c-loop)) { 12233801Sminshall ring_supply_data(&netoring, buffer-c, c); 12333801Sminshall count -= c; 12433801Sminshall } 12533801Sminshall if (loop) { 12633801Sminshall NET2ADD(IAC, IAC); 12733801Sminshall count--; 12834303Sminshall buffer++; 12933801Sminshall } 13032185Sminshall } 13132185Sminshall 13233801Sminshall if (done) { 13334303Sminshall NET2ADD(IAC, EOR); 13432185Sminshall netflush(); /* try to move along as quickly as ... */ 13532185Sminshall } 13632185Sminshall return(origCount - count); 13732185Sminshall } 13832185Sminshall 13932185Sminshall 14032185Sminshall #if defined(unix) 14133801Sminshall void 14232185Sminshall inputAvailable() 14332185Sminshall { 14432185Sminshall HaveInput = 1; 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 { 172*35417Sminshall 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) */ 184*35417Sminshall 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) */ 191*35417Sminshall 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 /* EmptyTerminal - called to make sure that the terminal buffer is empty. 20632185Sminshall * Note that we consider the buffer to run all the 20732185Sminshall * way to the kernel (thus the select). 20832185Sminshall */ 20932185Sminshall 21032185Sminshall void 21132185Sminshall EmptyTerminal() 21232185Sminshall { 21332185Sminshall #if defined(unix) 21432185Sminshall fd_set o; 21532185Sminshall 21632185Sminshall FD_ZERO(&o); 21732185Sminshall #endif /* defined(unix) */ 21832185Sminshall 21934303Sminshall if (TTYBYTES() == 0) { 22032185Sminshall #if defined(unix) 22132185Sminshall FD_SET(tout, &o); 222*35417Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 22332185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 22432185Sminshall #endif /* defined(unix) */ 22532185Sminshall } else { 22633801Sminshall while (TTYBYTES()) { 22732257Sminshall ttyflush(0); 22832185Sminshall #if defined(unix) 22932185Sminshall FD_SET(tout, &o); 230*35417Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 23132185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 23232185Sminshall #endif /* defined(unix) */ 23332185Sminshall } 23432185Sminshall } 23532185Sminshall } 23632185Sminshall 23732185Sminshall 23832185Sminshall /* 23932185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 24032185Sminshall */ 24132185Sminshall 24233801Sminshall int 24332185Sminshall Push3270() 24432185Sminshall { 24533801Sminshall int save = ring_full_count(&netiring); 24632185Sminshall 24733801Sminshall if (save) { 24833801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 24932185Sminshall if (Ibackp != Ibuf) { 25032185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 25132185Sminshall Ifrontp -= (Ibackp-Ibuf); 25232185Sminshall Ibackp = Ibuf; 25332185Sminshall } 25432185Sminshall } 25533801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 25632185Sminshall telrcv(); 25732185Sminshall } 25832185Sminshall } 25933801Sminshall return save != ring_full_count(&netiring); 26032185Sminshall } 26132185Sminshall 26232185Sminshall 26332185Sminshall /* 26432185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 26532185Sminshall * before quitting. 26632185Sminshall */ 26732185Sminshall 26833801Sminshall void 26932185Sminshall Finish3270() 27032185Sminshall { 27132185Sminshall while (Push3270() || !DoTerminalOutput()) { 27232185Sminshall #if defined(unix) 27332185Sminshall HaveInput = 0; 27432185Sminshall #endif /* defined(unix) */ 27532185Sminshall ; 27632185Sminshall } 27732185Sminshall } 27832185Sminshall 27932185Sminshall 28032185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 28132185Sminshall 28232185Sminshall void 28332185Sminshall StringToTerminal(s) 28432185Sminshall char *s; 28532185Sminshall { 28632185Sminshall int count; 28732185Sminshall 28832185Sminshall count = strlen(s); 28932185Sminshall if (count) { 29032185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 29132185Sminshall } 29232185Sminshall } 29332185Sminshall 29432185Sminshall 29532185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 29632185Sminshall /* _putchar - output a single character to the terminal. This name is so that 29732185Sminshall * curses(3x) can call us to send out data. 29832185Sminshall */ 29932185Sminshall 30032185Sminshall void 30132185Sminshall _putchar(c) 30232185Sminshall char c; 30332185Sminshall { 30433801Sminshall if (TTYBYTES()) { 30532185Sminshall (void) DataToTerminal(&c, 1); 30632185Sminshall } else { 30733801Sminshall TTYADD(c); 30832185Sminshall } 30932185Sminshall } 31032185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 31132185Sminshall 31232531Sminshall void 31332531Sminshall SetForExit() 31432531Sminshall { 31532531Sminshall setconnmode(); 31632531Sminshall if (In3270) { 31732531Sminshall Finish3270(); 31832531Sminshall } 31932531Sminshall setcommandmode(); 32032531Sminshall fflush(stdout); 32132531Sminshall fflush(stderr); 32232531Sminshall if (In3270) { 32332531Sminshall StopScreen(1); 32432531Sminshall } 32532531Sminshall setconnmode(); 32632531Sminshall setcommandmode(); 32732531Sminshall } 32832531Sminshall 32932531Sminshall void 33032531Sminshall Exit(returnCode) 33132531Sminshall int returnCode; 33232531Sminshall { 33332531Sminshall SetForExit(); 33432531Sminshall exit(returnCode); 33532531Sminshall } 33632531Sminshall 33732531Sminshall void 33832531Sminshall ExitString(string, returnCode) 33932531Sminshall char *string; 34032531Sminshall int returnCode; 34132531Sminshall { 34232531Sminshall SetForExit(); 34332531Sminshall fwrite(string, 1, strlen(string), stderr); 34432531Sminshall exit(returnCode); 34532531Sminshall } 34632531Sminshall 347*35417Sminshall #if defined(MSDOS) 34832531Sminshall void 34932531Sminshall ExitPerror(string, returnCode) 35032531Sminshall char *string; 35132531Sminshall int returnCode; 35232531Sminshall { 35332531Sminshall SetForExit(); 35432531Sminshall perror(string); 35532531Sminshall exit(returnCode); 35632531Sminshall } 357*35417Sminshall #endif /* defined(MSDOS) */ 35832531Sminshall 35932531Sminshall void 36032531Sminshall SetIn3270() 36132531Sminshall { 36232531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 36332531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 36432531Sminshall if (!In3270) { 36532531Sminshall In3270 = 1; 36632531Sminshall Init3270(); /* Initialize 3270 functions */ 36732531Sminshall /* initialize terminal key mapping */ 36832531Sminshall InitTerminal(); /* Start terminal going */ 36932531Sminshall setconnmode(); 37032531Sminshall } 37132531Sminshall } else { 37232531Sminshall if (In3270) { 37332531Sminshall StopScreen(1); 37432531Sminshall In3270 = 0; 37532531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 37632531Sminshall setconnmode(); 37732531Sminshall } 37832531Sminshall } 37932531Sminshall } 38032531Sminshall 38132531Sminshall /* 38232531Sminshall * tn3270_ttype() 38332531Sminshall * 38432531Sminshall * Send a response to a terminal type negotiation. 38532531Sminshall * 38632531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 38732531Sminshall */ 38832531Sminshall 38932531Sminshall int 39032531Sminshall tn3270_ttype() 39132531Sminshall { 39232531Sminshall /* 39332531Sminshall * Try to send a 3270 type terminal name. Decide which one based 39432531Sminshall * on the format of our screen, and (in the future) color 39532531Sminshall * capaiblities. 39632531Sminshall */ 39732531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 39832531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 39932531Sminshall Sent3270TerminalType = 1; 40032531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 40132531Sminshall MaxNumberLines = 27; 40232531Sminshall MaxNumberColumns = 132; 40332531Sminshall sb_terminal[SBTERMMODEL] = '5'; 40432531Sminshall } else if (MaxNumberLines >= 43) { 40532531Sminshall MaxNumberLines = 43; 40632531Sminshall MaxNumberColumns = 80; 40732531Sminshall sb_terminal[SBTERMMODEL] = '4'; 40832531Sminshall } else if (MaxNumberLines >= 32) { 40932531Sminshall MaxNumberLines = 32; 41032531Sminshall MaxNumberColumns = 80; 41132531Sminshall sb_terminal[SBTERMMODEL] = '3'; 41232531Sminshall } else { 41332531Sminshall MaxNumberLines = 24; 41432531Sminshall MaxNumberColumns = 80; 41532531Sminshall sb_terminal[SBTERMMODEL] = '2'; 41632531Sminshall } 41732531Sminshall NumberLines = 24; /* before we start out... */ 41832531Sminshall NumberColumns = 80; 41932531Sminshall ScreenSize = NumberLines*NumberColumns; 42032531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 42132531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 42232531Sminshall 1); 42332531Sminshall /*NOTREACHED*/ 42432531Sminshall } 42532531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 42632531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 42732531Sminshall return 1; 42832531Sminshall } else { 42932531Sminshall return 0; 43032531Sminshall } 43132531Sminshall } 43233801Sminshall 43333801Sminshall #if defined(unix) 43433801Sminshall settranscom(argc, argv) 43533801Sminshall int argc; 43633801Sminshall char *argv[]; 43733801Sminshall { 438*35417Sminshall int i; 43933801Sminshall 44033801Sminshall if (argc == 1 && transcom) { 44133801Sminshall transcom = 0; 44233801Sminshall } 44333801Sminshall if (argc == 1) { 44433801Sminshall return; 44533801Sminshall } 44633801Sminshall transcom = tline; 44733801Sminshall (void) strcpy(transcom, argv[1]); 44833801Sminshall for (i = 2; i < argc; ++i) { 44933801Sminshall (void) strcat(transcom, " "); 45033801Sminshall (void) strcat(transcom, argv[i]); 45133801Sminshall } 45233801Sminshall } 45333801Sminshall #endif /* defined(unix) */ 45433801Sminshall 45532185Sminshall #endif /* defined(TN3270) */ 456