xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 34311)
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*34311Sminshall static char sccsid[] = "@(#)tn3270.c	1.10 (Berkeley) 05/15/88";
1533686Sbostic #endif /* not lint */
1633686Sbostic 
1733801Sminshall #include <sys/types.h>
1833801Sminshall #include <arpa/telnet.h>
1933801Sminshall 
2034305Sminshall #include "general.h"
2134305Sminshall 
2233801Sminshall #include "defines.h"
2333801Sminshall #include "ring.h"
2433801Sminshall #include "externs.h"
2532657Sminshall #include "fdset.h"
2632657Sminshall 
2732185Sminshall #if	defined(TN3270)
2832185Sminshall 
2933801Sminshall #include "../ctlr/screen.h"
3033801Sminshall #include "../general/globals.h"
3132185Sminshall 
3233801Sminshall #if	defined(unix)
3333801Sminshall char	tline[200];
3433801Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
3533801Sminshall #endif	/* defined(unix) */
3632531Sminshall 
3733801Sminshall char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
3832531Sminshall 
3932531Sminshall static char	sb_terminal[] = { IAC, SB,
4032531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
4132531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
4232531Sminshall 			IAC, SE };
4332531Sminshall #define	SBTERMMODEL	13
4432531Sminshall 
4532531Sminshall static int
4632531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
4732531Sminshall 
4833801Sminshall #endif	/* defined(TN3270) */
4932531Sminshall 
5033801Sminshall 
5133801Sminshall void
5234303Sminshall init_3270()
5332551Sminshall {
5433801Sminshall #if	defined(TN3270)
5533801Sminshall     Sent3270TerminalType = 0;
5633801Sminshall     Ifrontp = Ibackp = Ibuf;
5733801Sminshall     init_ctlr();		/* Initialize some things */
5833801Sminshall     init_keyboard();
5933801Sminshall     init_screen();
6033801Sminshall     init_system();
6133801Sminshall #endif	/* defined(TN3270) */
6232551Sminshall }
6332551Sminshall 
6433801Sminshall 
6533801Sminshall #if	defined(TN3270)
6633801Sminshall 
6732185Sminshall /*
6832185Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
6932185Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
7032185Sminshall  * don't call us with "done" until you want that done...)
7132185Sminshall  *
7232185Sminshall  * We actually do send all the data to the network buffer, since our
7332185Sminshall  * only client needs for us to do that.
7432185Sminshall  */
7532185Sminshall 
7632185Sminshall int
7732185Sminshall DataToNetwork(buffer, count, done)
7832185Sminshall register char	*buffer;	/* where the data is */
7932185Sminshall register int	count;		/* how much to send */
8032185Sminshall int		done;		/* is this the last of a logical block */
8132185Sminshall {
8233801Sminshall     register int loop, c;
8332185Sminshall     int origCount;
8432185Sminshall 
8532185Sminshall     origCount = count;
8632185Sminshall 
8732185Sminshall     while (count) {
8834303Sminshall 	/* If not enough room for EORs, IACs, etc., wait */
8933801Sminshall 	if (NETROOM() < 6) {
9033801Sminshall 	    fd_set o;
9133801Sminshall 
9233801Sminshall 	    FD_ZERO(&o);
9332185Sminshall 	    netflush();
9433801Sminshall 	    while (NETROOM() < 6) {
9532185Sminshall 		FD_SET(net, &o);
9632185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
9732185Sminshall 						(struct timeval *) 0);
9832185Sminshall 		netflush();
9932185Sminshall 	    }
10032185Sminshall 	}
10134303Sminshall 	c = ring_empty_count(&netoring);
10234303Sminshall 	if (c > count) {
10334303Sminshall 	    c = count;
10434303Sminshall 	}
10534303Sminshall 	loop = c;
10633801Sminshall 	while (loop) {
107*34311Sminshall 	    if (((unsigned char)*buffer) == IAC) {
10833801Sminshall 		break;
10933801Sminshall 	    }
11033801Sminshall 	    buffer++;
11133801Sminshall 	    loop--;
11232185Sminshall 	}
11333801Sminshall 	if ((c = c-loop)) {
11433801Sminshall 	    ring_supply_data(&netoring, buffer-c, c);
11533801Sminshall 	    count -= c;
11633801Sminshall 	}
11733801Sminshall 	if (loop) {
11833801Sminshall 	    NET2ADD(IAC, IAC);
11933801Sminshall 	    count--;
12034303Sminshall 	    buffer++;
12133801Sminshall 	}
12232185Sminshall     }
12332185Sminshall 
12433801Sminshall     if (done) {
12534303Sminshall 	NET2ADD(IAC, EOR);
12632185Sminshall 	netflush();		/* try to move along as quickly as ... */
12732185Sminshall     }
12832185Sminshall     return(origCount - count);
12932185Sminshall }
13032185Sminshall 
13132185Sminshall 
13232185Sminshall #if	defined(unix)
13333801Sminshall void
13432185Sminshall inputAvailable()
13532185Sminshall {
13632185Sminshall     HaveInput = 1;
13732185Sminshall }
13832185Sminshall #endif	/* defined(unix) */
13932185Sminshall 
14032185Sminshall void
14132185Sminshall outputPurge()
14232185Sminshall {
14332257Sminshall     ttyflush(1);
14432185Sminshall }
14532185Sminshall 
14632185Sminshall 
14732185Sminshall /*
14832185Sminshall  * The following routines are places where the various tn3270
14932185Sminshall  * routines make calls into telnet.c.
15032185Sminshall  */
15132185Sminshall 
15234303Sminshall /*
15334303Sminshall  * DataToTerminal - queue up some data to go to terminal.
15434303Sminshall  *
15534303Sminshall  * Note: there are people who call us and depend on our processing
15634303Sminshall  * *all* the data at one time (thus the select).
15734303Sminshall  */
15832185Sminshall 
15932185Sminshall int
16032185Sminshall DataToTerminal(buffer, count)
16132185Sminshall register char	*buffer;		/* where the data is */
16232185Sminshall register int	count;			/* how much to send */
16332185Sminshall {
16433801Sminshall     register int loop, c;
16532185Sminshall     int origCount;
16632185Sminshall 
16732185Sminshall     origCount = count;
16832185Sminshall 
16932185Sminshall     while (count) {
17033801Sminshall 	if (TTYROOM() == 0) {
17132185Sminshall #if	defined(unix)
17233801Sminshall 	    fd_set o;
17333801Sminshall 
17433801Sminshall 	    FD_ZERO(&o);
17533801Sminshall #endif	/* defined(unix) */
17633801Sminshall 	    ttyflush();
17733801Sminshall 	    while (TTYROOM() == 0) {
17833801Sminshall #if	defined(unix)
17932185Sminshall 		FD_SET(tout, &o);
18032185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
18132185Sminshall 						(struct timeval *) 0);
18232185Sminshall #endif	/* defined(unix) */
18333801Sminshall 		ttyflush();
18432185Sminshall 	    }
18532185Sminshall 	}
18634303Sminshall 	c = TTYROOM();
18734303Sminshall 	if (c > count) {
18834303Sminshall 	    c = count;
18933801Sminshall 	}
19034303Sminshall 	ring_supply_data(&ttyoring, buffer, c);
19134303Sminshall 	count -= c;
19234303Sminshall 	buffer += c;
19332185Sminshall     }
19434303Sminshall     return(origCount);
19532185Sminshall }
19632185Sminshall 
19732185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
19832185Sminshall  *			Note that we consider the buffer to run all the
19932185Sminshall  *			way to the kernel (thus the select).
20032185Sminshall  */
20132185Sminshall 
20232185Sminshall void
20332185Sminshall EmptyTerminal()
20432185Sminshall {
20532185Sminshall #if	defined(unix)
20632185Sminshall     fd_set	o;
20732185Sminshall 
20832185Sminshall     FD_ZERO(&o);
20932185Sminshall #endif	/* defined(unix) */
21032185Sminshall 
21134303Sminshall     if (TTYBYTES() == 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     } else {
21833801Sminshall 	while (TTYBYTES()) {
21932257Sminshall 	    ttyflush(0);
22032185Sminshall #if	defined(unix)
22132185Sminshall 	    FD_SET(tout, &o);
22232185Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
22332185Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
22432185Sminshall #endif	/* defined(unix) */
22532185Sminshall 	}
22632185Sminshall     }
22732185Sminshall }
22832185Sminshall 
22932185Sminshall 
23032185Sminshall /*
23132185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
23232185Sminshall  */
23332185Sminshall 
23433801Sminshall int
23532185Sminshall Push3270()
23632185Sminshall {
23733801Sminshall     int save = ring_full_count(&netiring);
23832185Sminshall 
23933801Sminshall     if (save) {
24033801Sminshall 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
24132185Sminshall 	    if (Ibackp != Ibuf) {
24232185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
24332185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
24432185Sminshall 		Ibackp = Ibuf;
24532185Sminshall 	    }
24632185Sminshall 	}
24733801Sminshall 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
24832185Sminshall 	    telrcv();
24932185Sminshall 	}
25032185Sminshall     }
25133801Sminshall     return save != ring_full_count(&netiring);
25232185Sminshall }
25332185Sminshall 
25432185Sminshall 
25532185Sminshall /*
25632185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
25732185Sminshall  *		before quitting.
25832185Sminshall  */
25932185Sminshall 
26033801Sminshall void
26132185Sminshall Finish3270()
26232185Sminshall {
26332185Sminshall     while (Push3270() || !DoTerminalOutput()) {
26432185Sminshall #if	defined(unix)
26532185Sminshall 	HaveInput = 0;
26632185Sminshall #endif	/* defined(unix) */
26732185Sminshall 	;
26832185Sminshall     }
26932185Sminshall }
27032185Sminshall 
27132185Sminshall 
27232185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
27332185Sminshall 
27432185Sminshall void
27532185Sminshall StringToTerminal(s)
27632185Sminshall char *s;
27732185Sminshall {
27832185Sminshall     int count;
27932185Sminshall 
28032185Sminshall     count = strlen(s);
28132185Sminshall     if (count) {
28232185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
28332185Sminshall     }
28432185Sminshall }
28532185Sminshall 
28632185Sminshall 
28732185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
28832185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
28932185Sminshall  *	curses(3x) can call us to send out data.
29032185Sminshall  */
29132185Sminshall 
29232185Sminshall void
29332185Sminshall _putchar(c)
29432185Sminshall char c;
29532185Sminshall {
29633801Sminshall     if (TTYBYTES()) {
29732185Sminshall 	(void) DataToTerminal(&c, 1);
29832185Sminshall     } else {
29933801Sminshall 	TTYADD(c);
30032185Sminshall     }
30132185Sminshall }
30232185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
30332185Sminshall 
30432531Sminshall void
30532531Sminshall SetForExit()
30632531Sminshall {
30732531Sminshall     setconnmode();
30832531Sminshall     if (In3270) {
30932531Sminshall 	Finish3270();
31032531Sminshall     }
31132531Sminshall     setcommandmode();
31232531Sminshall     fflush(stdout);
31332531Sminshall     fflush(stderr);
31432531Sminshall     if (In3270) {
31532531Sminshall 	StopScreen(1);
31632531Sminshall     }
31732531Sminshall     setconnmode();
31832531Sminshall     setcommandmode();
31932531Sminshall }
32032531Sminshall 
32132531Sminshall void
32232531Sminshall Exit(returnCode)
32332531Sminshall int returnCode;
32432531Sminshall {
32532531Sminshall     SetForExit();
32632531Sminshall     exit(returnCode);
32732531Sminshall }
32832531Sminshall 
32932531Sminshall void
33032531Sminshall ExitString(string, returnCode)
33132531Sminshall char *string;
33232531Sminshall int returnCode;
33332531Sminshall {
33432531Sminshall     SetForExit();
33532531Sminshall     fwrite(string, 1, strlen(string), stderr);
33632531Sminshall     exit(returnCode);
33732531Sminshall }
33832531Sminshall 
33932531Sminshall void
34032531Sminshall ExitPerror(string, returnCode)
34132531Sminshall char *string;
34232531Sminshall int returnCode;
34332531Sminshall {
34432531Sminshall     SetForExit();
34532531Sminshall     perror(string);
34632531Sminshall     exit(returnCode);
34732531Sminshall }
34832531Sminshall 
34932531Sminshall void
35032531Sminshall SetIn3270()
35132531Sminshall {
35232531Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
35332531Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
35432531Sminshall 	if (!In3270) {
35532531Sminshall 	    In3270 = 1;
35632531Sminshall 	    Init3270();		/* Initialize 3270 functions */
35732531Sminshall 	    /* initialize terminal key mapping */
35832531Sminshall 	    InitTerminal();	/* Start terminal going */
35932531Sminshall 	    setconnmode();
36032531Sminshall 	}
36132531Sminshall     } else {
36232531Sminshall 	if (In3270) {
36332531Sminshall 	    StopScreen(1);
36432531Sminshall 	    In3270 = 0;
36532531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
36632531Sminshall 	    setconnmode();
36732531Sminshall 	}
36832531Sminshall     }
36932531Sminshall }
37032531Sminshall 
37132531Sminshall /*
37232531Sminshall  * tn3270_ttype()
37332531Sminshall  *
37432531Sminshall  *	Send a response to a terminal type negotiation.
37532531Sminshall  *
37632531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
37732531Sminshall  */
37832531Sminshall 
37932531Sminshall int
38032531Sminshall tn3270_ttype()
38132531Sminshall {
38232531Sminshall     /*
38332531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
38432531Sminshall      * on the format of our screen, and (in the future) color
38532531Sminshall      * capaiblities.
38632531Sminshall      */
38732531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
38832531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
38932531Sminshall 	Sent3270TerminalType = 1;
39032531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
39132531Sminshall 	    MaxNumberLines = 27;
39232531Sminshall 	    MaxNumberColumns = 132;
39332531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
39432531Sminshall 	} else if (MaxNumberLines >= 43) {
39532531Sminshall 	    MaxNumberLines = 43;
39632531Sminshall 	    MaxNumberColumns = 80;
39732531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
39832531Sminshall 	} else if (MaxNumberLines >= 32) {
39932531Sminshall 	    MaxNumberLines = 32;
40032531Sminshall 	    MaxNumberColumns = 80;
40132531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
40232531Sminshall 	} else {
40332531Sminshall 	    MaxNumberLines = 24;
40432531Sminshall 	    MaxNumberColumns = 80;
40532531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
40632531Sminshall 	}
40732531Sminshall 	NumberLines = 24;		/* before we start out... */
40832531Sminshall 	NumberColumns = 80;
40932531Sminshall 	ScreenSize = NumberLines*NumberColumns;
41032531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
41132531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
41232531Sminshall 								1);
41332531Sminshall 	    /*NOTREACHED*/
41432531Sminshall 	}
41532531Sminshall 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
41632531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
41732531Sminshall 	return 1;
41832531Sminshall     } else {
41932531Sminshall 	return 0;
42032531Sminshall     }
42132531Sminshall }
42233801Sminshall 
42333801Sminshall #if	defined(unix)
42433801Sminshall settranscom(argc, argv)
42533801Sminshall 	int argc;
42633801Sminshall 	char *argv[];
42733801Sminshall {
42833801Sminshall 	int i, len = 0;
42933801Sminshall 
43033801Sminshall 	if (argc == 1 && transcom) {
43133801Sminshall 	   transcom = 0;
43233801Sminshall 	}
43333801Sminshall 	if (argc == 1) {
43433801Sminshall 	   return;
43533801Sminshall 	}
43633801Sminshall 	for (i = 1; i < argc; ++i) {
43733801Sminshall 	    len += 1 + strlen(argv[1]);
43833801Sminshall 	}
43933801Sminshall 	transcom = tline;
44033801Sminshall 	(void) strcpy(transcom, argv[1]);
44133801Sminshall 	for (i = 2; i < argc; ++i) {
44233801Sminshall 	    (void) strcat(transcom, " ");
44333801Sminshall 	    (void) strcat(transcom, argv[i]);
44433801Sminshall 	}
44533801Sminshall }
44633801Sminshall #endif	/* defined(unix) */
44733801Sminshall 
44832185Sminshall #endif	/* defined(TN3270) */
449