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*33801Sminshall static char sccsid[] = "@(#)tn3270.c 1.7 (Berkeley) 03/27/88"; 1533686Sbostic #endif /* not lint */ 1633686Sbostic 17*33801Sminshall #include <sys/types.h> 18*33801Sminshall #include <arpa/telnet.h> 19*33801Sminshall 20*33801Sminshall #include "defines.h" 21*33801Sminshall #include "ring.h" 22*33801Sminshall #include "externs.h" 2332657Sminshall #include "fdset.h" 2432657Sminshall 2532185Sminshall #if defined(TN3270) 2632185Sminshall 27*33801Sminshall #include "../ctlr/screen.h" 28*33801Sminshall #include "../general/globals.h" 2932185Sminshall 30*33801Sminshall #if defined(unix) 31*33801Sminshall char tline[200]; 32*33801Sminshall char *transcom = 0; /* transparent mode command (default: none) */ 33*33801Sminshall #endif /* defined(unix) */ 3432531Sminshall 35*33801Sminshall 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 46*33801Sminshall #endif /* defined(TN3270) */ 4732531Sminshall 48*33801Sminshall 49*33801Sminshall void 50*33801Sminshall tn3270_init() 5132551Sminshall { 52*33801Sminshall #if defined(TN3270) 53*33801Sminshall Sent3270TerminalType = 0; 54*33801Sminshall Ifrontp = Ibackp = Ibuf; 55*33801Sminshall init_ctlr(); /* Initialize some things */ 56*33801Sminshall init_keyboard(); 57*33801Sminshall init_screen(); 58*33801Sminshall init_system(); 59*33801Sminshall #endif /* defined(TN3270) */ 6032551Sminshall } 6132551Sminshall 62*33801Sminshall 63*33801Sminshall #if defined(TN3270) 64*33801Sminshall 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 { 80*33801Sminshall register int loop, c; 8132185Sminshall int origCount; 8232185Sminshall 8332185Sminshall origCount = count; 8432185Sminshall 8532185Sminshall while (count) { 86*33801Sminshall if (NETROOM() < 6) { 87*33801Sminshall fd_set o; 88*33801Sminshall 89*33801Sminshall FD_ZERO(&o); 9032185Sminshall netflush(); 91*33801Sminshall while (NETROOM() < 6) { 9232185Sminshall FD_SET(net, &o); 9332185Sminshall (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, 9432185Sminshall (struct timeval *) 0); 9532185Sminshall netflush(); 9632185Sminshall } 9732185Sminshall } 98*33801Sminshall c = loop = ring_empty_consecutive(&netoring); 99*33801Sminshall while (loop) { 100*33801Sminshall if (*buffer == IAC) { 101*33801Sminshall break; 102*33801Sminshall } 103*33801Sminshall buffer++; 104*33801Sminshall loop--; 10532185Sminshall } 106*33801Sminshall if ((c = c-loop)) { 107*33801Sminshall ring_supply_data(&netoring, buffer-c, c); 108*33801Sminshall count -= c; 109*33801Sminshall } 110*33801Sminshall if (loop) { 111*33801Sminshall NET2ADD(IAC, IAC); 112*33801Sminshall count--; 113*33801Sminshall } 11432185Sminshall } 11532185Sminshall 116*33801Sminshall if (done) { 117*33801Sminshall NET2ADD(IAC, IAC); 11832185Sminshall netflush(); /* try to move along as quickly as ... */ 11932185Sminshall } 12032185Sminshall return(origCount - count); 12132185Sminshall } 12232185Sminshall 12332185Sminshall 12432185Sminshall #if defined(unix) 125*33801Sminshall void 12632185Sminshall inputAvailable() 12732185Sminshall { 12832185Sminshall HaveInput = 1; 12932185Sminshall } 13032185Sminshall #endif /* defined(unix) */ 13132185Sminshall 13232185Sminshall void 13332185Sminshall outputPurge() 13432185Sminshall { 13532257Sminshall ttyflush(1); 13632185Sminshall } 13732185Sminshall 13832185Sminshall 13932185Sminshall /* 14032185Sminshall * The following routines are places where the various tn3270 14132185Sminshall * routines make calls into telnet.c. 14232185Sminshall */ 14332185Sminshall 14432185Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 14532185Sminshall 14632185Sminshall int 14732185Sminshall DataToTerminal(buffer, count) 14832185Sminshall register char *buffer; /* where the data is */ 14932185Sminshall register int count; /* how much to send */ 15032185Sminshall { 151*33801Sminshall register int loop, c; 15232185Sminshall int origCount; 15332185Sminshall 15432185Sminshall origCount = count; 15532185Sminshall 15632185Sminshall while (count) { 157*33801Sminshall if (TTYROOM() == 0) { 15832185Sminshall #if defined(unix) 159*33801Sminshall fd_set o; 160*33801Sminshall 161*33801Sminshall FD_ZERO(&o); 162*33801Sminshall #endif /* defined(unix) */ 163*33801Sminshall ttyflush(); 164*33801Sminshall while (TTYROOM() == 0) { 165*33801Sminshall #if defined(unix) 16632185Sminshall FD_SET(tout, &o); 16732185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 16832185Sminshall (struct timeval *) 0); 16932185Sminshall #endif /* defined(unix) */ 170*33801Sminshall ttyflush(); 17132185Sminshall } 17232185Sminshall } 173*33801Sminshall c = loop = ring_empty_consecutive(&ttyoring); 174*33801Sminshall while (loop) { 175*33801Sminshall if (*buffer == IAC) { 176*33801Sminshall break; 177*33801Sminshall } 178*33801Sminshall buffer++; 179*33801Sminshall loop--; 180*33801Sminshall } 181*33801Sminshall if ((c = c-loop)) { 182*33801Sminshall ring_supply_data(&ttyoring, buffer-c, c); 183*33801Sminshall count -= c; 184*33801Sminshall } 18532185Sminshall } 18632185Sminshall return(origCount - count); 18732185Sminshall } 18832185Sminshall 18932185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 19032185Sminshall * Note that we consider the buffer to run all the 19132185Sminshall * way to the kernel (thus the select). 19232185Sminshall */ 19332185Sminshall 19432185Sminshall void 19532185Sminshall EmptyTerminal() 19632185Sminshall { 19732185Sminshall #if defined(unix) 19832185Sminshall fd_set o; 19932185Sminshall 20032185Sminshall FD_ZERO(&o); 20132185Sminshall #endif /* defined(unix) */ 20232185Sminshall 203*33801Sminshall if (TTYBYTES()) { 20432185Sminshall #if defined(unix) 20532185Sminshall FD_SET(tout, &o); 20632185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 20732185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 20832185Sminshall #endif /* defined(unix) */ 20932185Sminshall } else { 210*33801Sminshall while (TTYBYTES()) { 21132257Sminshall ttyflush(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 } 21832185Sminshall } 21932185Sminshall } 22032185Sminshall 22132185Sminshall 22232185Sminshall /* 22332185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 22432185Sminshall */ 22532185Sminshall 226*33801Sminshall int 22732185Sminshall Push3270() 22832185Sminshall { 229*33801Sminshall int save = ring_full_count(&netiring); 23032185Sminshall 231*33801Sminshall if (save) { 232*33801Sminshall if (Ifrontp+save > Ibuf+sizeof Ibuf) { 23332185Sminshall if (Ibackp != Ibuf) { 23432185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 23532185Sminshall Ifrontp -= (Ibackp-Ibuf); 23632185Sminshall Ibackp = Ibuf; 23732185Sminshall } 23832185Sminshall } 239*33801Sminshall if (Ifrontp+save < Ibuf+sizeof Ibuf) { 24032185Sminshall telrcv(); 24132185Sminshall } 24232185Sminshall } 243*33801Sminshall return save != ring_full_count(&netiring); 24432185Sminshall } 24532185Sminshall 24632185Sminshall 24732185Sminshall /* 24832185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 24932185Sminshall * before quitting. 25032185Sminshall */ 25132185Sminshall 252*33801Sminshall void 25332185Sminshall Finish3270() 25432185Sminshall { 25532185Sminshall while (Push3270() || !DoTerminalOutput()) { 25632185Sminshall #if defined(unix) 25732185Sminshall HaveInput = 0; 25832185Sminshall #endif /* defined(unix) */ 25932185Sminshall ; 26032185Sminshall } 26132185Sminshall } 26232185Sminshall 26332185Sminshall 26432185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 26532185Sminshall 26632185Sminshall void 26732185Sminshall StringToTerminal(s) 26832185Sminshall char *s; 26932185Sminshall { 27032185Sminshall int count; 27132185Sminshall 27232185Sminshall count = strlen(s); 27332185Sminshall if (count) { 27432185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 27532185Sminshall } 27632185Sminshall } 27732185Sminshall 27832185Sminshall 27932185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 28032185Sminshall /* _putchar - output a single character to the terminal. This name is so that 28132185Sminshall * curses(3x) can call us to send out data. 28232185Sminshall */ 28332185Sminshall 28432185Sminshall void 28532185Sminshall _putchar(c) 28632185Sminshall char c; 28732185Sminshall { 288*33801Sminshall if (TTYBYTES()) { 28932185Sminshall (void) DataToTerminal(&c, 1); 29032185Sminshall } else { 291*33801Sminshall TTYADD(c); 29232185Sminshall } 29332185Sminshall } 29432185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 29532185Sminshall 29632531Sminshall void 29732531Sminshall SetForExit() 29832531Sminshall { 29932531Sminshall setconnmode(); 30032531Sminshall if (In3270) { 30132531Sminshall Finish3270(); 30232531Sminshall } 30332531Sminshall setcommandmode(); 30432531Sminshall fflush(stdout); 30532531Sminshall fflush(stderr); 30632531Sminshall if (In3270) { 30732531Sminshall StopScreen(1); 30832531Sminshall } 30932531Sminshall setconnmode(); 31032531Sminshall setcommandmode(); 31132531Sminshall } 31232531Sminshall 31332531Sminshall void 31432531Sminshall Exit(returnCode) 31532531Sminshall int returnCode; 31632531Sminshall { 31732531Sminshall SetForExit(); 31832531Sminshall exit(returnCode); 31932531Sminshall } 32032531Sminshall 32132531Sminshall void 32232531Sminshall ExitString(string, returnCode) 32332531Sminshall char *string; 32432531Sminshall int returnCode; 32532531Sminshall { 32632531Sminshall SetForExit(); 32732531Sminshall fwrite(string, 1, strlen(string), stderr); 32832531Sminshall exit(returnCode); 32932531Sminshall } 33032531Sminshall 33132531Sminshall void 33232531Sminshall ExitPerror(string, returnCode) 33332531Sminshall char *string; 33432531Sminshall int returnCode; 33532531Sminshall { 33632531Sminshall SetForExit(); 33732531Sminshall perror(string); 33832531Sminshall exit(returnCode); 33932531Sminshall } 34032531Sminshall 34132531Sminshall void 34232531Sminshall SetIn3270() 34332531Sminshall { 34432531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 34532531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 34632531Sminshall if (!In3270) { 34732531Sminshall In3270 = 1; 34832531Sminshall Init3270(); /* Initialize 3270 functions */ 34932531Sminshall /* initialize terminal key mapping */ 35032531Sminshall InitTerminal(); /* Start terminal going */ 35132531Sminshall setconnmode(); 35232531Sminshall } 35332531Sminshall } else { 35432531Sminshall if (In3270) { 35532531Sminshall StopScreen(1); 35632531Sminshall In3270 = 0; 35732531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 35832531Sminshall setconnmode(); 35932531Sminshall } 36032531Sminshall } 36132531Sminshall } 36232531Sminshall 36332531Sminshall /* 36432531Sminshall * tn3270_ttype() 36532531Sminshall * 36632531Sminshall * Send a response to a terminal type negotiation. 36732531Sminshall * 36832531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 36932531Sminshall */ 37032531Sminshall 37132531Sminshall int 37232531Sminshall tn3270_ttype() 37332531Sminshall { 37432531Sminshall /* 37532531Sminshall * Try to send a 3270 type terminal name. Decide which one based 37632531Sminshall * on the format of our screen, and (in the future) color 37732531Sminshall * capaiblities. 37832531Sminshall */ 37932531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 38032531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 38132531Sminshall Sent3270TerminalType = 1; 38232531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 38332531Sminshall MaxNumberLines = 27; 38432531Sminshall MaxNumberColumns = 132; 38532531Sminshall sb_terminal[SBTERMMODEL] = '5'; 38632531Sminshall } else if (MaxNumberLines >= 43) { 38732531Sminshall MaxNumberLines = 43; 38832531Sminshall MaxNumberColumns = 80; 38932531Sminshall sb_terminal[SBTERMMODEL] = '4'; 39032531Sminshall } else if (MaxNumberLines >= 32) { 39132531Sminshall MaxNumberLines = 32; 39232531Sminshall MaxNumberColumns = 80; 39332531Sminshall sb_terminal[SBTERMMODEL] = '3'; 39432531Sminshall } else { 39532531Sminshall MaxNumberLines = 24; 39632531Sminshall MaxNumberColumns = 80; 39732531Sminshall sb_terminal[SBTERMMODEL] = '2'; 39832531Sminshall } 39932531Sminshall NumberLines = 24; /* before we start out... */ 40032531Sminshall NumberColumns = 80; 40132531Sminshall ScreenSize = NumberLines*NumberColumns; 40232531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 40332531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 40432531Sminshall 1); 40532531Sminshall /*NOTREACHED*/ 40632531Sminshall } 40732531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 40832531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 40932531Sminshall return 1; 41032531Sminshall } else { 41132531Sminshall return 0; 41232531Sminshall } 41332531Sminshall } 414*33801Sminshall 415*33801Sminshall #if defined(unix) 416*33801Sminshall settranscom(argc, argv) 417*33801Sminshall int argc; 418*33801Sminshall char *argv[]; 419*33801Sminshall { 420*33801Sminshall int i, len = 0; 421*33801Sminshall 422*33801Sminshall if (argc == 1 && transcom) { 423*33801Sminshall transcom = 0; 424*33801Sminshall } 425*33801Sminshall if (argc == 1) { 426*33801Sminshall return; 427*33801Sminshall } 428*33801Sminshall for (i = 1; i < argc; ++i) { 429*33801Sminshall len += 1 + strlen(argv[1]); 430*33801Sminshall } 431*33801Sminshall transcom = tline; 432*33801Sminshall (void) strcpy(transcom, argv[1]); 433*33801Sminshall for (i = 2; i < argc; ++i) { 434*33801Sminshall (void) strcat(transcom, " "); 435*33801Sminshall (void) strcat(transcom, argv[i]); 436*33801Sminshall } 437*33801Sminshall } 438*33801Sminshall #endif /* defined(unix) */ 439*33801Sminshall 44032185Sminshall #endif /* defined(TN3270) */ 441