1*33686Sbostic /* 2*33686Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33686Sbostic * All rights reserved. 4*33686Sbostic * 5*33686Sbostic * Redistribution and use in source and binary forms are permitted 6*33686Sbostic * provided that this notice is preserved and that due credit is given 7*33686Sbostic * to the University of California at Berkeley. The name of the University 8*33686Sbostic * may not be used to endorse or promote products derived from this 9*33686Sbostic * software without specific prior written permission. This software 10*33686Sbostic * is provided ``as is'' without express or implied warranty. 11*33686Sbostic */ 12*33686Sbostic 13*33686Sbostic #ifndef lint 14*33686Sbostic static char sccsid[] = "@(#)tn3270.c 1.6 (Berkeley) 03/08/88"; 15*33686Sbostic #endif /* not lint */ 16*33686Sbostic 1732657Sminshall #include "fdset.h" 1832657Sminshall 1932185Sminshall void 2032185Sminshall tn3270_init() 2132185Sminshall { 2232185Sminshall #if defined(TN3270) 2332185Sminshall Sent3270TerminalType = 0; 2432185Sminshall Ifrontp = Ibackp = Ibuf; 2532185Sminshall init_ctlr(); /* Initialize some things */ 2632185Sminshall init_keyboard(); 2732185Sminshall init_screen(); 2832185Sminshall init_system(); 2932185Sminshall #endif /* defined(TN3270) */ 3032185Sminshall } 3132185Sminshall 3232185Sminshall #if defined(TN3270) 3332185Sminshall 3432531Sminshall 3532531Sminshall static 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 4632531Sminshall 4732551Sminshall #if defined(unix) 4832551Sminshall static 4932551Sminshall settranscom(argc, argv) 5032551Sminshall int argc; 5132551Sminshall char *argv[]; 5232551Sminshall { 5332551Sminshall int i, len = 0; 5432551Sminshall char *strcpy(), *strcat(); 5532551Sminshall 5632551Sminshall if (argc == 1 && transcom) { 5732551Sminshall transcom = 0; 5832551Sminshall } 5932551Sminshall if (argc == 1) { 6032551Sminshall return; 6132551Sminshall } 6232551Sminshall for (i = 1; i < argc; ++i) { 6332551Sminshall len += 1 + strlen(argv[1]); 6432551Sminshall } 6532551Sminshall transcom = tline; 6632551Sminshall (void) strcpy(transcom, argv[1]); 6732551Sminshall for (i = 2; i < argc; ++i) { 6832551Sminshall (void) strcat(transcom, " "); 6932551Sminshall (void) strcat(transcom, argv[i]); 7032551Sminshall } 7132551Sminshall } 7232551Sminshall #endif /* defined(unix) */ 7332551Sminshall 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 { 8932185Sminshall register int c; 9032185Sminshall int origCount; 9132185Sminshall fd_set o; 9232185Sminshall 9332185Sminshall origCount = count; 9432185Sminshall FD_ZERO(&o); 9532185Sminshall 9632185Sminshall while (count) { 9732185Sminshall if ((netobuf+sizeof netobuf - nfrontp) < 6) { 9832185Sminshall netflush(); 9932185Sminshall while ((netobuf+sizeof netobuf - nfrontp) < 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 } 10632185Sminshall c = *buffer++; 10732185Sminshall count--; 10832185Sminshall if (c == IAC) { 10932185Sminshall *nfrontp++ = IAC; 11032185Sminshall *nfrontp++ = IAC; 11132185Sminshall } else { 11232185Sminshall *nfrontp++ = c; 11332185Sminshall } 11432185Sminshall } 11532185Sminshall 11632185Sminshall if (done && !count) { 11732185Sminshall *nfrontp++ = IAC; 11832185Sminshall *nfrontp++ = EOR; 11932185Sminshall netflush(); /* try to move along as quickly as ... */ 12032185Sminshall } 12132185Sminshall return(origCount - count); 12232185Sminshall } 12332185Sminshall 12432185Sminshall 12532185Sminshall #if defined(unix) 12632185Sminshall static void 12732185Sminshall inputAvailable() 12832185Sminshall { 12932185Sminshall HaveInput = 1; 13032185Sminshall } 13132185Sminshall #endif /* defined(unix) */ 13232185Sminshall 13332185Sminshall void 13432185Sminshall outputPurge() 13532185Sminshall { 13632257Sminshall ttyflush(1); 13732185Sminshall } 13832185Sminshall 13932185Sminshall 14032185Sminshall /* 14132185Sminshall * The following routines are places where the various tn3270 14232185Sminshall * routines make calls into telnet.c. 14332185Sminshall */ 14432185Sminshall 14532185Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */ 14632185Sminshall TtyChars() 14732185Sminshall { 14832185Sminshall return(tfrontp-tbackp); 14932185Sminshall } 15032185Sminshall 15132185Sminshall /* DataToTerminal - queue up some data to go to terminal. */ 15232185Sminshall 15332185Sminshall int 15432185Sminshall DataToTerminal(buffer, count) 15532185Sminshall register char *buffer; /* where the data is */ 15632185Sminshall register int count; /* how much to send */ 15732185Sminshall { 15832185Sminshall int origCount; 15932185Sminshall #if defined(unix) 16032185Sminshall fd_set o; 16132185Sminshall 16232185Sminshall FD_ZERO(&o); 16332185Sminshall #endif /* defined(unix) */ 16432185Sminshall origCount = count; 16532185Sminshall 16632185Sminshall while (count) { 16732185Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 16832257Sminshall ttyflush(0); 16932185Sminshall while (tfrontp >= ttyobuf+sizeof ttyobuf) { 17032185Sminshall #if defined(unix) 17132185Sminshall FD_SET(tout, &o); 17232185Sminshall (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 17332185Sminshall (struct timeval *) 0); 17432185Sminshall #endif /* defined(unix) */ 17532257Sminshall ttyflush(0); 17632185Sminshall } 17732185Sminshall } 17832185Sminshall *tfrontp++ = *buffer++; 17932185Sminshall count--; 18032185Sminshall } 18132185Sminshall return(origCount - count); 18232185Sminshall } 18332185Sminshall 18432185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty. 18532185Sminshall * Note that we consider the buffer to run all the 18632185Sminshall * way to the kernel (thus the select). 18732185Sminshall */ 18832185Sminshall 18932185Sminshall void 19032185Sminshall EmptyTerminal() 19132185Sminshall { 19232185Sminshall #if defined(unix) 19332185Sminshall fd_set o; 19432185Sminshall 19532185Sminshall FD_ZERO(&o); 19632185Sminshall #endif /* defined(unix) */ 19732185Sminshall 19832185Sminshall if (tfrontp == tbackp) { 19932185Sminshall #if defined(unix) 20032185Sminshall FD_SET(tout, &o); 20132185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 20232185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 20332185Sminshall #endif /* defined(unix) */ 20432185Sminshall } else { 20532185Sminshall while (tfrontp != tbackp) { 20632257Sminshall ttyflush(0); 20732185Sminshall #if defined(unix) 20832185Sminshall FD_SET(tout, &o); 20932185Sminshall (void) select(tout+1, (int *) 0, &o, (int *) 0, 21032185Sminshall (struct timeval *) 0); /* wait for TTLOWAT */ 21132185Sminshall #endif /* defined(unix) */ 21232185Sminshall } 21332185Sminshall } 21432185Sminshall } 21532185Sminshall 21632185Sminshall 21732185Sminshall /* 21832185Sminshall * Push3270 - Try to send data along the 3270 output (to screen) direction. 21932185Sminshall */ 22032185Sminshall 22132185Sminshall static int 22232185Sminshall Push3270() 22332185Sminshall { 22432185Sminshall int save = scc; 22532185Sminshall 22632185Sminshall if (scc) { 22732185Sminshall if (Ifrontp+scc > Ibuf+sizeof Ibuf) { 22832185Sminshall if (Ibackp != Ibuf) { 22932185Sminshall memcpy(Ibuf, Ibackp, Ifrontp-Ibackp); 23032185Sminshall Ifrontp -= (Ibackp-Ibuf); 23132185Sminshall Ibackp = Ibuf; 23232185Sminshall } 23332185Sminshall } 23432185Sminshall if (Ifrontp+scc < Ibuf+sizeof Ibuf) { 23532185Sminshall telrcv(); 23632185Sminshall } 23732185Sminshall } 23832185Sminshall return save != scc; 23932185Sminshall } 24032185Sminshall 24132185Sminshall 24232185Sminshall /* 24332185Sminshall * Finish3270 - get the last dregs of 3270 data out to the terminal 24432185Sminshall * before quitting. 24532185Sminshall */ 24632185Sminshall 24732185Sminshall static void 24832185Sminshall Finish3270() 24932185Sminshall { 25032185Sminshall while (Push3270() || !DoTerminalOutput()) { 25132185Sminshall #if defined(unix) 25232185Sminshall HaveInput = 0; 25332185Sminshall #endif /* defined(unix) */ 25432185Sminshall ; 25532185Sminshall } 25632185Sminshall } 25732185Sminshall 25832185Sminshall 25932185Sminshall /* StringToTerminal - output a null terminated string to the terminal */ 26032185Sminshall 26132185Sminshall void 26232185Sminshall StringToTerminal(s) 26332185Sminshall char *s; 26432185Sminshall { 26532185Sminshall int count; 26632185Sminshall 26732185Sminshall count = strlen(s); 26832185Sminshall if (count) { 26932185Sminshall (void) DataToTerminal(s, count); /* we know it always goes... */ 27032185Sminshall } 27132185Sminshall } 27232185Sminshall 27332185Sminshall 27432185Sminshall #if ((!defined(NOT43)) || defined(PUTCHAR)) 27532185Sminshall /* _putchar - output a single character to the terminal. This name is so that 27632185Sminshall * curses(3x) can call us to send out data. 27732185Sminshall */ 27832185Sminshall 27932185Sminshall void 28032185Sminshall _putchar(c) 28132185Sminshall char c; 28232185Sminshall { 28332185Sminshall if (tfrontp >= ttyobuf+sizeof ttyobuf) { 28432185Sminshall (void) DataToTerminal(&c, 1); 28532185Sminshall } else { 28632185Sminshall *tfrontp++ = c; /* optimize if possible. */ 28732185Sminshall } 28832185Sminshall } 28932185Sminshall #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ 29032185Sminshall 29132531Sminshall void 29232531Sminshall SetForExit() 29332531Sminshall { 29432531Sminshall setconnmode(); 29532531Sminshall if (In3270) { 29632531Sminshall Finish3270(); 29732531Sminshall } 29832531Sminshall setcommandmode(); 29932531Sminshall fflush(stdout); 30032531Sminshall fflush(stderr); 30132531Sminshall if (In3270) { 30232531Sminshall StopScreen(1); 30332531Sminshall } 30432531Sminshall setconnmode(); 30532531Sminshall setcommandmode(); 30632531Sminshall } 30732531Sminshall 30832531Sminshall void 30932531Sminshall Exit(returnCode) 31032531Sminshall int returnCode; 31132531Sminshall { 31232531Sminshall SetForExit(); 31332531Sminshall exit(returnCode); 31432531Sminshall } 31532531Sminshall 31632531Sminshall void 31732531Sminshall ExitString(string, returnCode) 31832531Sminshall char *string; 31932531Sminshall int returnCode; 32032531Sminshall { 32132531Sminshall SetForExit(); 32232531Sminshall fwrite(string, 1, strlen(string), stderr); 32332531Sminshall exit(returnCode); 32432531Sminshall } 32532531Sminshall 32632531Sminshall void 32732531Sminshall ExitPerror(string, returnCode) 32832531Sminshall char *string; 32932531Sminshall int returnCode; 33032531Sminshall { 33132531Sminshall SetForExit(); 33232531Sminshall perror(string); 33332531Sminshall exit(returnCode); 33432531Sminshall } 33532531Sminshall 33632531Sminshall void 33732531Sminshall SetIn3270() 33832531Sminshall { 33932531Sminshall if (Sent3270TerminalType && myopts[TELOPT_BINARY] 34032531Sminshall && hisopts[TELOPT_BINARY] && !donebinarytoggle) { 34132531Sminshall if (!In3270) { 34232531Sminshall In3270 = 1; 34332531Sminshall Init3270(); /* Initialize 3270 functions */ 34432531Sminshall /* initialize terminal key mapping */ 34532531Sminshall InitTerminal(); /* Start terminal going */ 34632531Sminshall setconnmode(); 34732531Sminshall } 34832531Sminshall } else { 34932531Sminshall if (In3270) { 35032531Sminshall StopScreen(1); 35132531Sminshall In3270 = 0; 35232531Sminshall Stop3270(); /* Tell 3270 we aren't here anymore */ 35332531Sminshall setconnmode(); 35432531Sminshall } 35532531Sminshall } 35632531Sminshall } 35732531Sminshall 35832531Sminshall /* 35932531Sminshall * tn3270_ttype() 36032531Sminshall * 36132531Sminshall * Send a response to a terminal type negotiation. 36232531Sminshall * 36332531Sminshall * Return '0' if no more responses to send; '1' if a response sent. 36432531Sminshall */ 36532531Sminshall 36632531Sminshall int 36732531Sminshall tn3270_ttype() 36832531Sminshall { 36932531Sminshall /* 37032531Sminshall * Try to send a 3270 type terminal name. Decide which one based 37132531Sminshall * on the format of our screen, and (in the future) color 37232531Sminshall * capaiblities. 37332531Sminshall */ 37432531Sminshall InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ 37532531Sminshall if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { 37632531Sminshall Sent3270TerminalType = 1; 37732531Sminshall if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { 37832531Sminshall MaxNumberLines = 27; 37932531Sminshall MaxNumberColumns = 132; 38032531Sminshall sb_terminal[SBTERMMODEL] = '5'; 38132531Sminshall } else if (MaxNumberLines >= 43) { 38232531Sminshall MaxNumberLines = 43; 38332531Sminshall MaxNumberColumns = 80; 38432531Sminshall sb_terminal[SBTERMMODEL] = '4'; 38532531Sminshall } else if (MaxNumberLines >= 32) { 38632531Sminshall MaxNumberLines = 32; 38732531Sminshall MaxNumberColumns = 80; 38832531Sminshall sb_terminal[SBTERMMODEL] = '3'; 38932531Sminshall } else { 39032531Sminshall MaxNumberLines = 24; 39132531Sminshall MaxNumberColumns = 80; 39232531Sminshall sb_terminal[SBTERMMODEL] = '2'; 39332531Sminshall } 39432531Sminshall NumberLines = 24; /* before we start out... */ 39532531Sminshall NumberColumns = 80; 39632531Sminshall ScreenSize = NumberLines*NumberColumns; 39732531Sminshall if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { 39832531Sminshall ExitString("Programming error: MAXSCREENSIZE too small.\n", 39932531Sminshall 1); 40032531Sminshall /*NOTREACHED*/ 40132531Sminshall } 40232531Sminshall printsub(">", sb_terminal+2, sizeof sb_terminal-2); 40332531Sminshall ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); 40432531Sminshall return 1; 40532531Sminshall } else { 40632531Sminshall return 0; 40732531Sminshall } 40832531Sminshall } 40932185Sminshall #endif /* defined(TN3270) */ 410