130043Sminshall /*
230043Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
330043Sminshall  *	University of California and by Gregory Glenn Minshall.
430043Sminshall  *
530043Sminshall  *	Permission to use, copy, modify, and distribute these
630043Sminshall  *	programs and their documentation for any purpose and
730043Sminshall  *	without fee is hereby granted, provided that this
830043Sminshall  *	copyright and permission appear on all copies and
930043Sminshall  *	supporting documentation, the name of the Regents of
1030043Sminshall  *	the University of California not be used in advertising
1130043Sminshall  *	or publicity pertaining to distribution of the programs
1230043Sminshall  *	without specific prior permission, and notice be given in
1330043Sminshall  *	supporting documentation that copying and distribution is
1430043Sminshall  *	by permission of the Regents of the University of California
1530043Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1630043Sminshall  *	University of California nor Gregory Glenn Minshall make
1730043Sminshall  *	representations about the suitability of this software
1830043Sminshall  *	for any purpose.  It is provided "as is" without
1930043Sminshall  *	express or implied warranty.
2030043Sminshall  */
2130043Sminshall 
2230043Sminshall #ifndef lint
2330043Sminshall static	char	sccsid[] = "@(#)outbound.c	3.1  10/29/86";
2430043Sminshall #endif	/* lint */
2530043Sminshall 
2630043Sminshall 
2730043Sminshall #if defined(unix)
2830043Sminshall #include <signal.h>
2930043Sminshall #include <sgtty.h>
3030043Sminshall #endif
3130043Sminshall #include <stdio.h>
3230043Sminshall #include <curses.h>
3330043Sminshall 
3430043Sminshall #include "terminal.h"
3530043Sminshall 
3630043Sminshall #include "../telnet.ext"
3730043Sminshall 
3830043Sminshall #include "../ctlr/hostctlr.h"
3930043Sminshall #include "../ctlr/inbound.ext"
4030043Sminshall #include "../ctlr/options.ext"
4130043Sminshall #include "../ctlr/outbound.ext"
4230043Sminshall #include "../ctlr/screen.h"
4330043Sminshall 
4430043Sminshall #include "../keyboard/map3270.ext"
4530043Sminshall 
4630043Sminshall #include "../system/globals.h"
4730043Sminshall 
4830043Sminshall extern void EmptyTerminal();
4930043Sminshall 
5030043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
5130043Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
5230043Sminshall 
5330043Sminshall 
5430043Sminshall static int terminalCursorAddress = 0;	/* where the cursor is on term */
5530043Sminshall static int screenInitd = 0; 		/* the screen has been initialized */
5630043Sminshall static int screenStopped = 1;		/* the screen has been stopped */
5730043Sminshall #if	defined(SLOWSCREEN)
5830043Sminshall static int max_changes_before_poll;	/* how many characters before looking */
5930043Sminshall 					/* at terminal and net again */
6030043Sminshall #endif	/* defined(SLOWSCREEN) */
6130043Sminshall 
6230043Sminshall static int needToRing = 0;		/* need to ring terinal bell */
6330043Sminshall static char *bellSequence = "\07";	/* bell sequence (may be replaced by
6430043Sminshall 					 * VB during initialization)
6530043Sminshall 					 */
6630043Sminshall static WINDOW *bellwin;			/* The window the bell message is in */
6730043Sminshall int	bellwinup = 0;			/* Are we up with it or not */
6830043Sminshall 
6930043Sminshall #if	defined(unix)
7030043Sminshall static char *KS, *KE;
7130043Sminshall #endif	/* defined(unix) */
7230043Sminshall 
73*30074Sminshall 
74*30074Sminshall #if	defined(SLOWSCREEN)
75*30074Sminshall static int inHighlightMode = 0;
76*30074Sminshall #endif	/* defined(SLOWSCREEN) */
77*30074Sminshall 
78*30074Sminshall /* Variables for transparent mode */
7930043Sminshall #if	defined(unix)
8030043Sminshall static int tcflag = -1;			/* transparent mode command flag */
8130043Sminshall static int savefd[2];			/* for storing fds during transcom */
82*30074Sminshall extern int	tin, tout;		/* file descriptors */
8330043Sminshall #endif	/* defined(unix) */
8430043Sminshall 
8530043Sminshall 
8630043Sminshall #include "disp_asc.out"
8730043Sminshall 
8830043Sminshall 
8930043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
9030043Sminshall 
9130043Sminshall static void
9230043Sminshall OurExitString(file, string, value)
9330043Sminshall FILE	*file;
9430043Sminshall char	*string;
9530043Sminshall int	value;
9630043Sminshall {
9730043Sminshall     static int recursion = 0;
9830043Sminshall 
9930043Sminshall     if (!recursion) {
10030043Sminshall 	recursion = 1;
10130043Sminshall 	ExitString(file, string, value);
10230043Sminshall     }
10330043Sminshall }
10430043Sminshall 
10530043Sminshall 
10630043Sminshall /* DoARefresh */
10730043Sminshall 
10830043Sminshall static void
10930043Sminshall DoARefresh()
11030043Sminshall {
11130043Sminshall     if (ERR == refresh()) {
11230043Sminshall 	OurExitString(stderr, "ERR from refresh\n", 1);
11330043Sminshall     }
11430043Sminshall }
11530043Sminshall 
11630043Sminshall static void
11730043Sminshall GoAway(from, where)
11830043Sminshall char *from;		/* routine that gave error */
11930043Sminshall int	where;		/* cursor address */
12030043Sminshall {
12130043Sminshall 	char foo[100];
12230043Sminshall 
12330043Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
12430043Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
12530043Sminshall 	OurExitString(stderr, foo, 1);
12630043Sminshall 	/* NOTREACHED */
12730043Sminshall }
12830043Sminshall 
12930043Sminshall #if	defined(SLOWSCREEN)
13030043Sminshall /* What is the screen address of the attribute byte for the terminal */
13130043Sminshall 
13230043Sminshall static int
13330043Sminshall WhereTermAttrByte(p)
13430043Sminshall register int	p;
13530043Sminshall {
13630043Sminshall     register int i;
13730043Sminshall 
13830043Sminshall     i = p;
13930043Sminshall 
14030043Sminshall     do {
14130043Sminshall 	if (TermIsStartField(i)) {
14230043Sminshall 	    return(i);
14330043Sminshall 	}
14430043Sminshall 	i = ScreenDec(i);
14530043Sminshall     } while (i != p);
14630043Sminshall 
14730043Sminshall     return(LowestScreen());	/* unformatted screen... */
14830043Sminshall }
14930043Sminshall #endif	/* defined(SLOWSCREEN) */
15030043Sminshall 
15130043Sminshall /*
15230043Sminshall  *	There are two algorithms for updating the screen.
15330043Sminshall  *  The first, SlowScreen() optimizes the line between the
15430043Sminshall  *  computer and the screen (say a 9600 baud line).  To do
15530043Sminshall  *  this, we break out of the loop every so often to look
15630043Sminshall  *  at any pending input from the network (so that successive
15730043Sminshall  *  screens will only partially print until the final screen,
15830043Sminshall  *  the one the user possibly wants to see, is displayed
15930043Sminshall  *  in its entirety).
16030043Sminshall  *
16130043Sminshall  *	The second algorithm tries to optimize CPU time (by
16230043Sminshall  *  being simpler) at the cost of the bandwidth to the
16330043Sminshall  *  screen.
16430043Sminshall  *
16530043Sminshall  *	Of course, curses(3X) gets in here also.
16630043Sminshall  */
16730043Sminshall 
16830043Sminshall 
16930043Sminshall #if defined(SLOWSCREEN)
17030043Sminshall #if	defined(NOT43)
17130043Sminshall static int
17230043Sminshall #else	/* defined(NOT43) */
17330043Sminshall static void
17430043Sminshall #endif	/* defined(NOT43) */
17530043Sminshall SlowScreen()
17630043Sminshall {
17730043Sminshall     register int pointer;
17830043Sminshall     register int c;
17930043Sminshall     register int fieldattr;
18030043Sminshall     register int columnsleft;
18130043Sminshall 
18230043Sminshall #   define  SetHighlightMode(p) { \
18330043Sminshall 		if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \
18430043Sminshall 		    if (!inHighlightMode) { \
18530043Sminshall 			inHighlightMode = 1; \
18630043Sminshall 			standout(); \
18730043Sminshall 		    } \
18830043Sminshall 		} else { \
18930043Sminshall 		    if (inHighlightMode) { \
19030043Sminshall 			inHighlightMode = 0; \
19130043Sminshall 			standend(); \
19230043Sminshall 		    } \
19330043Sminshall 		} \
19430043Sminshall 	    }
19530043Sminshall 
19630043Sminshall #   define  DoCharacterAt(c,p) { \
19730043Sminshall 		SetTerminal(p, c); \
19830043Sminshall 		if (p != HighestScreen()) { \
19930043Sminshall 		    c = TerminalCharacterAttr(disp_asc[c&0xff], p, \
20030043Sminshall 								fieldattr); \
20130043Sminshall 		    if (terminalCursorAddress != p) { \
20230043Sminshall 			if (ERR == mvaddch(ScreenLine(p), \
20330043Sminshall 						ScreenLineOffset(p), c)) {\
20430043Sminshall 			    GoAway("mvaddch", p); \
20530043Sminshall 			} \
20630043Sminshall 		    } else { \
20730043Sminshall 			if (ERR == addch(c)) {\
20830043Sminshall 			    GoAway("addch", p); \
20930043Sminshall 			} \
21030043Sminshall 		    } \
21130043Sminshall 		    terminalCursorAddress = ScreenInc(p); \
21230043Sminshall 		} \
21330043Sminshall 	    }
21430043Sminshall 
21530043Sminshall 
21630043Sminshall     /* run through screen, printing out non-null lines */
21730043Sminshall 
21830043Sminshall     /* There are two separate reasons for wanting to terminate this
21930043Sminshall      * loop early.  One is to respond to new input (either from
22030043Sminshall      * the terminal or from the network [host]).  For this reason,
22130043Sminshall      * we expect to see 'HaveInput' come true when new input comes in.
22230043Sminshall      *
22330043Sminshall      * The second reason is a bit more difficult (for me) to understand.
22430043Sminshall      * Basically, we don't want to get too far ahead of the characters that
22530043Sminshall      * appear on the screen.  Ideally, we would type out a few characters,
22630043Sminshall      * wait until they appeared on the screen, then type out a few more.
22730043Sminshall      * The reason for this is that the user, on seeing some characters
22830043Sminshall      * appear on the screen may then start to type something.  We would
22930043Sminshall      * like to look at what the user types at about the same 'time'
23030043Sminshall      * (measured by characters being sent to the terminal) that the
23130043Sminshall      * user types them.  For this reason, what we would like to do
23230043Sminshall      * is update a bit, then call curses to do a refresh, flush the
23330043Sminshall      * output to the terminal, then wait until the terminal data
23430043Sminshall      * has been sent.
23530043Sminshall      *
23630043Sminshall      * Note that curses is useful for, among other things, deciding whether
23730043Sminshall      * or not to send :ce: (clear to end of line), so we should call curses
23830043Sminshall      * at end of lines (beginning of next lines).
23930043Sminshall      *
24030043Sminshall      * The problems here are the following:  If we do lots of write(2)s,
24130043Sminshall      * we will be doing lots of context switches, thus lots of overhead
24230043Sminshall      * (which we have already).  Second, if we do a select to wait for
24330043Sminshall      * the output to drain, we have to contend with the fact that NOW
24430043Sminshall      * we are scheduled to run, but who knows what the scheduler will
24530043Sminshall      * decide when the output has caught up.
24630043Sminshall      */
24730043Sminshall 
24830043Sminshall     if (Highest == HighestScreen()) {
24930043Sminshall 	Highest = ScreenDec(Highest);	/* else, while loop will never end */
25030043Sminshall     }
25130043Sminshall     if (Lowest < LowestScreen()) {
25230043Sminshall 	Lowest = LowestScreen();	/* could be -1 in some cases with
25330043Sminshall 					 * unformatted screens.
25430043Sminshall 					 */
25530043Sminshall     }
25630043Sminshall     if (Highest >= (pointer = Lowest)) {
25730043Sminshall 		/* if there is anything to do, do it.  We won't terminate
25830043Sminshall 		 * the loop until we've gone at least to Highest.
25930043Sminshall 		 */
26030043Sminshall 	while ((pointer <= Highest) && !HaveInput) {
26130043Sminshall 
26230043Sminshall 		/* point at the next place of disagreement */
26330043Sminshall 	    pointer += (bunequal(Host+pointer, Terminal+pointer,
26430043Sminshall 			(Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
26530043Sminshall 
26630043Sminshall 		/* how many characters to change until the end of the
26730043Sminshall 		 * current line
26830043Sminshall 		 */
26930043Sminshall 	    columnsleft = NumberColumns - ScreenLineOffset(pointer);
27030043Sminshall 		/*
27130043Sminshall 		 * Make sure we are where we think we are.
27230043Sminshall 		 */
27330043Sminshall 	    move(ScreenLine(pointer), ScreenLineOffset(pointer));
27430043Sminshall 
27530043Sminshall 		/* what is the field attribute of the current position */
27630043Sminshall 	    fieldattr = FieldAttributes(WhereAttrByte(pointer));
27730043Sminshall 
27830043Sminshall 	    if ((IsStartField(pointer) != TermIsStartField(pointer)) ||
27930043Sminshall 		    (IsStartField(pointer) &&
28030043Sminshall 			fieldattr != TermAttributes(pointer))) {
28130043Sminshall 
28230043Sminshall 		int oldterm;
28330043Sminshall 
28430043Sminshall 		oldterm = TermAttributes(pointer);
28530043Sminshall 		if (IsStartField(pointer)) {
28630043Sminshall 		    TermNewField(pointer, fieldattr);
28730043Sminshall 		    SetTerminal(pointer, 0);
28830043Sminshall 		} else {
28930043Sminshall 		    TermDeleteField(pointer);
29030043Sminshall 		}
29130043Sminshall 		    /* We always do the first character in a divergent
29230043Sminshall 		     * field, since otherwise the start of a field in
29330043Sminshall 		     * the Host structure may leave a highlighted blank
29430043Sminshall 		     * on the screen, and the start of a field in the
29530043Sminshall 		     * Terminal structure may leave a non-highlighted
29630043Sminshall 		     * something in the middle of a highlighted field
29730043Sminshall 		     * on the screen.
29830043Sminshall 		     */
29930043Sminshall 		SetHighlightMode(pointer);
30030043Sminshall 		c = GetHost(pointer);
30130043Sminshall 		DoCharacterAt(c,pointer);		/* MACRO */
30230043Sminshall 
30330043Sminshall 		if (NotVisuallyCompatibleAttributes
30430043Sminshall 				(pointer, fieldattr, oldterm)) {
30530043Sminshall 		    int j;
30630043Sminshall 
30730043Sminshall 		    j = pointer;
30830043Sminshall 
30930043Sminshall 		    pointer = ScreenInc(pointer);
31030043Sminshall 		    if (!(--columnsleft)) {
31130043Sminshall 			DoARefresh();
31230043Sminshall 			EmptyTerminal();
31330043Sminshall 			move(ScreenLine(pointer), 0);
31430043Sminshall 			columnsleft = NumberColumns;
31530043Sminshall 		    }
31630043Sminshall 		    SetHighlightMode(pointer);	/* Turn on highlighting */
31730043Sminshall 		    while (!IsStartField(pointer) &&
31830043Sminshall 				!TermIsStartField(pointer)) {
31930043Sminshall 			c = GetHost(pointer);
32030043Sminshall 			DoCharacterAt(c,pointer);	/* MACRO */
32130043Sminshall 			pointer = ScreenInc(pointer);
32230043Sminshall 			if (!(--columnsleft)) {
32330043Sminshall 			    DoARefresh();
32430043Sminshall 			    EmptyTerminal();
32530043Sminshall 			    move(ScreenLine(pointer), 0);
32630043Sminshall 			    columnsleft = NumberColumns;
32730043Sminshall 				/* We don't look at HaveInput here, since
32830043Sminshall 				 * if we leave this loop before the end of
32930043Sminshall 				 * the 3270 field, we could have pointer
33030043Sminshall 				 * higher than Highest.  This would cause
33130043Sminshall 				 * us to end the highest "while" loop,
33230043Sminshall 				 * but we may, in fact, need to go around the
33330043Sminshall 				 * screen once again.
33430043Sminshall 				 */
33530043Sminshall 			}
33630043Sminshall 			/*		The loop needs to be protected
33730043Sminshall 			 *	from the situation where there had been only
33830043Sminshall 			 *	one field on the Terminal, and none on the Host.
33930043Sminshall 			 *	In this case, we have just deleted our last
34030043Sminshall 			 *	field.	Hence, the break.
34130043Sminshall 			 */
34230043Sminshall 			if (j == pointer) {
34330043Sminshall 			    break;
34430043Sminshall 			}
34530043Sminshall 		    }
34630043Sminshall 		    if (IsStartField(pointer) && !TermIsStartField(pointer)) {
34730043Sminshall 			    /* Remember what the terminal looked like */
34830043Sminshall 			TermNewField(pointer, oldterm);
34930043Sminshall 			    /*
35030043Sminshall 			     * The danger here is that the current position may
35130043Sminshall 			     * be the start of a Host field.  If so, and the
35230043Sminshall 			     * field is highlighted, and our terminal was
35330043Sminshall 			     * highlighted, then we will leave a highlighted
35430043Sminshall 			     * blank at this position.
35530043Sminshall 			     */
35630043Sminshall 			SetHighlightMode(pointer);
35730043Sminshall 			c = GetHost(pointer);
35830043Sminshall 			DoCharacterAt(c,pointer);
35930043Sminshall 		    }
36030043Sminshall 			/* We could be in the situation of needing to exit.
36130043Sminshall 			 * This could happen if the current field wrapped around
36230043Sminshall 			 * the end of the screen.
36330043Sminshall 			 */
36430043Sminshall 		    if (j > pointer) {
36530043Sminshall 			break;
36630043Sminshall 		    }
36730043Sminshall 		} else {
36830043Sminshall 		    c = GetHost(pointer);
36930043Sminshall 			/* We always do the first character in a divergent
37030043Sminshall 			 * field, since otherwise the start of a field in
37130043Sminshall 			 * the Host structure may leave a highlighted blank
37230043Sminshall 			 * on the screen, and the start of a field in the
37330043Sminshall 			 * Terminal structure may leave a non-highlighted
37430043Sminshall 			 * something in the middle of a highlighted field
37530043Sminshall 			 * on the screen.
37630043Sminshall 			 */
37730043Sminshall 		    SetHighlightMode(pointer);
37830043Sminshall 		    DoCharacterAt(c,pointer);
37930043Sminshall 		}
38030043Sminshall 	    } else {
38130043Sminshall 		SetHighlightMode(pointer);
38230054Sminshall 		/*
38330054Sminshall 		 * The following will terminate at least when we get back
38430043Sminshall 		 * to the original 'pointer' location (since we force
38530043Sminshall 		 * things to be equal).
38630043Sminshall 		 */
38730043Sminshall 		while (((c = GetHost(pointer)) != GetTerminal(pointer)) &&
38830043Sminshall 			!IsStartField(pointer) && !TermIsStartField(pointer)) {
38930043Sminshall 		    DoCharacterAt(c, pointer);
39030043Sminshall 		    pointer = ScreenInc(pointer);
39130043Sminshall 		    if (!(--columnsleft)) {
39230043Sminshall 			DoARefresh();
39330043Sminshall 			EmptyTerminal();
39430043Sminshall 			if (HaveInput) {	/* if input came in, take it */
39530043Sminshall 			    break;
39630043Sminshall 			}
39730043Sminshall 			move(ScreenLine(pointer), 0);
39830043Sminshall 			columnsleft = NumberColumns;
39930043Sminshall 		    }
40030043Sminshall 		}
40130043Sminshall 	    }
40230043Sminshall 	}
40330043Sminshall     }
40430043Sminshall     DoARefresh();
40530043Sminshall     Lowest = pointer;
40630043Sminshall     if (Lowest > Highest) {		/* if we finished input... */
40730043Sminshall 	Lowest = HighestScreen()+1;
40830043Sminshall 	Highest = LowestScreen()-1;
40930043Sminshall 	terminalCursorAddress = CorrectTerminalCursor();
41030043Sminshall 	if (ERR == move(ScreenLine(terminalCursorAddress),
41130043Sminshall 			ScreenLineOffset(terminalCursorAddress))) {
41230043Sminshall 	    GoAway("move", terminalCursorAddress);
41330043Sminshall 	}
41430043Sminshall 	DoARefresh();
41530043Sminshall 	if (needToRing) {
41630043Sminshall 	    StringToTerminal(bellSequence);
41730043Sminshall 	    needToRing = 0;
41830043Sminshall 	}
41930043Sminshall     }
42030043Sminshall     EmptyTerminal();			/* move data along */
42130043Sminshall     return;
42230043Sminshall }
42330043Sminshall #endif	/* defined(SLOWSCREEN) */
42430043Sminshall 
42530043Sminshall #if	defined(NOT43)
42630043Sminshall static int
42730043Sminshall #else	/* defined(NOT43) */
42830043Sminshall static void
42930043Sminshall #endif	/* defined(NOT43) */
43030043Sminshall FastScreen()
43130043Sminshall {
43230043Sminshall #if	defined(msdos)
43330043Sminshall #define	SaveCorner	0
43430043Sminshall #else	/* defined(msdos) */
43530043Sminshall #define	SaveCorner	1
43630043Sminshall #endif	/* defined(msdos) */
43730043Sminshall 
43830043Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
43930043Sminshall 				standout(); \
44030043Sminshall 			    } else { \
44130043Sminshall 				standend(); \
44230043Sminshall 			    } \
44330043Sminshall 			    if (IsNonDisplayAttr(a)) { \
44430043Sminshall 				a = 0; 	/* zero == don't display */ \
44530043Sminshall 			    } \
44630043Sminshall 			    if (!FormattedScreen()) { \
44730043Sminshall 				a = 1;	/* one ==> do display on unformatted */\
44830043Sminshall 			    }
44930043Sminshall     ScreenImage *p, *upper;
45030043Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
45130043Sminshall 
45230043Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
45330043Sminshall  * only need to go from Lowest to Highest.  However, if we find a
45430043Sminshall  * field in the middle, we do the whole screen.
45530043Sminshall  *
45630043Sminshall  * In particular, we separate out the two cases from the beginning.
45730043Sminshall  */
45830043Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
45930043Sminshall 	register int columnsleft;
46030043Sminshall 
46130043Sminshall 	move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
46230043Sminshall 	p = &Host[Lowest];
46330043Sminshall #if	!defined(msdos)
46430043Sminshall 	if (Highest == HighestScreen()) {
46530043Sminshall 	    Highest = ScreenDec(Highest);
46630043Sminshall 	}
46730043Sminshall #endif	/* !defined(msdos) */
46830043Sminshall 	upper = &Host[Highest];
46930043Sminshall 	fieldattr = FieldAttributes(Lowest);
47030043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
47130043Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
47230043Sminshall 
47330043Sminshall 	while (p <= upper) {
47430054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
47530043Sminshall 		Highest = HighestScreen();
47630043Sminshall 		Lowest = LowestScreen();
47730043Sminshall 		FastScreen();		/* Recurse */
47830043Sminshall 		return;
47930043Sminshall 	    } else if (fieldattr) {	/* Should we display? */
48030043Sminshall 		addch(disp_asc[p->data]);	/* Display translated data */
48130043Sminshall 	    } else {
48230043Sminshall 		addch(' ');			/* Display a blank */
48330043Sminshall 	    }
48430043Sminshall 			/* If the physical screen is larger than what we
48530043Sminshall 			 * are using, we need to make sure that each line
48630043Sminshall 			 * starts at the beginning of the line.  Otherwise,
48730043Sminshall 			 * we will just string all the lines together.
48830043Sminshall 			 */
48930043Sminshall 	    p++;
49030043Sminshall 	    if (--columnsleft == 0) {
49130043Sminshall 		int i = p-Host;
49230043Sminshall 
49330043Sminshall 		move(ScreenLine(i), 0);
49430043Sminshall 		columnsleft = NumberColumns;
49530043Sminshall 	    }
49630043Sminshall 	}
49730043Sminshall     } else {		/* Going from Lowest to Highest */
49830043Sminshall 	unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
49930043Sminshall 	ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
50030043Sminshall 	register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
50130043Sminshall 
50230043Sminshall 	*tmpend = 0;		/* terminate from the beginning */
50330043Sminshall 	move(0,0);
50430043Sminshall 	p = Host;
50530043Sminshall 	fieldattr = FieldAttributes(LowestScreen());
50630043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
50730043Sminshall 
50830043Sminshall 	while (p <= End) {
50930054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
51030043Sminshall 		if (tmp != tmpbuf) {
51130043Sminshall 		    *tmp++ = 0;			/* close out */
51230043Sminshall 		    addstr(tmpbuf);
51330043Sminshall 		    tmp = tmpbuf;
51430043Sminshall 		    tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host);
51530043Sminshall 		}
51630054Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
51730043Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
51830043Sminshall 		*tmp++ = ' ';
51930043Sminshall 	    } else {
52030043Sminshall 		if (fieldattr) {	/* Should we display? */
52130043Sminshall 				/* Display translated data */
52230043Sminshall 		    *tmp++ = disp_asc[p->data];
52330043Sminshall 		} else {
52430043Sminshall 		    *tmp++ = ' ';
52530043Sminshall 		}
52630043Sminshall 	    }
52730043Sminshall 			/* If the physical screen is larger than what we
52830043Sminshall 			 * are using, we need to make sure that each line
52930043Sminshall 			 * starts at the beginning of the line.  Otherwise,
53030043Sminshall 			 * we will just string all the lines together.
53130043Sminshall 			 */
53230043Sminshall 	    p++;
53330043Sminshall 	    if (tmp == tmpend) {
53430043Sminshall 		int i = p-Host;		/* Be sure the "p++" happened first! */
53530043Sminshall 
53630043Sminshall 		*tmp++ = 0;
53730043Sminshall 		addstr(tmpbuf);
53830043Sminshall 		tmp = tmpbuf;
53930043Sminshall 		move(ScreenLine(i), 0);
54030043Sminshall 		tmpend = tmpbuf + NumberColumns;
54130043Sminshall 	    }
54230043Sminshall 	}
54330043Sminshall 	if (tmp != tmpbuf) {
54430043Sminshall 	    *tmp++ = 0;
54530043Sminshall 	    addstr(tmpbuf);
54630043Sminshall 	    tmp = tmpbuf;
54730043Sminshall 	}
54830043Sminshall     }
54930043Sminshall     Lowest = HighestScreen()+1;
55030043Sminshall     Highest = LowestScreen()-1;
55130043Sminshall     terminalCursorAddress = CorrectTerminalCursor();
55230043Sminshall     if (ERR == move(ScreenLine(terminalCursorAddress),
55330043Sminshall 		    ScreenLineOffset(terminalCursorAddress))) {
55430043Sminshall 	GoAway("move", terminalCursorAddress);
55530043Sminshall     }
55630043Sminshall     DoARefresh();
55730043Sminshall     if (needToRing) {
55830043Sminshall 	StringToTerminal(bellSequence);
55930043Sminshall 	needToRing = 0;
56030043Sminshall     }
56130043Sminshall     EmptyTerminal();			/* move data along */
56230043Sminshall     return;
56330043Sminshall }
56430043Sminshall 
56530043Sminshall 
56630043Sminshall /* TryToSend - send data out to user's terminal */
56730043Sminshall 
56830043Sminshall #if	defined(NOT43)
56930043Sminshall int
57030043Sminshall #else	/* defined(NOT43) */
57130043Sminshall void
57230043Sminshall #endif	/* defined(NOT43) */
57330043Sminshall 	(*TryToSend)() = FastScreen;
57430043Sminshall 
57530043Sminshall /* StartScreen - called to initialize the screen, etc. */
57630043Sminshall 
57730043Sminshall void
57830043Sminshall StartScreen()
57930043Sminshall {
58030043Sminshall #if defined(unix)
58130043Sminshall     struct sgttyb ourttyb;
58230043Sminshall     static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
58330043Sminshall 		2400, 4800, 9600 };
58430043Sminshall #endif
58530043Sminshall 
58630043Sminshall     if (!screenInitd) { 	/* not initialized */
58730043Sminshall #if	defined(unix)
58830043Sminshall 	char KSEbuffer[2050];
58930043Sminshall 	char *lotsofspace = KSEbuffer;
59030043Sminshall 	extern int abort();
59130043Sminshall 	extern char *tgetstr();
59230043Sminshall #endif	/* defined(unix) */
59330043Sminshall 
59430043Sminshall 	bzero((char *)Host, sizeof Host);
59530043Sminshall 
59630043Sminshall 	bzero(Orders, sizeof Orders);
59730043Sminshall 	Orders[ORDER_SF] = Orders[ORDER_SBA] = Orders[ORDER_IC]
59830043Sminshall 		= Orders[ORDER_PT] = Orders[ORDER_RA] = Orders[ORDER_EUA]
59930043Sminshall 		= Orders[ORDER_YALE] = 1;
60030043Sminshall 
60130043Sminshall 	DeleteAllFields();
60230043Sminshall #if	defined(SLOWSCREEN)
60330043Sminshall 	bzero((char *)Terminal, sizeof Terminal);
60430043Sminshall #endif	/* defined(SLOWSCREEN) */
60530043Sminshall 	Lowest = HighestScreen()+1;
60630043Sminshall 	Highest = LowestScreen()-1;
60730043Sminshall 	terminalCursorAddress =
60830043Sminshall 		CursorAddress =
60930043Sminshall 		BufferAddress = SetBufferAddress(0,0);
61030043Sminshall 	UnLocked = 1;
61130043Sminshall 	Initialized = 1;
61230043Sminshall 	OutputClock = 1;
61330043Sminshall 	TransparentClock = -1;
61430043Sminshall #if defined(unix)
61530043Sminshall 	signal(SIGHUP, abort);
61630043Sminshall #endif
61730043Sminshall 
61830043Sminshall 	TryToSend = FastScreen;
61930043Sminshall #if defined(unix) && defined(SLOWSCREEN)
62030043Sminshall 	ioctl(1, TIOCGETP, (char *) &ourttyb);
62130043Sminshall 	if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
62230043Sminshall 	    max_changes_before_poll = 1920;
62330043Sminshall 	} else {
62430043Sminshall 	    max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
62530043Sminshall 	    if (max_changes_before_poll < 40) {
62630043Sminshall 		max_changes_before_poll = 40;
62730043Sminshall 	    }
62830043Sminshall 	    TryToSend = SlowScreen;
62930043Sminshall 	    HaveInput = 1;		/* get signals going */
63030043Sminshall 	}
63130043Sminshall #endif	/* defined(unix) && defined(SLOWSCREEN) */
63230043Sminshall 	setcommandmode();
63330043Sminshall 	/*
63430043Sminshall 	 * By now, initscr() (in curses) has been called (from telnet.c),
63530043Sminshall 	 * and the screen has been initialized.
63630043Sminshall 	 */
63730043Sminshall #if defined(unix)
63830043Sminshall 	nonl();
63930043Sminshall 			/* the problem is that curses catches SIGTSTP to
64030043Sminshall 			 * be nice, but it messes us up.
64130043Sminshall 			 */
64230043Sminshall 	signal(SIGTSTP, SIG_DFL);
64330043Sminshall 	if ((KS = tgetstr("ks", &lotsofspace)) != 0) {
64430043Sminshall 	    KS = strsave(KS);
64530043Sminshall 	    StringToTerminal(KS);
64630043Sminshall 	}
64730043Sminshall 	if ((KE = tgetstr("ke", &lotsofspace)) != 0) {
64830043Sminshall 	    KE = strsave(KE);
64930043Sminshall 	}
65030043Sminshall 	if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
65130043Sminshall 	   SO = strsave(tgetstr("md", &lotsofspace));
65230043Sminshall 	   SE = strsave(tgetstr("me", &lotsofspace));
65330043Sminshall 	}
65430043Sminshall #endif
65530043Sminshall 	DoARefresh();
65630043Sminshall 	setconnmode();
65730043Sminshall 	if (VB && *VB) {
65830043Sminshall 	    bellSequence = VB;		/* use visual bell */
65930043Sminshall 	}
66030043Sminshall 	screenInitd = 1;
66130043Sminshall 	screenStopped = 0;		/* Not stopped */
66230043Sminshall     }
66330043Sminshall }
66430043Sminshall 
66530043Sminshall 
66630043Sminshall /* StopScreen - called when we are going away... */
66730043Sminshall 
66830043Sminshall void
66930043Sminshall StopScreen(doNewLine)
67030043Sminshall int doNewLine;
67130043Sminshall {
67230043Sminshall     if (screenInitd && !screenStopped) {
67330043Sminshall 	move(NumberLines-1, 1);
67430043Sminshall 	standend();
67530043Sminshall #if	defined(SLOWSCREEN)
67630043Sminshall 	inHighlightMode = 0;
67730043Sminshall #endif	/* defined(SLOWSCREEN) */
67830043Sminshall 	DoARefresh();
67930043Sminshall 	setcommandmode();
68030043Sminshall 	endwin();
68130043Sminshall 	setconnmode();
68230043Sminshall #if	defined(unix)
68330043Sminshall 	if (KE) {
68430043Sminshall 	    StringToTerminal(KE);
68530043Sminshall 	}
68630043Sminshall #endif	/* defined(unix) */
68730043Sminshall 	if (doNewLine) {
68830043Sminshall 	    StringToTerminal("\r\n");
68930043Sminshall 	}
69030043Sminshall 	EmptyTerminal();
69130043Sminshall 	screenStopped = 1;		/* This is stopped */
69230043Sminshall     }
69330043Sminshall }
69430043Sminshall 
69530043Sminshall 
69630043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
69730043Sminshall 
69830043Sminshall void
69930043Sminshall RefreshScreen()
70030043Sminshall {
70130043Sminshall     clearok(curscr, TRUE);
70230043Sminshall     (*TryToSend)();
70330043Sminshall }
70430043Sminshall 
70530043Sminshall 
70630043Sminshall /* ConnectScreen - called to reconnect to the screen */
70730043Sminshall 
70830043Sminshall void
70930043Sminshall ConnectScreen()
71030043Sminshall {
71130043Sminshall     if (screenInitd) {
71230043Sminshall #if	defined(unix)
71330043Sminshall 	if (KS) {
71430043Sminshall 	    StringToTerminal(KS);
71530043Sminshall 	}
71630043Sminshall #endif	/* defined(unix) */
71730043Sminshall 	RefreshScreen();
71830043Sminshall 	(*TryToSend)();
71930043Sminshall 	screenStopped = 0;
72030043Sminshall     }
72130043Sminshall }
72230043Sminshall 
72330043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
72430043Sminshall 
72530043Sminshall void
72630043Sminshall LocalClearScreen()
72730043Sminshall {
72830043Sminshall     outputPurge();		/* flush all data to terminal */
72930043Sminshall     clear();			/* clear in curses */
73030043Sminshall #if	defined(SLOWSCREEN)
73130043Sminshall     bzero((char *)Terminal, sizeof Terminal);
73230043Sminshall #endif	/* defined(SLOWSCREEN) */
73330043Sminshall     Clear3270();
73430043Sminshall     Lowest = HighestScreen()+1; /* everything in sync... */
73530043Sminshall     Highest = LowestScreen()+1;
73630043Sminshall }
73730043Sminshall 
73830043Sminshall 
73930043Sminshall void
74030043Sminshall BellOff()
74130043Sminshall {
74230043Sminshall     if (bellwinup) {
74330043Sminshall 	delwin(bellwin);
74430043Sminshall 	bellwin = 0;
74530043Sminshall 	bellwinup = 0;
74630043Sminshall 	Lowest = MIN(Lowest, LINES/2);
74730043Sminshall 	Highest = MAX(Highest, (LINES/2)+3);
74830043Sminshall #if	defined(SLOWSCREEN)
74930043Sminshall 	bzero(Terminal+LINES/2, (sizeof Terminal[0])*(3*COLS));
75030043Sminshall #endif	/* defined(SLOWSCREEN) */
75130043Sminshall 	touchwin(stdscr);
75230043Sminshall 	DoARefresh();
75330043Sminshall     }
75430043Sminshall }
75530043Sminshall 
75630043Sminshall 
75730043Sminshall void
75830043Sminshall RingBell(s)
75930043Sminshall char *s;
76030043Sminshall {
76130043Sminshall     needToRing = 1;
76230043Sminshall     if (s) {
76330043Sminshall 	int len = strlen(s);
76430043Sminshall 
76530043Sminshall 	if (len > COLS-2) {
76630043Sminshall 	    len = COLS-2;
76730043Sminshall 	}
76830043Sminshall 	if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
76930043Sminshall 	    OurExitString(stderr, "Error from newwin in RingBell", 1);
77030043Sminshall 	}
77130043Sminshall 	werase(bellwin);
77230043Sminshall 	wstandout(bellwin);
77330043Sminshall 	box(bellwin, '|', '-');
77430043Sminshall 	if (wmove(bellwin, 1, 1) == ERR) {
77530043Sminshall 	    OurExitString(stderr, "Error from wmove in RingBell", 1);
77630043Sminshall 	}
77730043Sminshall 	while (len--) {
77830043Sminshall 	    if (waddch(bellwin, *s++) == ERR) {
77930043Sminshall 		OurExitString(stderr, "Error from waddch in RingBell", 1);
78030043Sminshall 	    }
78130043Sminshall 	}
78230043Sminshall 	wstandend(bellwin);
78330043Sminshall 	if (wrefresh(bellwin) == ERR) {
78430043Sminshall 	    OurExitString(stderr, "Error from wrefresh in RingBell", 1);
78530043Sminshall 	}
78630043Sminshall 	bellwinup = 1;
78730043Sminshall     }
78830043Sminshall }
78930043Sminshall 
79030043Sminshall 
79130043Sminshall /* returns a 1 if no more output available (so, go ahead and block),
79230043Sminshall     or a 0 if there is more output available (so, just poll the other
79330043Sminshall     sources/destinations, don't block).
79430043Sminshall  */
79530043Sminshall 
79630043Sminshall int
79730043Sminshall DoTerminalOutput()
79830043Sminshall {
79930043Sminshall 	/* called just before a select to conserve IO to terminal */
80030043Sminshall     if (Initialized &&
80130043Sminshall 	    ((Lowest <= Highest) || needToRing ||
80230043Sminshall 			(terminalCursorAddress != CorrectTerminalCursor()))) {
80330043Sminshall 	(*TryToSend)();
80430043Sminshall     }
80530043Sminshall     if (Lowest > Highest) {
80630043Sminshall 	return(1);		/* no more output now */
80730043Sminshall     } else {
80830043Sminshall 	return(0);		/* more output for future */
80930043Sminshall     }
81030043Sminshall }
811*30074Sminshall 
812*30074Sminshall /*
813*30074Sminshall  * The following are defined to handle transparent data.
814*30074Sminshall  */
815*30074Sminshall 
816*30074Sminshall void
817*30074Sminshall TransStop()
818*30074Sminshall {
819*30074Sminshall #if	defined(unix)
820*30074Sminshall     if (tcflag == 0) {
821*30074Sminshall        tcflag = -1;
822*30074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
823*30074Sminshall     } else if (tcflag > 0) {
824*30074Sminshall        setcommandmode();
825*30074Sminshall        (void) close(tin);
826*30074Sminshall        (void) close(tout);
827*30074Sminshall        tin = savefd[0];
828*30074Sminshall        tout = savefd[1];
829*30074Sminshall        setconnmode();
830*30074Sminshall        tcflag = -1;
831*30074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
832*30074Sminshall     }
833*30074Sminshall #endif	/* defined(unix) */
834*30074Sminshall     RefreshScreen();
835*30074Sminshall }
836*30074Sminshall 
837*30074Sminshall void
838*30074Sminshall TransOut(buffer, count)
839*30074Sminshall unsigned char	*buffer;
840*30074Sminshall int		count;
841*30074Sminshall {
842*30074Sminshall #if	defined(unix)
843*30074Sminshall     extern char *transcom;
844*30074Sminshall     int inpipefd[2], outpipefd[2], savemode;
845*30074Sminshall     void aborttc();
846*30074Sminshall #endif	/* defined(unix) */
847*30074Sminshall 
848*30074Sminshall     while (DoTerminalOutput() == 0) {
849*30074Sminshall #if defined(unix)
850*30074Sminshall 	HaveInput = 0;
851*30074Sminshall #endif /* defined(unix) */
852*30074Sminshall     }
853*30074Sminshall #if	defined(unix)
854*30074Sminshall     if (transcom && tcflag == -1) {
855*30074Sminshall        while (1) {			  /* go thru once */
856*30074Sminshall 	     if (pipe(outpipefd) < 0) {
857*30074Sminshall 		break;
858*30074Sminshall 	     }
859*30074Sminshall 	     if (pipe(inpipefd) < 0) {
860*30074Sminshall 		break;
861*30074Sminshall 	     }
862*30074Sminshall 	     if ((tcflag = fork()) == 0) {
863*30074Sminshall 		(void) close(outpipefd[1]);
864*30074Sminshall 		(void) close(0);
865*30074Sminshall 		if (dup(outpipefd[0]) < 0) {
866*30074Sminshall 		   exit(1);
867*30074Sminshall 		}
868*30074Sminshall 		(void) close(outpipefd[0]);
869*30074Sminshall 		(void) close(inpipefd[0]);
870*30074Sminshall 		(void) close(1);
871*30074Sminshall 		if (dup(inpipefd[1]) < 0) {
872*30074Sminshall 		   exit(1);
873*30074Sminshall 		}
874*30074Sminshall 		(void) close(inpipefd[1]);
875*30074Sminshall 		if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
876*30074Sminshall 		    exit(1);
877*30074Sminshall 		}
878*30074Sminshall 	     }
879*30074Sminshall 	     (void) close(inpipefd[1]);
880*30074Sminshall 	     (void) close(outpipefd[0]);
881*30074Sminshall 	     savefd[0] = tin;
882*30074Sminshall 	     savefd[1] = tout;
883*30074Sminshall 	     setcommandmode();
884*30074Sminshall 	     tin = inpipefd[0];
885*30074Sminshall 	     tout = outpipefd[1];
886*30074Sminshall 	     (void) signal(SIGCHLD, aborttc);
887*30074Sminshall 	     setconnmode();
888*30074Sminshall 	     tcflag = 1;
889*30074Sminshall 	     break;
890*30074Sminshall        }
891*30074Sminshall        if (tcflag < 1) {
892*30074Sminshall 	  tcflag = 0;
893*30074Sminshall        }
894*30074Sminshall     }
895*30074Sminshall #endif	/* defined(unix) */
896*30074Sminshall     (void) DataToTerminal(buffer, count);
897*30074Sminshall }
898*30074Sminshall 
899*30074Sminshall 
900*30074Sminshall #if	defined(unix)
901*30074Sminshall static void
902*30074Sminshall aborttc()
903*30074Sminshall {
904*30074Sminshall 	int savemode;
905*30074Sminshall 
906*30074Sminshall 	setcommandmode();
907*30074Sminshall 	(void) close(tin);
908*30074Sminshall 	(void) close(tout);
909*30074Sminshall 	tin = savefd[0];
910*30074Sminshall 	tout = savefd[1];
911*30074Sminshall 	setconnmode();
912*30074Sminshall 	tcflag = 0;
913*30074Sminshall }
914*30074Sminshall #endif	/* defined(unix) */
915