xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 32531)
132185Sminshall void
232185Sminshall tn3270_init()
332185Sminshall {
432185Sminshall #if	defined(TN3270)
532185Sminshall     Sent3270TerminalType = 0;
632185Sminshall     Ifrontp = Ibackp = Ibuf;
732185Sminshall     init_ctlr();		/* Initialize some things */
832185Sminshall     init_keyboard();
932185Sminshall     init_screen();
1032185Sminshall     init_system();
1132185Sminshall #endif	/* defined(TN3270) */
1232185Sminshall }
1332185Sminshall 
1432185Sminshall #if	defined(TN3270)
1532185Sminshall 
16*32531Sminshall 
17*32531Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
18*32531Sminshall 
19*32531Sminshall static char	sb_terminal[] = { IAC, SB,
20*32531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
21*32531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
22*32531Sminshall 			IAC, SE };
23*32531Sminshall #define	SBTERMMODEL	13
24*32531Sminshall 
25*32531Sminshall static int
26*32531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
27*32531Sminshall 
28*32531Sminshall 
2932185Sminshall /*
3032185Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
3132185Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
3232185Sminshall  * don't call us with "done" until you want that done...)
3332185Sminshall  *
3432185Sminshall  * We actually do send all the data to the network buffer, since our
3532185Sminshall  * only client needs for us to do that.
3632185Sminshall  */
3732185Sminshall 
3832185Sminshall int
3932185Sminshall DataToNetwork(buffer, count, done)
4032185Sminshall register char	*buffer;	/* where the data is */
4132185Sminshall register int	count;		/* how much to send */
4232185Sminshall int		done;		/* is this the last of a logical block */
4332185Sminshall {
4432185Sminshall     register int c;
4532185Sminshall     int origCount;
4632185Sminshall     fd_set o;
4732185Sminshall 
4832185Sminshall     origCount = count;
4932185Sminshall     FD_ZERO(&o);
5032185Sminshall 
5132185Sminshall     while (count) {
5232185Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
5332185Sminshall 	    netflush();
5432185Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
5532185Sminshall 		FD_SET(net, &o);
5632185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
5732185Sminshall 						(struct timeval *) 0);
5832185Sminshall 		netflush();
5932185Sminshall 	    }
6032185Sminshall 	}
6132185Sminshall 	c = *buffer++;
6232185Sminshall 	count--;
6332185Sminshall 	if (c == IAC) {
6432185Sminshall 	    *nfrontp++ = IAC;
6532185Sminshall 	    *nfrontp++ = IAC;
6632185Sminshall 	} else {
6732185Sminshall 	    *nfrontp++ = c;
6832185Sminshall 	}
6932185Sminshall     }
7032185Sminshall 
7132185Sminshall     if (done && !count) {
7232185Sminshall 	*nfrontp++ = IAC;
7332185Sminshall 	*nfrontp++ = EOR;
7432185Sminshall 	netflush();		/* try to move along as quickly as ... */
7532185Sminshall     }
7632185Sminshall     return(origCount - count);
7732185Sminshall }
7832185Sminshall 
7932185Sminshall 
8032185Sminshall #if	defined(unix)
8132185Sminshall static void
8232185Sminshall inputAvailable()
8332185Sminshall {
8432185Sminshall     HaveInput = 1;
8532185Sminshall }
8632185Sminshall #endif	/* defined(unix) */
8732185Sminshall 
8832185Sminshall void
8932185Sminshall outputPurge()
9032185Sminshall {
9132257Sminshall     ttyflush(1);
9232185Sminshall }
9332185Sminshall 
9432185Sminshall 
9532185Sminshall /*
9632185Sminshall  * The following routines are places where the various tn3270
9732185Sminshall  * routines make calls into telnet.c.
9832185Sminshall  */
9932185Sminshall 
10032185Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
10132185Sminshall TtyChars()
10232185Sminshall {
10332185Sminshall     return(tfrontp-tbackp);
10432185Sminshall }
10532185Sminshall 
10632185Sminshall /* DataToTerminal - queue up some data to go to terminal. */
10732185Sminshall 
10832185Sminshall int
10932185Sminshall DataToTerminal(buffer, count)
11032185Sminshall register char	*buffer;		/* where the data is */
11132185Sminshall register int	count;			/* how much to send */
11232185Sminshall {
11332185Sminshall     int origCount;
11432185Sminshall #if	defined(unix)
11532185Sminshall     fd_set	o;
11632185Sminshall 
11732185Sminshall     FD_ZERO(&o);
11832185Sminshall #endif	/* defined(unix) */
11932185Sminshall     origCount = count;
12032185Sminshall 
12132185Sminshall     while (count) {
12232185Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
12332257Sminshall 	    ttyflush(0);
12432185Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
12532185Sminshall #if	defined(unix)
12632185Sminshall 		FD_SET(tout, &o);
12732185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
12832185Sminshall 						(struct timeval *) 0);
12932185Sminshall #endif	/* defined(unix) */
13032257Sminshall 		ttyflush(0);
13132185Sminshall 	    }
13232185Sminshall 	}
13332185Sminshall 	*tfrontp++ = *buffer++;
13432185Sminshall 	count--;
13532185Sminshall     }
13632185Sminshall     return(origCount - count);
13732185Sminshall }
13832185Sminshall 
13932185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
14032185Sminshall  *			Note that we consider the buffer to run all the
14132185Sminshall  *			way to the kernel (thus the select).
14232185Sminshall  */
14332185Sminshall 
14432185Sminshall void
14532185Sminshall EmptyTerminal()
14632185Sminshall {
14732185Sminshall #if	defined(unix)
14832185Sminshall     fd_set	o;
14932185Sminshall 
15032185Sminshall     FD_ZERO(&o);
15132185Sminshall #endif	/* defined(unix) */
15232185Sminshall 
15332185Sminshall     if (tfrontp == tbackp) {
15432185Sminshall #if	defined(unix)
15532185Sminshall 	FD_SET(tout, &o);
15632185Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
15732185Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
15832185Sminshall #endif	/* defined(unix) */
15932185Sminshall     } else {
16032185Sminshall 	while (tfrontp != tbackp) {
16132257Sminshall 	    ttyflush(0);
16232185Sminshall #if	defined(unix)
16332185Sminshall 	    FD_SET(tout, &o);
16432185Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
16532185Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
16632185Sminshall #endif	/* defined(unix) */
16732185Sminshall 	}
16832185Sminshall     }
16932185Sminshall }
17032185Sminshall 
17132185Sminshall 
17232185Sminshall /*
17332185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
17432185Sminshall  */
17532185Sminshall 
17632185Sminshall static int
17732185Sminshall Push3270()
17832185Sminshall {
17932185Sminshall     int save = scc;
18032185Sminshall 
18132185Sminshall     if (scc) {
18232185Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
18332185Sminshall 	    if (Ibackp != Ibuf) {
18432185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
18532185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
18632185Sminshall 		Ibackp = Ibuf;
18732185Sminshall 	    }
18832185Sminshall 	}
18932185Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
19032185Sminshall 	    telrcv();
19132185Sminshall 	}
19232185Sminshall     }
19332185Sminshall     return save != scc;
19432185Sminshall }
19532185Sminshall 
19632185Sminshall 
19732185Sminshall /*
19832185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
19932185Sminshall  *		before quitting.
20032185Sminshall  */
20132185Sminshall 
20232185Sminshall static void
20332185Sminshall Finish3270()
20432185Sminshall {
20532185Sminshall     while (Push3270() || !DoTerminalOutput()) {
20632185Sminshall #if	defined(unix)
20732185Sminshall 	HaveInput = 0;
20832185Sminshall #endif	/* defined(unix) */
20932185Sminshall 	;
21032185Sminshall     }
21132185Sminshall }
21232185Sminshall 
21332185Sminshall 
21432185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
21532185Sminshall 
21632185Sminshall void
21732185Sminshall StringToTerminal(s)
21832185Sminshall char *s;
21932185Sminshall {
22032185Sminshall     int count;
22132185Sminshall 
22232185Sminshall     count = strlen(s);
22332185Sminshall     if (count) {
22432185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
22532185Sminshall     }
22632185Sminshall }
22732185Sminshall 
22832185Sminshall 
22932185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
23032185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
23132185Sminshall  *	curses(3x) can call us to send out data.
23232185Sminshall  */
23332185Sminshall 
23432185Sminshall void
23532185Sminshall _putchar(c)
23632185Sminshall char c;
23732185Sminshall {
23832185Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
23932185Sminshall 	(void) DataToTerminal(&c, 1);
24032185Sminshall     } else {
24132185Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
24232185Sminshall     }
24332185Sminshall }
24432185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
24532185Sminshall 
246*32531Sminshall void
247*32531Sminshall SetForExit()
248*32531Sminshall {
249*32531Sminshall     setconnmode();
250*32531Sminshall     if (In3270) {
251*32531Sminshall 	Finish3270();
252*32531Sminshall     }
253*32531Sminshall     setcommandmode();
254*32531Sminshall     fflush(stdout);
255*32531Sminshall     fflush(stderr);
256*32531Sminshall     if (In3270) {
257*32531Sminshall 	StopScreen(1);
258*32531Sminshall     }
259*32531Sminshall     setconnmode();
260*32531Sminshall     setcommandmode();
261*32531Sminshall }
262*32531Sminshall 
263*32531Sminshall void
264*32531Sminshall Exit(returnCode)
265*32531Sminshall int returnCode;
266*32531Sminshall {
267*32531Sminshall     SetForExit();
268*32531Sminshall     exit(returnCode);
269*32531Sminshall }
270*32531Sminshall 
271*32531Sminshall void
272*32531Sminshall ExitString(string, returnCode)
273*32531Sminshall char *string;
274*32531Sminshall int returnCode;
275*32531Sminshall {
276*32531Sminshall     SetForExit();
277*32531Sminshall     fwrite(string, 1, strlen(string), stderr);
278*32531Sminshall     exit(returnCode);
279*32531Sminshall }
280*32531Sminshall 
281*32531Sminshall void
282*32531Sminshall ExitPerror(string, returnCode)
283*32531Sminshall char *string;
284*32531Sminshall int returnCode;
285*32531Sminshall {
286*32531Sminshall     SetForExit();
287*32531Sminshall     perror(string);
288*32531Sminshall     exit(returnCode);
289*32531Sminshall }
290*32531Sminshall 
291*32531Sminshall void
292*32531Sminshall SetIn3270()
293*32531Sminshall {
294*32531Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
295*32531Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
296*32531Sminshall 	if (!In3270) {
297*32531Sminshall 	    In3270 = 1;
298*32531Sminshall 	    Init3270();		/* Initialize 3270 functions */
299*32531Sminshall 	    /* initialize terminal key mapping */
300*32531Sminshall 	    InitTerminal();	/* Start terminal going */
301*32531Sminshall 	    setconnmode();
302*32531Sminshall 	}
303*32531Sminshall     } else {
304*32531Sminshall 	if (In3270) {
305*32531Sminshall 	    StopScreen(1);
306*32531Sminshall 	    In3270 = 0;
307*32531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
308*32531Sminshall 	    setconnmode();
309*32531Sminshall 	}
310*32531Sminshall     }
311*32531Sminshall }
312*32531Sminshall 
313*32531Sminshall /*
314*32531Sminshall  * tn3270_ttype()
315*32531Sminshall  *
316*32531Sminshall  *	Send a response to a terminal type negotiation.
317*32531Sminshall  *
318*32531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
319*32531Sminshall  */
320*32531Sminshall 
321*32531Sminshall int
322*32531Sminshall tn3270_ttype()
323*32531Sminshall {
324*32531Sminshall     /*
325*32531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
326*32531Sminshall      * on the format of our screen, and (in the future) color
327*32531Sminshall      * capaiblities.
328*32531Sminshall      */
329*32531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
330*32531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
331*32531Sminshall 	Sent3270TerminalType = 1;
332*32531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
333*32531Sminshall 	    MaxNumberLines = 27;
334*32531Sminshall 	    MaxNumberColumns = 132;
335*32531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
336*32531Sminshall 	} else if (MaxNumberLines >= 43) {
337*32531Sminshall 	    MaxNumberLines = 43;
338*32531Sminshall 	    MaxNumberColumns = 80;
339*32531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
340*32531Sminshall 	} else if (MaxNumberLines >= 32) {
341*32531Sminshall 	    MaxNumberLines = 32;
342*32531Sminshall 	    MaxNumberColumns = 80;
343*32531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
344*32531Sminshall 	} else {
345*32531Sminshall 	    MaxNumberLines = 24;
346*32531Sminshall 	    MaxNumberColumns = 80;
347*32531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
348*32531Sminshall 	}
349*32531Sminshall 	NumberLines = 24;		/* before we start out... */
350*32531Sminshall 	NumberColumns = 80;
351*32531Sminshall 	ScreenSize = NumberLines*NumberColumns;
352*32531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
353*32531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
354*32531Sminshall 								1);
355*32531Sminshall 	    /*NOTREACHED*/
356*32531Sminshall 	}
357*32531Sminshall 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
358*32531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
359*32531Sminshall 	return 1;
360*32531Sminshall     } else {
361*32531Sminshall 	return 0;
362*32531Sminshall     }
363*32531Sminshall }
36432185Sminshall #endif	/* defined(TN3270) */
365