xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 69785)
133686Sbostic /*
262313Sbostic  * Copyright (c) 1988, 1993
362313Sbostic  *	The Regents of the University of California.  All rights reserved.
433686Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633686Sbostic  */
733686Sbostic 
833686Sbostic #ifndef lint
9*69785Sdab static char sccsid[] = "@(#)tn3270.c	8.2 (Berkeley) 05/30/95";
1033686Sbostic #endif /* not lint */
1133686Sbostic 
1233801Sminshall #include <sys/types.h>
1333801Sminshall #include <arpa/telnet.h>
1433801Sminshall 
1534305Sminshall #include "general.h"
1634305Sminshall 
1733801Sminshall #include "defines.h"
1833801Sminshall #include "ring.h"
1933801Sminshall #include "externs.h"
2032657Sminshall #include "fdset.h"
2132657Sminshall 
2232185Sminshall #if	defined(TN3270)
2332185Sminshall 
2433801Sminshall #include "../ctlr/screen.h"
2533801Sminshall #include "../general/globals.h"
2632185Sminshall 
2759892Sbostic #include "../sys_curses/telextrn.h"
2835417Sminshall #include "../ctlr/externs.h"
2935417Sminshall 
3033801Sminshall #if	defined(unix)
3136240Sminshall int
3236240Sminshall 	HaveInput,		/* There is input available to scan */
3338208Sminshall 	cursesdata,		/* Do we dump curses data? */
3436240Sminshall 	sigiocount;		/* Number of times we got a SIGIO */
3536240Sminshall 
3633801Sminshall char	tline[200];
3733801Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
3833801Sminshall #endif	/* defined(unix) */
3932531Sminshall 
4033801Sminshall char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
4132531Sminshall 
4232531Sminshall static char	sb_terminal[] = { IAC, SB,
4332531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
4432531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
4532531Sminshall 			IAC, SE };
4632531Sminshall #define	SBTERMMODEL	13
4732531Sminshall 
4832531Sminshall static int
4932531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
5032531Sminshall 
5133801Sminshall #endif	/* defined(TN3270) */
5232531Sminshall 
5333801Sminshall 
5446808Sdab     void
5534303Sminshall init_3270()
5632551Sminshall {
5733801Sminshall #if	defined(TN3270)
5836240Sminshall #if	defined(unix)
5936240Sminshall     HaveInput = 0;
6036240Sminshall     sigiocount = 0;
6136240Sminshall #endif	/* defined(unix) */
6233801Sminshall     Sent3270TerminalType = 0;
6333801Sminshall     Ifrontp = Ibackp = Ibuf;
6433801Sminshall     init_ctlr();		/* Initialize some things */
6533801Sminshall     init_keyboard();
6633801Sminshall     init_screen();
6733801Sminshall     init_system();
6833801Sminshall #endif	/* defined(TN3270) */
6932551Sminshall }
7032551Sminshall 
7133801Sminshall 
7233801Sminshall #if	defined(TN3270)
7333801Sminshall 
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 
8346808Sdab     int
8432185Sminshall DataToNetwork(buffer, count, done)
8546808Sdab     register char *buffer;	/* where the data is */
8646808Sdab     register int  count;	/* how much to send */
8746808Sdab     int		  done;		/* is this the last of a logical block */
8832185Sminshall {
8933801Sminshall     register int loop, c;
9032185Sminshall     int origCount;
9132185Sminshall 
9232185Sminshall     origCount = count;
9332185Sminshall 
9432185Sminshall     while (count) {
9534303Sminshall 	/* If not enough room for EORs, IACs, etc., wait */
9633801Sminshall 	if (NETROOM() < 6) {
9733801Sminshall 	    fd_set o;
9833801Sminshall 
9933801Sminshall 	    FD_ZERO(&o);
10032185Sminshall 	    netflush();
10133801Sminshall 	    while (NETROOM() < 6) {
10232185Sminshall 		FD_SET(net, &o);
10332185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
10432185Sminshall 						(struct timeval *) 0);
10532185Sminshall 		netflush();
10632185Sminshall 	    }
10732185Sminshall 	}
10834303Sminshall 	c = ring_empty_count(&netoring);
10934303Sminshall 	if (c > count) {
11034303Sminshall 	    c = count;
11134303Sminshall 	}
11234303Sminshall 	loop = c;
11333801Sminshall 	while (loop) {
11434311Sminshall 	    if (((unsigned char)*buffer) == IAC) {
11533801Sminshall 		break;
11633801Sminshall 	    }
11733801Sminshall 	    buffer++;
11833801Sminshall 	    loop--;
11932185Sminshall 	}
12033801Sminshall 	if ((c = c-loop)) {
12133801Sminshall 	    ring_supply_data(&netoring, buffer-c, c);
12233801Sminshall 	    count -= c;
12333801Sminshall 	}
12433801Sminshall 	if (loop) {
12533801Sminshall 	    NET2ADD(IAC, IAC);
12633801Sminshall 	    count--;
12734303Sminshall 	    buffer++;
12833801Sminshall 	}
12932185Sminshall     }
13032185Sminshall 
13133801Sminshall     if (done) {
13234303Sminshall 	NET2ADD(IAC, EOR);
13332185Sminshall 	netflush();		/* try to move along as quickly as ... */
13432185Sminshall     }
13532185Sminshall     return(origCount - count);
13632185Sminshall }
13732185Sminshall 
13832185Sminshall 
13932185Sminshall #if	defined(unix)
14046808Sdab     void
14159893Sbostic inputAvailable(signo)
14259893Sbostic 	int signo;
14332185Sminshall {
14432185Sminshall     HaveInput = 1;
14536240Sminshall     sigiocount++;
14632185Sminshall }
14732185Sminshall #endif	/* defined(unix) */
14832185Sminshall 
14946808Sdab     void
15032185Sminshall outputPurge()
15132185Sminshall {
15244360Sborman     (void) ttyflush(1);
15332185Sminshall }
15432185Sminshall 
15532185Sminshall 
15632185Sminshall /*
15732185Sminshall  * The following routines are places where the various tn3270
15832185Sminshall  * routines make calls into telnet.c.
15932185Sminshall  */
16032185Sminshall 
16134303Sminshall /*
16234303Sminshall  * DataToTerminal - queue up some data to go to terminal.
16334303Sminshall  *
16434303Sminshall  * Note: there are people who call us and depend on our processing
16534303Sminshall  * *all* the data at one time (thus the select).
16634303Sminshall  */
16732185Sminshall 
16846808Sdab     int
16932185Sminshall DataToTerminal(buffer, count)
17046808Sdab     register char	*buffer;		/* where the data is */
17146808Sdab     register int	count;			/* how much to send */
17232185Sminshall {
17335417Sminshall     register int c;
17432185Sminshall     int origCount;
17532185Sminshall 
17632185Sminshall     origCount = count;
17732185Sminshall 
17832185Sminshall     while (count) {
17933801Sminshall 	if (TTYROOM() == 0) {
18032185Sminshall #if	defined(unix)
18133801Sminshall 	    fd_set o;
18233801Sminshall 
18333801Sminshall 	    FD_ZERO(&o);
18433801Sminshall #endif	/* defined(unix) */
18544360Sborman 	    (void) ttyflush(0);
18633801Sminshall 	    while (TTYROOM() == 0) {
18733801Sminshall #if	defined(unix)
18832185Sminshall 		FD_SET(tout, &o);
18932185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
19032185Sminshall 						(struct timeval *) 0);
19132185Sminshall #endif	/* defined(unix) */
19244360Sborman 		(void) ttyflush(0);
19332185Sminshall 	    }
19432185Sminshall 	}
19534303Sminshall 	c = TTYROOM();
19634303Sminshall 	if (c > count) {
19734303Sminshall 	    c = count;
19833801Sminshall 	}
19934303Sminshall 	ring_supply_data(&ttyoring, buffer, c);
20034303Sminshall 	count -= c;
20134303Sminshall 	buffer += c;
20232185Sminshall     }
20334303Sminshall     return(origCount);
20432185Sminshall }
20532185Sminshall 
20632185Sminshall 
20732185Sminshall /*
20832185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
20932185Sminshall  */
21032185Sminshall 
21146808Sdab     int
21232185Sminshall Push3270()
21332185Sminshall {
21433801Sminshall     int save = ring_full_count(&netiring);
21532185Sminshall 
21633801Sminshall     if (save) {
21733801Sminshall 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
21832185Sminshall 	    if (Ibackp != Ibuf) {
219*69785Sdab 		memmove(Ibuf, Ibackp, Ifrontp-Ibackp);
22032185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
22132185Sminshall 		Ibackp = Ibuf;
22232185Sminshall 	    }
22332185Sminshall 	}
22433801Sminshall 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
22544360Sborman 	    (void)telrcv();
22632185Sminshall 	}
22732185Sminshall     }
22833801Sminshall     return save != ring_full_count(&netiring);
22932185Sminshall }
23032185Sminshall 
23132185Sminshall 
23232185Sminshall /*
23332185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
23432185Sminshall  *		before quitting.
23532185Sminshall  */
23632185Sminshall 
23746808Sdab     void
23832185Sminshall Finish3270()
23932185Sminshall {
24032185Sminshall     while (Push3270() || !DoTerminalOutput()) {
24132185Sminshall #if	defined(unix)
24232185Sminshall 	HaveInput = 0;
24332185Sminshall #endif	/* defined(unix) */
24432185Sminshall 	;
24532185Sminshall     }
24632185Sminshall }
24732185Sminshall 
24832185Sminshall 
24932185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
25032185Sminshall 
25146808Sdab     void
25232185Sminshall StringToTerminal(s)
25346808Sdab     char *s;
25432185Sminshall {
25532185Sminshall     int count;
25632185Sminshall 
25732185Sminshall     count = strlen(s);
25832185Sminshall     if (count) {
25932185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
26032185Sminshall     }
26132185Sminshall }
26232185Sminshall 
26332185Sminshall 
26432185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
26532185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
26632185Sminshall  *	curses(3x) can call us to send out data.
26732185Sminshall  */
26832185Sminshall 
26946808Sdab     void
27032185Sminshall _putchar(c)
27146808Sdab     char c;
27232185Sminshall {
27336201Sminshall #if	defined(sun)		/* SunOS 4.0 bug */
27436201Sminshall     c &= 0x7f;
27536201Sminshall #endif	/* defined(sun) */
27638208Sminshall     if (cursesdata) {
27738208Sminshall 	Dump('>', &c, 1);
27838208Sminshall     }
27936240Sminshall     if (!TTYROOM()) {
28032185Sminshall 	(void) DataToTerminal(&c, 1);
28132185Sminshall     } else {
28233801Sminshall 	TTYADD(c);
28332185Sminshall     }
28432185Sminshall }
28532185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
28632185Sminshall 
28746808Sdab     void
28832531Sminshall SetIn3270()
28932531Sminshall {
29038690Sborman     if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
29138690Sborman 		&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
29232531Sminshall 	if (!In3270) {
29332531Sminshall 	    In3270 = 1;
29432531Sminshall 	    Init3270();		/* Initialize 3270 functions */
29532531Sminshall 	    /* initialize terminal key mapping */
29632531Sminshall 	    InitTerminal();	/* Start terminal going */
29738690Sborman 	    setconnmode(0);
29832531Sminshall 	}
29932531Sminshall     } else {
30032531Sminshall 	if (In3270) {
30132531Sminshall 	    StopScreen(1);
30232531Sminshall 	    In3270 = 0;
30332531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
30438690Sborman 	    setconnmode(0);
30532531Sminshall 	}
30632531Sminshall     }
30732531Sminshall }
30832531Sminshall 
30932531Sminshall /*
31032531Sminshall  * tn3270_ttype()
31132531Sminshall  *
31232531Sminshall  *	Send a response to a terminal type negotiation.
31332531Sminshall  *
31432531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
31532531Sminshall  */
31632531Sminshall 
31746808Sdab     int
31832531Sminshall tn3270_ttype()
31932531Sminshall {
32032531Sminshall     /*
32132531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
32232531Sminshall      * on the format of our screen, and (in the future) color
32332531Sminshall      * capaiblities.
32432531Sminshall      */
32532531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
32632531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
32732531Sminshall 	Sent3270TerminalType = 1;
32832531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
32932531Sminshall 	    MaxNumberLines = 27;
33032531Sminshall 	    MaxNumberColumns = 132;
33132531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
33232531Sminshall 	} else if (MaxNumberLines >= 43) {
33332531Sminshall 	    MaxNumberLines = 43;
33432531Sminshall 	    MaxNumberColumns = 80;
33532531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
33632531Sminshall 	} else if (MaxNumberLines >= 32) {
33732531Sminshall 	    MaxNumberLines = 32;
33832531Sminshall 	    MaxNumberColumns = 80;
33932531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
34032531Sminshall 	} else {
34132531Sminshall 	    MaxNumberLines = 24;
34232531Sminshall 	    MaxNumberColumns = 80;
34332531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
34432531Sminshall 	}
34532531Sminshall 	NumberLines = 24;		/* before we start out... */
34632531Sminshall 	NumberColumns = 80;
34732531Sminshall 	ScreenSize = NumberLines*NumberColumns;
34832531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
34932531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
35032531Sminshall 								1);
35132531Sminshall 	    /*NOTREACHED*/
35232531Sminshall 	}
35338690Sborman 	printsub('>', sb_terminal+2, sizeof sb_terminal-2);
35432531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
35532531Sminshall 	return 1;
35632531Sminshall     } else {
35732531Sminshall 	return 0;
35832531Sminshall     }
35932531Sminshall }
36033801Sminshall 
36133801Sminshall #if	defined(unix)
36260179Sbostic 	int
36333801Sminshall settranscom(argc, argv)
36433801Sminshall 	int argc;
36533801Sminshall 	char *argv[];
36633801Sminshall {
36735417Sminshall 	int i;
36833801Sminshall 
36933801Sminshall 	if (argc == 1 && transcom) {
37033801Sminshall 	   transcom = 0;
37133801Sminshall 	}
37233801Sminshall 	if (argc == 1) {
37360179Sbostic 	   return 1;
37433801Sminshall 	}
37533801Sminshall 	transcom = tline;
37633801Sminshall 	(void) strcpy(transcom, argv[1]);
37733801Sminshall 	for (i = 2; i < argc; ++i) {
37833801Sminshall 	    (void) strcat(transcom, " ");
37933801Sminshall 	    (void) strcat(transcom, argv[i]);
38033801Sminshall 	}
38160179Sbostic 	return 1;
38233801Sminshall }
38333801Sminshall #endif	/* defined(unix) */
38433801Sminshall 
38532185Sminshall #endif	/* defined(TN3270) */
386