xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 33686)
1*33686Sbostic /*
2*33686Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33686Sbostic  * All rights reserved.
4*33686Sbostic  *
5*33686Sbostic  * Redistribution and use in source and binary forms are permitted
6*33686Sbostic  * provided that this notice is preserved and that due credit is given
7*33686Sbostic  * to the University of California at Berkeley. The name of the University
8*33686Sbostic  * may not be used to endorse or promote products derived from this
9*33686Sbostic  * software without specific prior written permission. This software
10*33686Sbostic  * is provided ``as is'' without express or implied warranty.
11*33686Sbostic  */
12*33686Sbostic 
13*33686Sbostic #ifndef lint
14*33686Sbostic static char sccsid[] = "@(#)tn3270.c	1.6 (Berkeley) 03/08/88";
15*33686Sbostic #endif /* not lint */
16*33686Sbostic 
1732657Sminshall #include "fdset.h"
1832657Sminshall 
1932185Sminshall void
2032185Sminshall tn3270_init()
2132185Sminshall {
2232185Sminshall #if	defined(TN3270)
2332185Sminshall     Sent3270TerminalType = 0;
2432185Sminshall     Ifrontp = Ibackp = Ibuf;
2532185Sminshall     init_ctlr();		/* Initialize some things */
2632185Sminshall     init_keyboard();
2732185Sminshall     init_screen();
2832185Sminshall     init_system();
2932185Sminshall #endif	/* defined(TN3270) */
3032185Sminshall }
3132185Sminshall 
3232185Sminshall #if	defined(TN3270)
3332185Sminshall 
3432531Sminshall 
3532531Sminshall static char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
3632531Sminshall 
3732531Sminshall static char	sb_terminal[] = { IAC, SB,
3832531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
3932531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
4032531Sminshall 			IAC, SE };
4132531Sminshall #define	SBTERMMODEL	13
4232531Sminshall 
4332531Sminshall static int
4432531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
4532531Sminshall 
4632531Sminshall 
4732551Sminshall #if	defined(unix)
4832551Sminshall static
4932551Sminshall settranscom(argc, argv)
5032551Sminshall 	int argc;
5132551Sminshall 	char *argv[];
5232551Sminshall {
5332551Sminshall 	int i, len = 0;
5432551Sminshall 	char *strcpy(), *strcat();
5532551Sminshall 
5632551Sminshall 	if (argc == 1 && transcom) {
5732551Sminshall 	   transcom = 0;
5832551Sminshall 	}
5932551Sminshall 	if (argc == 1) {
6032551Sminshall 	   return;
6132551Sminshall 	}
6232551Sminshall 	for (i = 1; i < argc; ++i) {
6332551Sminshall 	    len += 1 + strlen(argv[1]);
6432551Sminshall 	}
6532551Sminshall 	transcom = tline;
6632551Sminshall 	(void) strcpy(transcom, argv[1]);
6732551Sminshall 	for (i = 2; i < argc; ++i) {
6832551Sminshall 	    (void) strcat(transcom, " ");
6932551Sminshall 	    (void) strcat(transcom, argv[i]);
7032551Sminshall 	}
7132551Sminshall }
7232551Sminshall #endif	/* defined(unix) */
7332551Sminshall 
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 
8332185Sminshall int
8432185Sminshall DataToNetwork(buffer, count, done)
8532185Sminshall register char	*buffer;	/* where the data is */
8632185Sminshall register int	count;		/* how much to send */
8732185Sminshall int		done;		/* is this the last of a logical block */
8832185Sminshall {
8932185Sminshall     register int c;
9032185Sminshall     int origCount;
9132185Sminshall     fd_set o;
9232185Sminshall 
9332185Sminshall     origCount = count;
9432185Sminshall     FD_ZERO(&o);
9532185Sminshall 
9632185Sminshall     while (count) {
9732185Sminshall 	if ((netobuf+sizeof netobuf - nfrontp) < 6) {
9832185Sminshall 	    netflush();
9932185Sminshall 	    while ((netobuf+sizeof netobuf - nfrontp) < 6) {
10032185Sminshall 		FD_SET(net, &o);
10132185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
10232185Sminshall 						(struct timeval *) 0);
10332185Sminshall 		netflush();
10432185Sminshall 	    }
10532185Sminshall 	}
10632185Sminshall 	c = *buffer++;
10732185Sminshall 	count--;
10832185Sminshall 	if (c == IAC) {
10932185Sminshall 	    *nfrontp++ = IAC;
11032185Sminshall 	    *nfrontp++ = IAC;
11132185Sminshall 	} else {
11232185Sminshall 	    *nfrontp++ = c;
11332185Sminshall 	}
11432185Sminshall     }
11532185Sminshall 
11632185Sminshall     if (done && !count) {
11732185Sminshall 	*nfrontp++ = IAC;
11832185Sminshall 	*nfrontp++ = EOR;
11932185Sminshall 	netflush();		/* try to move along as quickly as ... */
12032185Sminshall     }
12132185Sminshall     return(origCount - count);
12232185Sminshall }
12332185Sminshall 
12432185Sminshall 
12532185Sminshall #if	defined(unix)
12632185Sminshall static void
12732185Sminshall inputAvailable()
12832185Sminshall {
12932185Sminshall     HaveInput = 1;
13032185Sminshall }
13132185Sminshall #endif	/* defined(unix) */
13232185Sminshall 
13332185Sminshall void
13432185Sminshall outputPurge()
13532185Sminshall {
13632257Sminshall     ttyflush(1);
13732185Sminshall }
13832185Sminshall 
13932185Sminshall 
14032185Sminshall /*
14132185Sminshall  * The following routines are places where the various tn3270
14232185Sminshall  * routines make calls into telnet.c.
14332185Sminshall  */
14432185Sminshall 
14532185Sminshall /* TtyChars() - returns the number of characters in the TTY buffer */
14632185Sminshall TtyChars()
14732185Sminshall {
14832185Sminshall     return(tfrontp-tbackp);
14932185Sminshall }
15032185Sminshall 
15132185Sminshall /* DataToTerminal - queue up some data to go to terminal. */
15232185Sminshall 
15332185Sminshall int
15432185Sminshall DataToTerminal(buffer, count)
15532185Sminshall register char	*buffer;		/* where the data is */
15632185Sminshall register int	count;			/* how much to send */
15732185Sminshall {
15832185Sminshall     int origCount;
15932185Sminshall #if	defined(unix)
16032185Sminshall     fd_set	o;
16132185Sminshall 
16232185Sminshall     FD_ZERO(&o);
16332185Sminshall #endif	/* defined(unix) */
16432185Sminshall     origCount = count;
16532185Sminshall 
16632185Sminshall     while (count) {
16732185Sminshall 	if (tfrontp >= ttyobuf+sizeof ttyobuf) {
16832257Sminshall 	    ttyflush(0);
16932185Sminshall 	    while (tfrontp >= ttyobuf+sizeof ttyobuf) {
17032185Sminshall #if	defined(unix)
17132185Sminshall 		FD_SET(tout, &o);
17232185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
17332185Sminshall 						(struct timeval *) 0);
17432185Sminshall #endif	/* defined(unix) */
17532257Sminshall 		ttyflush(0);
17632185Sminshall 	    }
17732185Sminshall 	}
17832185Sminshall 	*tfrontp++ = *buffer++;
17932185Sminshall 	count--;
18032185Sminshall     }
18132185Sminshall     return(origCount - count);
18232185Sminshall }
18332185Sminshall 
18432185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
18532185Sminshall  *			Note that we consider the buffer to run all the
18632185Sminshall  *			way to the kernel (thus the select).
18732185Sminshall  */
18832185Sminshall 
18932185Sminshall void
19032185Sminshall EmptyTerminal()
19132185Sminshall {
19232185Sminshall #if	defined(unix)
19332185Sminshall     fd_set	o;
19432185Sminshall 
19532185Sminshall     FD_ZERO(&o);
19632185Sminshall #endif	/* defined(unix) */
19732185Sminshall 
19832185Sminshall     if (tfrontp == tbackp) {
19932185Sminshall #if	defined(unix)
20032185Sminshall 	FD_SET(tout, &o);
20132185Sminshall 	(void) select(tout+1, (int *) 0, &o, (int *) 0,
20232185Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
20332185Sminshall #endif	/* defined(unix) */
20432185Sminshall     } else {
20532185Sminshall 	while (tfrontp != tbackp) {
20632257Sminshall 	    ttyflush(0);
20732185Sminshall #if	defined(unix)
20832185Sminshall 	    FD_SET(tout, &o);
20932185Sminshall 	    (void) select(tout+1, (int *) 0, &o, (int *) 0,
21032185Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
21132185Sminshall #endif	/* defined(unix) */
21232185Sminshall 	}
21332185Sminshall     }
21432185Sminshall }
21532185Sminshall 
21632185Sminshall 
21732185Sminshall /*
21832185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
21932185Sminshall  */
22032185Sminshall 
22132185Sminshall static int
22232185Sminshall Push3270()
22332185Sminshall {
22432185Sminshall     int save = scc;
22532185Sminshall 
22632185Sminshall     if (scc) {
22732185Sminshall 	if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
22832185Sminshall 	    if (Ibackp != Ibuf) {
22932185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
23032185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
23132185Sminshall 		Ibackp = Ibuf;
23232185Sminshall 	    }
23332185Sminshall 	}
23432185Sminshall 	if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
23532185Sminshall 	    telrcv();
23632185Sminshall 	}
23732185Sminshall     }
23832185Sminshall     return save != scc;
23932185Sminshall }
24032185Sminshall 
24132185Sminshall 
24232185Sminshall /*
24332185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
24432185Sminshall  *		before quitting.
24532185Sminshall  */
24632185Sminshall 
24732185Sminshall static void
24832185Sminshall Finish3270()
24932185Sminshall {
25032185Sminshall     while (Push3270() || !DoTerminalOutput()) {
25132185Sminshall #if	defined(unix)
25232185Sminshall 	HaveInput = 0;
25332185Sminshall #endif	/* defined(unix) */
25432185Sminshall 	;
25532185Sminshall     }
25632185Sminshall }
25732185Sminshall 
25832185Sminshall 
25932185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
26032185Sminshall 
26132185Sminshall void
26232185Sminshall StringToTerminal(s)
26332185Sminshall char *s;
26432185Sminshall {
26532185Sminshall     int count;
26632185Sminshall 
26732185Sminshall     count = strlen(s);
26832185Sminshall     if (count) {
26932185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
27032185Sminshall     }
27132185Sminshall }
27232185Sminshall 
27332185Sminshall 
27432185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
27532185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
27632185Sminshall  *	curses(3x) can call us to send out data.
27732185Sminshall  */
27832185Sminshall 
27932185Sminshall void
28032185Sminshall _putchar(c)
28132185Sminshall char c;
28232185Sminshall {
28332185Sminshall     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
28432185Sminshall 	(void) DataToTerminal(&c, 1);
28532185Sminshall     } else {
28632185Sminshall 	*tfrontp++ = c;		/* optimize if possible. */
28732185Sminshall     }
28832185Sminshall }
28932185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
29032185Sminshall 
29132531Sminshall void
29232531Sminshall SetForExit()
29332531Sminshall {
29432531Sminshall     setconnmode();
29532531Sminshall     if (In3270) {
29632531Sminshall 	Finish3270();
29732531Sminshall     }
29832531Sminshall     setcommandmode();
29932531Sminshall     fflush(stdout);
30032531Sminshall     fflush(stderr);
30132531Sminshall     if (In3270) {
30232531Sminshall 	StopScreen(1);
30332531Sminshall     }
30432531Sminshall     setconnmode();
30532531Sminshall     setcommandmode();
30632531Sminshall }
30732531Sminshall 
30832531Sminshall void
30932531Sminshall Exit(returnCode)
31032531Sminshall int returnCode;
31132531Sminshall {
31232531Sminshall     SetForExit();
31332531Sminshall     exit(returnCode);
31432531Sminshall }
31532531Sminshall 
31632531Sminshall void
31732531Sminshall ExitString(string, returnCode)
31832531Sminshall char *string;
31932531Sminshall int returnCode;
32032531Sminshall {
32132531Sminshall     SetForExit();
32232531Sminshall     fwrite(string, 1, strlen(string), stderr);
32332531Sminshall     exit(returnCode);
32432531Sminshall }
32532531Sminshall 
32632531Sminshall void
32732531Sminshall ExitPerror(string, returnCode)
32832531Sminshall char *string;
32932531Sminshall int returnCode;
33032531Sminshall {
33132531Sminshall     SetForExit();
33232531Sminshall     perror(string);
33332531Sminshall     exit(returnCode);
33432531Sminshall }
33532531Sminshall 
33632531Sminshall void
33732531Sminshall SetIn3270()
33832531Sminshall {
33932531Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
34032531Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
34132531Sminshall 	if (!In3270) {
34232531Sminshall 	    In3270 = 1;
34332531Sminshall 	    Init3270();		/* Initialize 3270 functions */
34432531Sminshall 	    /* initialize terminal key mapping */
34532531Sminshall 	    InitTerminal();	/* Start terminal going */
34632531Sminshall 	    setconnmode();
34732531Sminshall 	}
34832531Sminshall     } else {
34932531Sminshall 	if (In3270) {
35032531Sminshall 	    StopScreen(1);
35132531Sminshall 	    In3270 = 0;
35232531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
35332531Sminshall 	    setconnmode();
35432531Sminshall 	}
35532531Sminshall     }
35632531Sminshall }
35732531Sminshall 
35832531Sminshall /*
35932531Sminshall  * tn3270_ttype()
36032531Sminshall  *
36132531Sminshall  *	Send a response to a terminal type negotiation.
36232531Sminshall  *
36332531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
36432531Sminshall  */
36532531Sminshall 
36632531Sminshall int
36732531Sminshall tn3270_ttype()
36832531Sminshall {
36932531Sminshall     /*
37032531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
37132531Sminshall      * on the format of our screen, and (in the future) color
37232531Sminshall      * capaiblities.
37332531Sminshall      */
37432531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
37532531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
37632531Sminshall 	Sent3270TerminalType = 1;
37732531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
37832531Sminshall 	    MaxNumberLines = 27;
37932531Sminshall 	    MaxNumberColumns = 132;
38032531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
38132531Sminshall 	} else if (MaxNumberLines >= 43) {
38232531Sminshall 	    MaxNumberLines = 43;
38332531Sminshall 	    MaxNumberColumns = 80;
38432531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
38532531Sminshall 	} else if (MaxNumberLines >= 32) {
38632531Sminshall 	    MaxNumberLines = 32;
38732531Sminshall 	    MaxNumberColumns = 80;
38832531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
38932531Sminshall 	} else {
39032531Sminshall 	    MaxNumberLines = 24;
39132531Sminshall 	    MaxNumberColumns = 80;
39232531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
39332531Sminshall 	}
39432531Sminshall 	NumberLines = 24;		/* before we start out... */
39532531Sminshall 	NumberColumns = 80;
39632531Sminshall 	ScreenSize = NumberLines*NumberColumns;
39732531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
39832531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
39932531Sminshall 								1);
40032531Sminshall 	    /*NOTREACHED*/
40132531Sminshall 	}
40232531Sminshall 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
40332531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
40432531Sminshall 	return 1;
40532531Sminshall     } else {
40632531Sminshall 	return 0;
40732531Sminshall     }
40832531Sminshall }
40932185Sminshall #endif	/* defined(TN3270) */
410