xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 38690)
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*38690Sborman static char sccsid[] = "@(#)tn3270.c	1.19 (Berkeley) 08/21/89";
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 
3735417Sminshall #include "../telextrn.h"
3835417Sminshall #include "../ctlr/externs.h"
3935417Sminshall 
4033801Sminshall #if	defined(unix)
4136240Sminshall int
4236240Sminshall 	HaveInput,		/* There is input available to scan */
4338208Sminshall 	cursesdata,		/* Do we dump curses data? */
4436240Sminshall 	sigiocount;		/* Number of times we got a SIGIO */
4536240Sminshall 
4633801Sminshall char	tline[200];
4733801Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
4833801Sminshall #endif	/* defined(unix) */
4932531Sminshall 
5033801Sminshall char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
5132531Sminshall 
5232531Sminshall static char	sb_terminal[] = { IAC, SB,
5332531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
5432531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
5532531Sminshall 			IAC, SE };
5632531Sminshall #define	SBTERMMODEL	13
5732531Sminshall 
5832531Sminshall static int
5932531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
6032531Sminshall 
6133801Sminshall #endif	/* defined(TN3270) */
6232531Sminshall 
6333801Sminshall 
6433801Sminshall void
6534303Sminshall init_3270()
6632551Sminshall {
6733801Sminshall #if	defined(TN3270)
6836240Sminshall #if	defined(unix)
6936240Sminshall     HaveInput = 0;
7036240Sminshall     sigiocount = 0;
7136240Sminshall #endif	/* defined(unix) */
7233801Sminshall     Sent3270TerminalType = 0;
7333801Sminshall     Ifrontp = Ibackp = Ibuf;
7433801Sminshall     init_ctlr();		/* Initialize some things */
7533801Sminshall     init_keyboard();
7633801Sminshall     init_screen();
7733801Sminshall     init_system();
7833801Sminshall #endif	/* defined(TN3270) */
7932551Sminshall }
8032551Sminshall 
8133801Sminshall 
8233801Sminshall #if	defined(TN3270)
8333801Sminshall 
8432185Sminshall /*
8532185Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
8632185Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
8732185Sminshall  * don't call us with "done" until you want that done...)
8832185Sminshall  *
8932185Sminshall  * We actually do send all the data to the network buffer, since our
9032185Sminshall  * only client needs for us to do that.
9132185Sminshall  */
9232185Sminshall 
9332185Sminshall int
9432185Sminshall DataToNetwork(buffer, count, done)
9532185Sminshall register char	*buffer;	/* where the data is */
9632185Sminshall register int	count;		/* how much to send */
9732185Sminshall int		done;		/* is this the last of a logical block */
9832185Sminshall {
9933801Sminshall     register int loop, c;
10032185Sminshall     int origCount;
10132185Sminshall 
10232185Sminshall     origCount = count;
10332185Sminshall 
10432185Sminshall     while (count) {
10534303Sminshall 	/* If not enough room for EORs, IACs, etc., wait */
10633801Sminshall 	if (NETROOM() < 6) {
10733801Sminshall 	    fd_set o;
10833801Sminshall 
10933801Sminshall 	    FD_ZERO(&o);
11032185Sminshall 	    netflush();
11133801Sminshall 	    while (NETROOM() < 6) {
11232185Sminshall 		FD_SET(net, &o);
11332185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
11432185Sminshall 						(struct timeval *) 0);
11532185Sminshall 		netflush();
11632185Sminshall 	    }
11732185Sminshall 	}
11834303Sminshall 	c = ring_empty_count(&netoring);
11934303Sminshall 	if (c > count) {
12034303Sminshall 	    c = count;
12134303Sminshall 	}
12234303Sminshall 	loop = c;
12333801Sminshall 	while (loop) {
12434311Sminshall 	    if (((unsigned char)*buffer) == IAC) {
12533801Sminshall 		break;
12633801Sminshall 	    }
12733801Sminshall 	    buffer++;
12833801Sminshall 	    loop--;
12932185Sminshall 	}
13033801Sminshall 	if ((c = c-loop)) {
13133801Sminshall 	    ring_supply_data(&netoring, buffer-c, c);
13233801Sminshall 	    count -= c;
13333801Sminshall 	}
13433801Sminshall 	if (loop) {
13533801Sminshall 	    NET2ADD(IAC, IAC);
13633801Sminshall 	    count--;
13734303Sminshall 	    buffer++;
13833801Sminshall 	}
13932185Sminshall     }
14032185Sminshall 
14133801Sminshall     if (done) {
14234303Sminshall 	NET2ADD(IAC, EOR);
14332185Sminshall 	netflush();		/* try to move along as quickly as ... */
14432185Sminshall     }
14532185Sminshall     return(origCount - count);
14632185Sminshall }
14732185Sminshall 
14832185Sminshall 
14932185Sminshall #if	defined(unix)
15033801Sminshall void
15132185Sminshall inputAvailable()
15232185Sminshall {
15332185Sminshall     HaveInput = 1;
15436240Sminshall     sigiocount++;
15532185Sminshall }
15632185Sminshall #endif	/* defined(unix) */
15732185Sminshall 
15832185Sminshall void
15932185Sminshall outputPurge()
16032185Sminshall {
16132257Sminshall     ttyflush(1);
16232185Sminshall }
16332185Sminshall 
16432185Sminshall 
16532185Sminshall /*
16632185Sminshall  * The following routines are places where the various tn3270
16732185Sminshall  * routines make calls into telnet.c.
16832185Sminshall  */
16932185Sminshall 
17034303Sminshall /*
17134303Sminshall  * DataToTerminal - queue up some data to go to terminal.
17234303Sminshall  *
17334303Sminshall  * Note: there are people who call us and depend on our processing
17434303Sminshall  * *all* the data at one time (thus the select).
17534303Sminshall  */
17632185Sminshall 
17732185Sminshall int
17832185Sminshall DataToTerminal(buffer, count)
17932185Sminshall register char	*buffer;		/* where the data is */
18032185Sminshall register int	count;			/* how much to send */
18132185Sminshall {
18235417Sminshall     register int c;
18332185Sminshall     int origCount;
18432185Sminshall 
18532185Sminshall     origCount = count;
18632185Sminshall 
18732185Sminshall     while (count) {
18833801Sminshall 	if (TTYROOM() == 0) {
18932185Sminshall #if	defined(unix)
19033801Sminshall 	    fd_set o;
19133801Sminshall 
19233801Sminshall 	    FD_ZERO(&o);
19333801Sminshall #endif	/* defined(unix) */
19435417Sminshall 	    ttyflush(0);
19533801Sminshall 	    while (TTYROOM() == 0) {
19633801Sminshall #if	defined(unix)
19732185Sminshall 		FD_SET(tout, &o);
19832185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
19932185Sminshall 						(struct timeval *) 0);
20032185Sminshall #endif	/* defined(unix) */
20135417Sminshall 		ttyflush(0);
20232185Sminshall 	    }
20332185Sminshall 	}
20434303Sminshall 	c = TTYROOM();
20534303Sminshall 	if (c > count) {
20634303Sminshall 	    c = count;
20733801Sminshall 	}
20834303Sminshall 	ring_supply_data(&ttyoring, buffer, c);
20934303Sminshall 	count -= c;
21034303Sminshall 	buffer += c;
21132185Sminshall     }
21234303Sminshall     return(origCount);
21332185Sminshall }
21432185Sminshall 
21532185Sminshall 
21632185Sminshall /*
21732185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
21832185Sminshall  */
21932185Sminshall 
22033801Sminshall int
22132185Sminshall Push3270()
22232185Sminshall {
22333801Sminshall     int save = ring_full_count(&netiring);
22432185Sminshall 
22533801Sminshall     if (save) {
22633801Sminshall 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
22732185Sminshall 	    if (Ibackp != Ibuf) {
22832185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
22932185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
23032185Sminshall 		Ibackp = Ibuf;
23132185Sminshall 	    }
23232185Sminshall 	}
23333801Sminshall 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
23432185Sminshall 	    telrcv();
23532185Sminshall 	}
23632185Sminshall     }
23733801Sminshall     return save != ring_full_count(&netiring);
23832185Sminshall }
23932185Sminshall 
24032185Sminshall 
24132185Sminshall /*
24232185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
24332185Sminshall  *		before quitting.
24432185Sminshall  */
24532185Sminshall 
24633801Sminshall void
24732185Sminshall Finish3270()
24832185Sminshall {
24932185Sminshall     while (Push3270() || !DoTerminalOutput()) {
25032185Sminshall #if	defined(unix)
25132185Sminshall 	HaveInput = 0;
25232185Sminshall #endif	/* defined(unix) */
25332185Sminshall 	;
25432185Sminshall     }
25532185Sminshall }
25632185Sminshall 
25732185Sminshall 
25832185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
25932185Sminshall 
26032185Sminshall void
26132185Sminshall StringToTerminal(s)
26232185Sminshall char *s;
26332185Sminshall {
26432185Sminshall     int count;
26532185Sminshall 
26632185Sminshall     count = strlen(s);
26732185Sminshall     if (count) {
26832185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
26932185Sminshall     }
27032185Sminshall }
27132185Sminshall 
27232185Sminshall 
27332185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
27432185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
27532185Sminshall  *	curses(3x) can call us to send out data.
27632185Sminshall  */
27732185Sminshall 
27832185Sminshall void
27932185Sminshall _putchar(c)
28032185Sminshall char c;
28132185Sminshall {
28236201Sminshall #if	defined(sun)		/* SunOS 4.0 bug */
28336201Sminshall     c &= 0x7f;
28436201Sminshall #endif	/* defined(sun) */
28538208Sminshall     if (cursesdata) {
28638208Sminshall 	Dump('>', &c, 1);
28738208Sminshall     }
28836240Sminshall     if (!TTYROOM()) {
28932185Sminshall 	(void) DataToTerminal(&c, 1);
29032185Sminshall     } else {
29133801Sminshall 	TTYADD(c);
29232185Sminshall     }
29332185Sminshall }
29432185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
29532185Sminshall 
29632531Sminshall void
29732531Sminshall SetIn3270()
29832531Sminshall {
299*38690Sborman     if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
300*38690Sborman 		&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
30132531Sminshall 	if (!In3270) {
30232531Sminshall 	    In3270 = 1;
30332531Sminshall 	    Init3270();		/* Initialize 3270 functions */
30432531Sminshall 	    /* initialize terminal key mapping */
30532531Sminshall 	    InitTerminal();	/* Start terminal going */
306*38690Sborman 	    setconnmode(0);
30732531Sminshall 	}
30832531Sminshall     } else {
30932531Sminshall 	if (In3270) {
31032531Sminshall 	    StopScreen(1);
31132531Sminshall 	    In3270 = 0;
31232531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
313*38690Sborman 	    setconnmode(0);
31432531Sminshall 	}
31532531Sminshall     }
31632531Sminshall }
31732531Sminshall 
31832531Sminshall /*
31932531Sminshall  * tn3270_ttype()
32032531Sminshall  *
32132531Sminshall  *	Send a response to a terminal type negotiation.
32232531Sminshall  *
32332531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
32432531Sminshall  */
32532531Sminshall 
32632531Sminshall int
32732531Sminshall tn3270_ttype()
32832531Sminshall {
32932531Sminshall     /*
33032531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
33132531Sminshall      * on the format of our screen, and (in the future) color
33232531Sminshall      * capaiblities.
33332531Sminshall      */
33432531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
33532531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
33632531Sminshall 	Sent3270TerminalType = 1;
33732531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
33832531Sminshall 	    MaxNumberLines = 27;
33932531Sminshall 	    MaxNumberColumns = 132;
34032531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
34132531Sminshall 	} else if (MaxNumberLines >= 43) {
34232531Sminshall 	    MaxNumberLines = 43;
34332531Sminshall 	    MaxNumberColumns = 80;
34432531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
34532531Sminshall 	} else if (MaxNumberLines >= 32) {
34632531Sminshall 	    MaxNumberLines = 32;
34732531Sminshall 	    MaxNumberColumns = 80;
34832531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
34932531Sminshall 	} else {
35032531Sminshall 	    MaxNumberLines = 24;
35132531Sminshall 	    MaxNumberColumns = 80;
35232531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
35332531Sminshall 	}
35432531Sminshall 	NumberLines = 24;		/* before we start out... */
35532531Sminshall 	NumberColumns = 80;
35632531Sminshall 	ScreenSize = NumberLines*NumberColumns;
35732531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
35832531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
35932531Sminshall 								1);
36032531Sminshall 	    /*NOTREACHED*/
36132531Sminshall 	}
362*38690Sborman 	printsub('>', sb_terminal+2, sizeof sb_terminal-2);
36332531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
36432531Sminshall 	return 1;
36532531Sminshall     } else {
36632531Sminshall 	return 0;
36732531Sminshall     }
36832531Sminshall }
36933801Sminshall 
37033801Sminshall #if	defined(unix)
37133801Sminshall settranscom(argc, argv)
37233801Sminshall 	int argc;
37333801Sminshall 	char *argv[];
37433801Sminshall {
37535417Sminshall 	int i;
37633801Sminshall 
37733801Sminshall 	if (argc == 1 && transcom) {
37833801Sminshall 	   transcom = 0;
37933801Sminshall 	}
38033801Sminshall 	if (argc == 1) {
38133801Sminshall 	   return;
38233801Sminshall 	}
38333801Sminshall 	transcom = tline;
38433801Sminshall 	(void) strcpy(transcom, argv[1]);
38533801Sminshall 	for (i = 2; i < argc; ++i) {
38633801Sminshall 	    (void) strcat(transcom, " ");
38733801Sminshall 	    (void) strcat(transcom, argv[i]);
38833801Sminshall 	}
38933801Sminshall }
39033801Sminshall #endif	/* defined(unix) */
39133801Sminshall 
39232185Sminshall #endif	/* defined(TN3270) */
393