xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 33801)
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