xref: /csrg-svn/usr.bin/telnet/tn3270.c (revision 35417)
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*35417Sminshall static char sccsid[] = "@(#)tn3270.c	1.13 (Berkeley) 08/28/88";
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 
37*35417Sminshall #include "../telextrn.h"
38*35417Sminshall #include "../ctlr/externs.h"
39*35417Sminshall 
4033801Sminshall #if	defined(unix)
4133801Sminshall char	tline[200];
4233801Sminshall char	*transcom = 0;	/* transparent mode command (default: none) */
4333801Sminshall #endif	/* defined(unix) */
4432531Sminshall 
4533801Sminshall char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
4632531Sminshall 
4732531Sminshall static char	sb_terminal[] = { IAC, SB,
4832531Sminshall 			TELOPT_TTYPE, TELQUAL_IS,
4932531Sminshall 			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
5032531Sminshall 			IAC, SE };
5132531Sminshall #define	SBTERMMODEL	13
5232531Sminshall 
5332531Sminshall static int
5432531Sminshall 	Sent3270TerminalType;	/* Have we said we are a 3270? */
5532531Sminshall 
5633801Sminshall #endif	/* defined(TN3270) */
5732531Sminshall 
5833801Sminshall 
5933801Sminshall void
6034303Sminshall init_3270()
6132551Sminshall {
6233801Sminshall #if	defined(TN3270)
6333801Sminshall     Sent3270TerminalType = 0;
6433801Sminshall     Ifrontp = Ibackp = Ibuf;
6533801Sminshall     init_ctlr();		/* Initialize some things */
6633801Sminshall     init_keyboard();
6733801Sminshall     init_screen();
6833801Sminshall     init_system();
6933801Sminshall #endif	/* defined(TN3270) */
7032551Sminshall }
7132551Sminshall 
7233801Sminshall 
7333801Sminshall #if	defined(TN3270)
7433801Sminshall 
7532185Sminshall /*
7632185Sminshall  * DataToNetwork - queue up some data to go to network.  If "done" is set,
7732185Sminshall  * then when last byte is queued, we add on an IAC EOR sequence (so,
7832185Sminshall  * don't call us with "done" until you want that done...)
7932185Sminshall  *
8032185Sminshall  * We actually do send all the data to the network buffer, since our
8132185Sminshall  * only client needs for us to do that.
8232185Sminshall  */
8332185Sminshall 
8432185Sminshall int
8532185Sminshall DataToNetwork(buffer, count, done)
8632185Sminshall register char	*buffer;	/* where the data is */
8732185Sminshall register int	count;		/* how much to send */
8832185Sminshall int		done;		/* is this the last of a logical block */
8932185Sminshall {
9033801Sminshall     register int loop, c;
9132185Sminshall     int origCount;
9232185Sminshall 
9332185Sminshall     origCount = count;
9432185Sminshall 
9532185Sminshall     while (count) {
9634303Sminshall 	/* If not enough room for EORs, IACs, etc., wait */
9733801Sminshall 	if (NETROOM() < 6) {
9833801Sminshall 	    fd_set o;
9933801Sminshall 
10033801Sminshall 	    FD_ZERO(&o);
10132185Sminshall 	    netflush();
10233801Sminshall 	    while (NETROOM() < 6) {
10332185Sminshall 		FD_SET(net, &o);
10432185Sminshall 		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
10532185Sminshall 						(struct timeval *) 0);
10632185Sminshall 		netflush();
10732185Sminshall 	    }
10832185Sminshall 	}
10934303Sminshall 	c = ring_empty_count(&netoring);
11034303Sminshall 	if (c > count) {
11134303Sminshall 	    c = count;
11234303Sminshall 	}
11334303Sminshall 	loop = c;
11433801Sminshall 	while (loop) {
11534311Sminshall 	    if (((unsigned char)*buffer) == IAC) {
11633801Sminshall 		break;
11733801Sminshall 	    }
11833801Sminshall 	    buffer++;
11933801Sminshall 	    loop--;
12032185Sminshall 	}
12133801Sminshall 	if ((c = c-loop)) {
12233801Sminshall 	    ring_supply_data(&netoring, buffer-c, c);
12333801Sminshall 	    count -= c;
12433801Sminshall 	}
12533801Sminshall 	if (loop) {
12633801Sminshall 	    NET2ADD(IAC, IAC);
12733801Sminshall 	    count--;
12834303Sminshall 	    buffer++;
12933801Sminshall 	}
13032185Sminshall     }
13132185Sminshall 
13233801Sminshall     if (done) {
13334303Sminshall 	NET2ADD(IAC, EOR);
13432185Sminshall 	netflush();		/* try to move along as quickly as ... */
13532185Sminshall     }
13632185Sminshall     return(origCount - count);
13732185Sminshall }
13832185Sminshall 
13932185Sminshall 
14032185Sminshall #if	defined(unix)
14133801Sminshall void
14232185Sminshall inputAvailable()
14332185Sminshall {
14432185Sminshall     HaveInput = 1;
14532185Sminshall }
14632185Sminshall #endif	/* defined(unix) */
14732185Sminshall 
14832185Sminshall void
14932185Sminshall outputPurge()
15032185Sminshall {
15132257Sminshall     ttyflush(1);
15232185Sminshall }
15332185Sminshall 
15432185Sminshall 
15532185Sminshall /*
15632185Sminshall  * The following routines are places where the various tn3270
15732185Sminshall  * routines make calls into telnet.c.
15832185Sminshall  */
15932185Sminshall 
16034303Sminshall /*
16134303Sminshall  * DataToTerminal - queue up some data to go to terminal.
16234303Sminshall  *
16334303Sminshall  * Note: there are people who call us and depend on our processing
16434303Sminshall  * *all* the data at one time (thus the select).
16534303Sminshall  */
16632185Sminshall 
16732185Sminshall int
16832185Sminshall DataToTerminal(buffer, count)
16932185Sminshall register char	*buffer;		/* where the data is */
17032185Sminshall register int	count;			/* how much to send */
17132185Sminshall {
172*35417Sminshall     register int c;
17332185Sminshall     int origCount;
17432185Sminshall 
17532185Sminshall     origCount = count;
17632185Sminshall 
17732185Sminshall     while (count) {
17833801Sminshall 	if (TTYROOM() == 0) {
17932185Sminshall #if	defined(unix)
18033801Sminshall 	    fd_set o;
18133801Sminshall 
18233801Sminshall 	    FD_ZERO(&o);
18333801Sminshall #endif	/* defined(unix) */
184*35417Sminshall 	    ttyflush(0);
18533801Sminshall 	    while (TTYROOM() == 0) {
18633801Sminshall #if	defined(unix)
18732185Sminshall 		FD_SET(tout, &o);
18832185Sminshall 		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
18932185Sminshall 						(struct timeval *) 0);
19032185Sminshall #endif	/* defined(unix) */
191*35417Sminshall 		ttyflush(0);
19232185Sminshall 	    }
19332185Sminshall 	}
19434303Sminshall 	c = TTYROOM();
19534303Sminshall 	if (c > count) {
19634303Sminshall 	    c = count;
19733801Sminshall 	}
19834303Sminshall 	ring_supply_data(&ttyoring, buffer, c);
19934303Sminshall 	count -= c;
20034303Sminshall 	buffer += c;
20132185Sminshall     }
20234303Sminshall     return(origCount);
20332185Sminshall }
20432185Sminshall 
20532185Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
20632185Sminshall  *			Note that we consider the buffer to run all the
20732185Sminshall  *			way to the kernel (thus the select).
20832185Sminshall  */
20932185Sminshall 
21032185Sminshall void
21132185Sminshall EmptyTerminal()
21232185Sminshall {
21332185Sminshall #if	defined(unix)
21432185Sminshall     fd_set	o;
21532185Sminshall 
21632185Sminshall     FD_ZERO(&o);
21732185Sminshall #endif	/* defined(unix) */
21832185Sminshall 
21934303Sminshall     if (TTYBYTES() == 0) {
22032185Sminshall #if	defined(unix)
22132185Sminshall 	FD_SET(tout, &o);
222*35417Sminshall 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
22332185Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
22432185Sminshall #endif	/* defined(unix) */
22532185Sminshall     } else {
22633801Sminshall 	while (TTYBYTES()) {
22732257Sminshall 	    ttyflush(0);
22832185Sminshall #if	defined(unix)
22932185Sminshall 	    FD_SET(tout, &o);
230*35417Sminshall 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
23132185Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
23232185Sminshall #endif	/* defined(unix) */
23332185Sminshall 	}
23432185Sminshall     }
23532185Sminshall }
23632185Sminshall 
23732185Sminshall 
23832185Sminshall /*
23932185Sminshall  * Push3270 - Try to send data along the 3270 output (to screen) direction.
24032185Sminshall  */
24132185Sminshall 
24233801Sminshall int
24332185Sminshall Push3270()
24432185Sminshall {
24533801Sminshall     int save = ring_full_count(&netiring);
24632185Sminshall 
24733801Sminshall     if (save) {
24833801Sminshall 	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
24932185Sminshall 	    if (Ibackp != Ibuf) {
25032185Sminshall 		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
25132185Sminshall 		Ifrontp -= (Ibackp-Ibuf);
25232185Sminshall 		Ibackp = Ibuf;
25332185Sminshall 	    }
25432185Sminshall 	}
25533801Sminshall 	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
25632185Sminshall 	    telrcv();
25732185Sminshall 	}
25832185Sminshall     }
25933801Sminshall     return save != ring_full_count(&netiring);
26032185Sminshall }
26132185Sminshall 
26232185Sminshall 
26332185Sminshall /*
26432185Sminshall  * Finish3270 - get the last dregs of 3270 data out to the terminal
26532185Sminshall  *		before quitting.
26632185Sminshall  */
26732185Sminshall 
26833801Sminshall void
26932185Sminshall Finish3270()
27032185Sminshall {
27132185Sminshall     while (Push3270() || !DoTerminalOutput()) {
27232185Sminshall #if	defined(unix)
27332185Sminshall 	HaveInput = 0;
27432185Sminshall #endif	/* defined(unix) */
27532185Sminshall 	;
27632185Sminshall     }
27732185Sminshall }
27832185Sminshall 
27932185Sminshall 
28032185Sminshall /* StringToTerminal - output a null terminated string to the terminal */
28132185Sminshall 
28232185Sminshall void
28332185Sminshall StringToTerminal(s)
28432185Sminshall char *s;
28532185Sminshall {
28632185Sminshall     int count;
28732185Sminshall 
28832185Sminshall     count = strlen(s);
28932185Sminshall     if (count) {
29032185Sminshall 	(void) DataToTerminal(s, count);	/* we know it always goes... */
29132185Sminshall     }
29232185Sminshall }
29332185Sminshall 
29432185Sminshall 
29532185Sminshall #if	((!defined(NOT43)) || defined(PUTCHAR))
29632185Sminshall /* _putchar - output a single character to the terminal.  This name is so that
29732185Sminshall  *	curses(3x) can call us to send out data.
29832185Sminshall  */
29932185Sminshall 
30032185Sminshall void
30132185Sminshall _putchar(c)
30232185Sminshall char c;
30332185Sminshall {
30433801Sminshall     if (TTYBYTES()) {
30532185Sminshall 	(void) DataToTerminal(&c, 1);
30632185Sminshall     } else {
30733801Sminshall 	TTYADD(c);
30832185Sminshall     }
30932185Sminshall }
31032185Sminshall #endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
31132185Sminshall 
31232531Sminshall void
31332531Sminshall SetForExit()
31432531Sminshall {
31532531Sminshall     setconnmode();
31632531Sminshall     if (In3270) {
31732531Sminshall 	Finish3270();
31832531Sminshall     }
31932531Sminshall     setcommandmode();
32032531Sminshall     fflush(stdout);
32132531Sminshall     fflush(stderr);
32232531Sminshall     if (In3270) {
32332531Sminshall 	StopScreen(1);
32432531Sminshall     }
32532531Sminshall     setconnmode();
32632531Sminshall     setcommandmode();
32732531Sminshall }
32832531Sminshall 
32932531Sminshall void
33032531Sminshall Exit(returnCode)
33132531Sminshall int returnCode;
33232531Sminshall {
33332531Sminshall     SetForExit();
33432531Sminshall     exit(returnCode);
33532531Sminshall }
33632531Sminshall 
33732531Sminshall void
33832531Sminshall ExitString(string, returnCode)
33932531Sminshall char *string;
34032531Sminshall int returnCode;
34132531Sminshall {
34232531Sminshall     SetForExit();
34332531Sminshall     fwrite(string, 1, strlen(string), stderr);
34432531Sminshall     exit(returnCode);
34532531Sminshall }
34632531Sminshall 
347*35417Sminshall #if defined(MSDOS)
34832531Sminshall void
34932531Sminshall ExitPerror(string, returnCode)
35032531Sminshall char *string;
35132531Sminshall int returnCode;
35232531Sminshall {
35332531Sminshall     SetForExit();
35432531Sminshall     perror(string);
35532531Sminshall     exit(returnCode);
35632531Sminshall }
357*35417Sminshall #endif /* defined(MSDOS) */
35832531Sminshall 
35932531Sminshall void
36032531Sminshall SetIn3270()
36132531Sminshall {
36232531Sminshall     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
36332531Sminshall 			    && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
36432531Sminshall 	if (!In3270) {
36532531Sminshall 	    In3270 = 1;
36632531Sminshall 	    Init3270();		/* Initialize 3270 functions */
36732531Sminshall 	    /* initialize terminal key mapping */
36832531Sminshall 	    InitTerminal();	/* Start terminal going */
36932531Sminshall 	    setconnmode();
37032531Sminshall 	}
37132531Sminshall     } else {
37232531Sminshall 	if (In3270) {
37332531Sminshall 	    StopScreen(1);
37432531Sminshall 	    In3270 = 0;
37532531Sminshall 	    Stop3270();		/* Tell 3270 we aren't here anymore */
37632531Sminshall 	    setconnmode();
37732531Sminshall 	}
37832531Sminshall     }
37932531Sminshall }
38032531Sminshall 
38132531Sminshall /*
38232531Sminshall  * tn3270_ttype()
38332531Sminshall  *
38432531Sminshall  *	Send a response to a terminal type negotiation.
38532531Sminshall  *
38632531Sminshall  *	Return '0' if no more responses to send; '1' if a response sent.
38732531Sminshall  */
38832531Sminshall 
38932531Sminshall int
39032531Sminshall tn3270_ttype()
39132531Sminshall {
39232531Sminshall     /*
39332531Sminshall      * Try to send a 3270 type terminal name.  Decide which one based
39432531Sminshall      * on the format of our screen, and (in the future) color
39532531Sminshall      * capaiblities.
39632531Sminshall      */
39732531Sminshall     InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
39832531Sminshall     if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
39932531Sminshall 	Sent3270TerminalType = 1;
40032531Sminshall 	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
40132531Sminshall 	    MaxNumberLines = 27;
40232531Sminshall 	    MaxNumberColumns = 132;
40332531Sminshall 	    sb_terminal[SBTERMMODEL] = '5';
40432531Sminshall 	} else if (MaxNumberLines >= 43) {
40532531Sminshall 	    MaxNumberLines = 43;
40632531Sminshall 	    MaxNumberColumns = 80;
40732531Sminshall 	    sb_terminal[SBTERMMODEL] = '4';
40832531Sminshall 	} else if (MaxNumberLines >= 32) {
40932531Sminshall 	    MaxNumberLines = 32;
41032531Sminshall 	    MaxNumberColumns = 80;
41132531Sminshall 	    sb_terminal[SBTERMMODEL] = '3';
41232531Sminshall 	} else {
41332531Sminshall 	    MaxNumberLines = 24;
41432531Sminshall 	    MaxNumberColumns = 80;
41532531Sminshall 	    sb_terminal[SBTERMMODEL] = '2';
41632531Sminshall 	}
41732531Sminshall 	NumberLines = 24;		/* before we start out... */
41832531Sminshall 	NumberColumns = 80;
41932531Sminshall 	ScreenSize = NumberLines*NumberColumns;
42032531Sminshall 	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
42132531Sminshall 	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
42232531Sminshall 								1);
42332531Sminshall 	    /*NOTREACHED*/
42432531Sminshall 	}
42532531Sminshall 	printsub(">", sb_terminal+2, sizeof sb_terminal-2);
42632531Sminshall 	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
42732531Sminshall 	return 1;
42832531Sminshall     } else {
42932531Sminshall 	return 0;
43032531Sminshall     }
43132531Sminshall }
43233801Sminshall 
43333801Sminshall #if	defined(unix)
43433801Sminshall settranscom(argc, argv)
43533801Sminshall 	int argc;
43633801Sminshall 	char *argv[];
43733801Sminshall {
438*35417Sminshall 	int i;
43933801Sminshall 
44033801Sminshall 	if (argc == 1 && transcom) {
44133801Sminshall 	   transcom = 0;
44233801Sminshall 	}
44333801Sminshall 	if (argc == 1) {
44433801Sminshall 	   return;
44533801Sminshall 	}
44633801Sminshall 	transcom = tline;
44733801Sminshall 	(void) strcpy(transcom, argv[1]);
44833801Sminshall 	for (i = 2; i < argc; ++i) {
44933801Sminshall 	    (void) strcat(transcom, " ");
45033801Sminshall 	    (void) strcat(transcom, argv[i]);
45133801Sminshall 	}
45233801Sminshall }
45333801Sminshall #endif	/* defined(unix) */
45433801Sminshall 
45532185Sminshall #endif	/* defined(TN3270) */
456