xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 32657)
1*32657Sminshall #include "fdset.h"
2*32657Sminshall 
332185Sminshall void
432185Sminshall tn3270_init()
532185Sminshall {
632185Sminshall #if	defined(TN3270)
732185Sminshall     Sent3270TerminalType = 0;
832185Sminshall     Ifrontp = Ibackp = Ibuf;
932185Sminshall     init_ctlr();		/* Initialize some things */
1032185Sminshall     init_keyboard();
1132185Sminshall     init_screen();
1232185Sminshall     init_system();
1332185Sminshall #endif	/* defined(TN3270) */
1432185Sminshall }
1532185Sminshall 
1632185Sminshall #if	defined(TN3270)
1732185Sminshall 
1832531Sminshall 
1932531Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
2032531Sminshall 
2132531Sminshall static char	sb_terminal[] = { IAC, SB,
2232531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
2332531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
2432531Sminshall 			IAC, SE };
2532531Sminshall #define	SBTERMMODEL	13
2632531Sminshall 
2732531Sminshall static int
2832531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
2932531Sminshall 
3032531Sminshall 
3132551Sminshall #if	defined(unix)
3232551Sminshall static
3332551Sminshall settranscom(argc, argv)
3432551Sminshall 	int argc;
3532551Sminshall 	char *argv[];
3632551Sminshall {
3732551Sminshall 	int i, len = 0;
3832551Sminshall 	char *strcpy(), *strcat();
3932551Sminshall 
4032551Sminshall 	if (argc == 1 && transcom) {
4132551Sminshall 	   transcom = 0;
4232551Sminshall 	}
4332551Sminshall 	if (argc == 1) {
4432551Sminshall 	   return;
4532551Sminshall 	}
4632551Sminshall 	for (i = 1; i < argc; ++i) {
4732551Sminshall 	    len += 1 + strlen(argv[1]);
4832551Sminshall 	}
4932551Sminshall 	transcom = tline;
5032551Sminshall 	(void) strcpy(transcom, argv[1]);
5132551Sminshall 	for (i = 2; i < argc; ++i) {
5232551Sminshall 	    (void) strcat(transcom, " ");
5332551Sminshall 	    (void) strcat(transcom, argv[i]);
5432551Sminshall 	}
5532551Sminshall }
5632551Sminshall #endif	/* defined(unix) */
5732551Sminshall 
5832185Sminshall /*
5932185Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
6032185Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
6132185Sminshall  * don't call us with "done" until you want that done...)
6232185Sminshall  *
6332185Sminshall  * We actually do send all the data to the network buffer, since our
6432185Sminshall  * only client needs for us to do that.
6532185Sminshall  */
6632185Sminshall 
6732185Sminshall int
6832185Sminshall DataToNetwork(buffer, count, done)
6932185Sminshall register char	*buffer;	/* where the data is */
7032185Sminshall register int	count;		/* how much to send */
7132185Sminshall int		done;		/* is this the last of a logical block */
7232185Sminshall {
7332185Sminshall     register int c;
7432185Sminshall     int origCount;
7532185Sminshall     fd_set o;
7632185Sminshall 
7732185Sminshall     origCount = count;
7832185Sminshall     FD_ZERO(&o);
7932185Sminshall 
8032185Sminshall     while (count) {
8132185Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
8232185Sminshall 	    netflush();
8332185Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
8432185Sminshall 		FD_SET(net, &o);
8532185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
8632185Sminshall 						(struct timeval *) 0);
8732185Sminshall 		netflush();
8832185Sminshall 	    }
8932185Sminshall 	}
9032185Sminshall 	c = *buffer++;
9132185Sminshall 	count--;
9232185Sminshall 	if (c == IAC) {
9332185Sminshall 	    *nfrontp++ = IAC;
9432185Sminshall 	    *nfrontp++ = IAC;
9532185Sminshall 	} else {
9632185Sminshall 	    *nfrontp++ = c;
9732185Sminshall 	}
9832185Sminshall     }
9932185Sminshall 
10032185Sminshall     if (done && !count) {
10132185Sminshall 	*nfrontp++ = IAC;
10232185Sminshall 	*nfrontp++ = EOR;
10332185Sminshall 	netflush();		/* try to move along as quickly as ... */
10432185Sminshall     }
10532185Sminshall     return(origCount - count);
10632185Sminshall }
10732185Sminshall 
10832185Sminshall 
10932185Sminshall #if	defined(unix)
11032185Sminshall static void
11132185Sminshall inputAvailable()
11232185Sminshall {
11332185Sminshall     HaveInput = 1;
11432185Sminshall }
11532185Sminshall #endif	/* defined(unix) */
11632185Sminshall 
11732185Sminshall void
11832185Sminshall outputPurge()
11932185Sminshall {
12032257Sminshall     ttyflush(1);
12132185Sminshall }
12232185Sminshall 
12332185Sminshall 
12432185Sminshall /*
12532185Sminshall  * The following routines are places where the various tn3270
12632185Sminshall  * routines make calls into telnet.c.
12732185Sminshall  */
12832185Sminshall 
12932185Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
13032185Sminshall TtyChars()
13132185Sminshall {
13232185Sminshall     return(tfrontp-tbackp);
13332185Sminshall }
13432185Sminshall 
13532185Sminshall /* DataToTerminal - queue up some data to go to terminal. */
13632185Sminshall 
13732185Sminshall int
13832185Sminshall DataToTerminal(buffer, count)
13932185Sminshall register char	*buffer;		/* where the data is */
14032185Sminshall register int	count;			/* how much to send */
14132185Sminshall {
14232185Sminshall     int origCount;
14332185Sminshall #if	defined(unix)
14432185Sminshall     fd_set	o;
14532185Sminshall 
14632185Sminshall     FD_ZERO(&o);
14732185Sminshall #endif	/* defined(unix) */
14832185Sminshall     origCount = count;
14932185Sminshall 
15032185Sminshall     while (count) {
15132185Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
15232257Sminshall 	    ttyflush(0);
15332185Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
15432185Sminshall #if	defined(unix)
15532185Sminshall 		FD_SET(tout, &o);
15632185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
15732185Sminshall 						(struct timeval *) 0);
15832185Sminshall #endif	/* defined(unix) */
15932257Sminshall 		ttyflush(0);
16032185Sminshall 	    }
16132185Sminshall 	}
16232185Sminshall 	*tfrontp++ = *buffer++;
16332185Sminshall 	count--;
16432185Sminshall     }
16532185Sminshall     return(origCount - count);
16632185Sminshall }
16732185Sminshall 
16832185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
16932185Sminshall  *			Note that we consider the buffer to run all the
17032185Sminshall  *			way to the kernel (thus the select).
17132185Sminshall  */
17232185Sminshall 
17332185Sminshall void
17432185Sminshall EmptyTerminal()
17532185Sminshall {
17632185Sminshall #if	defined(unix)
17732185Sminshall     fd_set	o;
17832185Sminshall 
17932185Sminshall     FD_ZERO(&o);
18032185Sminshall #endif	/* defined(unix) */
18132185Sminshall 
18232185Sminshall     if (tfrontp == tbackp) {
18332185Sminshall #if	defined(unix)
18432185Sminshall 	FD_SET(tout, &o);
18532185Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
18632185Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
18732185Sminshall #endif	/* defined(unix) */
18832185Sminshall     } else {
18932185Sminshall 	while (tfrontp != tbackp) {
19032257Sminshall 	    ttyflush(0);
19132185Sminshall #if	defined(unix)
19232185Sminshall 	    FD_SET(tout, &o);
19332185Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
19432185Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
19532185Sminshall #endif	/* defined(unix) */
19632185Sminshall 	}
19732185Sminshall     }
19832185Sminshall }
19932185Sminshall 
20032185Sminshall 
20132185Sminshall /*
20232185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
20332185Sminshall  */
20432185Sminshall 
20532185Sminshall static int
20632185Sminshall Push3270()
20732185Sminshall {
20832185Sminshall     int save = scc;
20932185Sminshall 
21032185Sminshall     if (scc) {
21132185Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
21232185Sminshall 	    if (Ibackp != Ibuf) {
21332185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
21432185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
21532185Sminshall 		Ibackp = Ibuf;
21632185Sminshall 	    }
21732185Sminshall 	}
21832185Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
21932185Sminshall 	    telrcv();
22032185Sminshall 	}
22132185Sminshall     }
22232185Sminshall     return save != scc;
22332185Sminshall }
22432185Sminshall 
22532185Sminshall 
22632185Sminshall /*
22732185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
22832185Sminshall  *		before quitting.
22932185Sminshall  */
23032185Sminshall 
23132185Sminshall static void
23232185Sminshall Finish3270()
23332185Sminshall {
23432185Sminshall     while (Push3270() || !DoTerminalOutput()) {
23532185Sminshall #if	defined(unix)
23632185Sminshall 	HaveInput = 0;
23732185Sminshall #endif	/* defined(unix) */
23832185Sminshall 	;
23932185Sminshall     }
24032185Sminshall }
24132185Sminshall 
24232185Sminshall 
24332185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
24432185Sminshall 
24532185Sminshall void
24632185Sminshall StringToTerminal(s)
24732185Sminshall char *s;
24832185Sminshall {
24932185Sminshall     int count;
25032185Sminshall 
25132185Sminshall     count = strlen(s);
25232185Sminshall     if (count) {
25332185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
25432185Sminshall     }
25532185Sminshall }
25632185Sminshall 
25732185Sminshall 
25832185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
25932185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
26032185Sminshall  *	curses(3x) can call us to send out data.
26132185Sminshall  */
26232185Sminshall 
26332185Sminshall void
26432185Sminshall _putchar(c)
26532185Sminshall char c;
26632185Sminshall {
26732185Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
26832185Sminshall 	(void) DataToTerminal(&c, 1);
26932185Sminshall     } else {
27032185Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
27132185Sminshall     }
27232185Sminshall }
27332185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
27432185Sminshall 
27532531Sminshall void
27632531Sminshall SetForExit()
27732531Sminshall {
27832531Sminshall     setconnmode();
27932531Sminshall     if (In3270) {
28032531Sminshall 	Finish3270();
28132531Sminshall     }
28232531Sminshall     setcommandmode();
28332531Sminshall     fflush(stdout);
28432531Sminshall     fflush(stderr);
28532531Sminshall     if (In3270) {
28632531Sminshall 	StopScreen(1);
28732531Sminshall     }
28832531Sminshall     setconnmode();
28932531Sminshall     setcommandmode();
29032531Sminshall }
29132531Sminshall 
29232531Sminshall void
29332531Sminshall Exit(returnCode)
29432531Sminshall int returnCode;
29532531Sminshall {
29632531Sminshall     SetForExit();
29732531Sminshall     exit(returnCode);
29832531Sminshall }
29932531Sminshall 
30032531Sminshall void
30132531Sminshall ExitString(string, returnCode)
30232531Sminshall char *string;
30332531Sminshall int returnCode;
30432531Sminshall {
30532531Sminshall     SetForExit();
30632531Sminshall     fwrite(string, 1, strlen(string), stderr);
30732531Sminshall     exit(returnCode);
30832531Sminshall }
30932531Sminshall 
31032531Sminshall void
31132531Sminshall ExitPerror(string, returnCode)
31232531Sminshall char *string;
31332531Sminshall int returnCode;
31432531Sminshall {
31532531Sminshall     SetForExit();
31632531Sminshall     perror(string);
31732531Sminshall     exit(returnCode);
31832531Sminshall }
31932531Sminshall 
32032531Sminshall void
32132531Sminshall SetIn3270()
32232531Sminshall {
32332531Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
32432531Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
32532531Sminshall 	if (!In3270) {
32632531Sminshall 	    In3270 = 1;
32732531Sminshall 	    Init3270();		/* Initialize 3270 functions */
32832531Sminshall 	    /* initialize terminal key mapping */
32932531Sminshall 	    InitTerminal();	/* Start terminal going */
33032531Sminshall 	    setconnmode();
33132531Sminshall 	}
33232531Sminshall     } else {
33332531Sminshall 	if (In3270) {
33432531Sminshall 	    StopScreen(1);
33532531Sminshall 	    In3270 = 0;
33632531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
33732531Sminshall 	    setconnmode();
33832531Sminshall 	}
33932531Sminshall     }
34032531Sminshall }
34132531Sminshall 
34232531Sminshall /*
34332531Sminshall  * tn3270_ttype()
34432531Sminshall  *
34532531Sminshall  *	Send a response to a terminal type negotiation.
34632531Sminshall  *
34732531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
34832531Sminshall  */
34932531Sminshall 
35032531Sminshall int
35132531Sminshall tn3270_ttype()
35232531Sminshall {
35332531Sminshall     /*
35432531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
35532531Sminshall      * on the format of our screen, and (in the future) color
35632531Sminshall      * capaiblities.
35732531Sminshall      */
35832531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
35932531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
36032531Sminshall 	Sent3270TerminalType = 1;
36132531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
36232531Sminshall 	    MaxNumberLines = 27;
36332531Sminshall 	    MaxNumberColumns = 132;
36432531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
36532531Sminshall 	} else if (MaxNumberLines >= 43) {
36632531Sminshall 	    MaxNumberLines = 43;
36732531Sminshall 	    MaxNumberColumns = 80;
36832531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
36932531Sminshall 	} else if (MaxNumberLines >= 32) {
37032531Sminshall 	    MaxNumberLines = 32;
37132531Sminshall 	    MaxNumberColumns = 80;
37232531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
37332531Sminshall 	} else {
37432531Sminshall 	    MaxNumberLines = 24;
37532531Sminshall 	    MaxNumberColumns = 80;
37632531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
37732531Sminshall 	}
37832531Sminshall 	NumberLines = 24;		/* before we start out... */
37932531Sminshall 	NumberColumns = 80;
38032531Sminshall 	ScreenSize = NumberLines*NumberColumns;
38132531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
38232531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
38332531Sminshall 								1);
38432531Sminshall 	    /*NOTREACHED*/
38532531Sminshall 	}
38632531Sminshall 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
38732531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
38832531Sminshall 	return 1;
38932531Sminshall     } else {
39032531Sminshall 	return 0;
39132531Sminshall     }
39232531Sminshall }
39332185Sminshall #endif	/* defined(TN3270) */
394