131105Sminshall /*
231105Sminshall  *	Copyright (c) 1984, 1985, 1986 by the Regents of the
331105Sminshall  *	University of California and by Gregory Glenn Minshall.
431105Sminshall  *
531105Sminshall  *	Permission to use, copy, modify, and distribute these
631105Sminshall  *	programs and their documentation for any purpose and
731105Sminshall  *	without fee is hereby granted, provided that this
831105Sminshall  *	copyright and permission appear on all copies and
931105Sminshall  *	supporting documentation, the name of the Regents of
1031105Sminshall  *	the University of California not be used in advertising
1131105Sminshall  *	or publicity pertaining to distribution of the programs
1231105Sminshall  *	without specific prior permission, and notice be given in
1331105Sminshall  *	supporting documentation that copying and distribution is
1431105Sminshall  *	by permission of the Regents of the University of California
1531105Sminshall  *	and by Gregory Glenn Minshall.  Neither the Regents of the
1631105Sminshall  *	University of California nor Gregory Glenn Minshall make
1731105Sminshall  *	representations about the suitability of this software
1831105Sminshall  *	for any purpose.  It is provided "as is" without
1931105Sminshall  *	express or implied warranty.
2031105Sminshall  */
2131105Sminshall 
2231105Sminshall #ifndef lint
2331105Sminshall static	char	sccsid[] = "@(#)outbound.c	3.1  10/29/86";
2431105Sminshall #endif	/* lint */
2531105Sminshall 
2631105Sminshall 
2731105Sminshall #include <stdio.h>
2831105Sminshall #include "../general.h"
2931105Sminshall 
3031105Sminshall #include "../telnet.ext"
3131105Sminshall 
3231105Sminshall #include "../ctlr/hostctlr.h"
3331105Sminshall #include "../ctlr/inbound.ext"
34*31117Sminshall #include "../ctlr/oia.h"
3531105Sminshall #include "../ctlr/options.ext"
3631105Sminshall #include "../ctlr/outbound.ext"
3731105Sminshall #include "../ctlr/screen.h"
3831105Sminshall 
3931105Sminshall #include "../keyboard/map3270.ext"
4031105Sminshall 
4131105Sminshall #include "../system/globals.h"
4231105Sminshall 
4331105Sminshall extern void EmptyTerminal();
4431105Sminshall 
4531105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
4631105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
4731105Sminshall 
4831105Sminshall 
4931105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
5031105Sminshall static int screenInitd; 		/* the screen has been initialized */
5131105Sminshall static int screenStopped;		/* the screen has been stopped */
5231105Sminshall 
5331105Sminshall static int needToRing;			/* need to ring terinal bell */
5431105Sminshall 
55*31117Sminshall typedef struct {
56*31117Sminshall     char
57*31117Sminshall 	data,		/* The data for this position */
58*31117Sminshall 	attr;		/* The attributes for this position */
59*31117Sminshall } ScreenBuffer;
6031105Sminshall 
61*31117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
6231105Sminshall 
6331105Sminshall /* Variables for transparent mode */
6431105Sminshall 
6531105Sminshall #include "disp_asc.out"
6631105Sminshall 
6731105Sminshall 
6831105Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
6931105Sminshall 
7031105Sminshall static void
7131105Sminshall OurExitString(file, string, value)
7231105Sminshall FILE	*file;
7331105Sminshall char	*string;
7431105Sminshall int	value;
7531105Sminshall {
7631105Sminshall     static int recursion = 0;
7731105Sminshall 
7831105Sminshall     if (!recursion) {
7931105Sminshall 	recursion = 1;
8031105Sminshall 	ExitString(file, string, value);
8131105Sminshall     }
8231105Sminshall }
8331105Sminshall 
8431105Sminshall 
8531105Sminshall static void
8631105Sminshall GoAway(from, where)
8731105Sminshall char *from;		/* routine that gave error */
8831105Sminshall int	where;		/* cursor address */
8931105Sminshall {
9031105Sminshall 	char foo[100];
9131105Sminshall 
9231105Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
9331105Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
9431105Sminshall 	OurExitString(stderr, foo, 1);
9531105Sminshall 	/* NOTREACHED */
9631105Sminshall }
9731105Sminshall 
9831105Sminshall static void
99*31117Sminshall TryToSend()
10031105Sminshall {
101*31117Sminshall #define	STANDOUT	0x0a
102*31117Sminshall #define	NORMAL		0x02	/* Normal mode */
10331105Sminshall 
10431105Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
105*31117Sminshall 				a = STANDOUT; \
10631105Sminshall 			    } else { \
107*31117Sminshall 				a = NORMAL; \
10831105Sminshall 			    } \
10931105Sminshall 			    if (IsNonDisplayAttr(a)) { \
11031105Sminshall 				a = 0; 	/* zero == don't display */ \
11131105Sminshall 			    } \
11231105Sminshall 			    if (!FormattedScreen()) { \
11331105Sminshall 				a = 1;	/* one ==> do display on unformatted */\
11431105Sminshall 			    }
11531105Sminshall     ScreenImage *p, *upper;
116*31117Sminshall     ScreenBuffer *sp;
11731105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
11831105Sminshall 
11931105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
12031105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
12131105Sminshall  * field in the middle, we do the whole screen.
12231105Sminshall  *
12331105Sminshall  * In particular, we separate out the two cases from the beginning.
12431105Sminshall  */
12531105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
12631105Sminshall 	register int columnsleft;
12731105Sminshall 
128*31117Sminshall 	sp = &Screen[Lowest];
12931105Sminshall 	p = &Host[Lowest];
13031105Sminshall 	upper = &Host[Highest];
13131105Sminshall 	fieldattr = FieldAttributes(Lowest);
13231105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
13331105Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
13431105Sminshall 
13531105Sminshall 	while (p <= upper) {
13631105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
13731105Sminshall 		Highest = HighestScreen();
13831105Sminshall 		Lowest = LowestScreen();
139*31117Sminshall 		TryToSend();		/* Recurse */
14031105Sminshall 		return;
14131105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
142*31117Sminshall 		sp->data = disp_asc[p->data];	/* Display translated data */
143*31117Sminshall 		sp->attr = fieldattr;
14431105Sminshall 	    } else {
145*31117Sminshall 		sp->data = ' ';
146*31117Sminshall 		sp->attr = NORMAL;
14731105Sminshall 	    }
14831105Sminshall 			/* If the physical screen is larger than what we
14931105Sminshall 			 * are using, we need to make sure that each line
15031105Sminshall 			 * starts at the beginning of the line.  Otherwise,
15131105Sminshall 			 * we will just string all the lines together.
15231105Sminshall 			 */
15331105Sminshall 	    p++;
154*31117Sminshall 	    sp++;
15531105Sminshall 	}
15631105Sminshall     } else {		/* Going from Lowest to Highest */
157*31117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
15831105Sminshall 
159*31117Sminshall 	sp = Screen;
16031105Sminshall 	p = Host;
16131105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
16231105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
16331105Sminshall 
16431105Sminshall 	while (p <= End) {
16531105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
16631105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
16731105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
16831105Sminshall 	    } else {
16931105Sminshall 		if (fieldattr) {	/* Should we display? */
17031105Sminshall 				/* Display translated data */
171*31117Sminshall 		    sp->data = disp_asc[p->data];
172*31117Sminshall 		    sp->attr = fieldattr;
17331105Sminshall 		} else {
174*31117Sminshall 		    sp->data = ' ';
175*31117Sminshall 		    sp->attr = NORMAL;
17631105Sminshall 		}
17731105Sminshall 	    }
17831105Sminshall 			/* If the physical screen is larger than what we
17931105Sminshall 			 * are using, we need to make sure that each line
18031105Sminshall 			 * starts at the beginning of the line.  Otherwise,
18131105Sminshall 			 * we will just string all the lines together.
18231105Sminshall 			 */
18331105Sminshall 	    p++;
184*31117Sminshall 	    sp++;
18531105Sminshall 	}
18631105Sminshall     }
187*31117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
188*31117Sminshall     scrwrite(Screen+Lowest, sizeof Screen[0]*(Highest-Lowest), Lowest);
189*31117Sminshall     VideoSetCursorPosition(ScreenLine(terminalCursorAddress),
190*31117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
19131105Sminshall     Lowest = HighestScreen()+1;
19231105Sminshall     Highest = LowestScreen()-1;
19331105Sminshall     if (needToRing) {
194*31117Sminshall 	DataToTerminal("\7", 1);
19531105Sminshall 	needToRing = 0;
19631105Sminshall     }
19731105Sminshall     return;
19831105Sminshall }
19931105Sminshall 
20031105Sminshall /* InitTerminal - called to initialize the screen, etc. */
20131105Sminshall 
20231105Sminshall void
20331105Sminshall InitTerminal()
20431105Sminshall {
20531105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
20631105Sminshall     if (!screenInitd) { 	/* not initialized */
207*31117Sminshall 	NumberLines = 24;	/* XXX */
208*31117Sminshall 	NumberColumns = 80;	/* XXX */
209*31117Sminshall 	scrini();
210*31117Sminshall 	savescr();		/* Save the screen buffer away */
211*31117Sminshall 	ClearArray(Screen);
21231105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
21331105Sminshall 	screenInitd = 1;
21431105Sminshall 	screenStopped = 0;		/* Not stopped */
21531105Sminshall     }
21631105Sminshall     Initialized = 1;
21731105Sminshall }
21831105Sminshall 
21931105Sminshall 
22031105Sminshall /* StopScreen - called when we are going away... */
22131105Sminshall 
22231105Sminshall void
22331105Sminshall StopScreen(doNewLine)
22431105Sminshall int doNewLine;
22531105Sminshall {
22631105Sminshall     if (screenInitd && !screenStopped) {
227*31117Sminshall 	scrrest();
228*31117Sminshall 	VideoSetCursorPosition(NumberLines-1, NumberColumns-1, 0);
22931105Sminshall     }
23031105Sminshall }
23131105Sminshall 
23231105Sminshall 
23331105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
23431105Sminshall 
23531105Sminshall void
23631105Sminshall RefreshScreen()
23731105Sminshall {
238*31117Sminshall     Highest = HighestScreen();
239*31117Sminshall     Lowest = LowestScreen();
240*31117Sminshall     TryToSend();
24131105Sminshall }
24231105Sminshall 
24331105Sminshall 
24431105Sminshall /* ConnectScreen - called to reconnect to the screen */
24531105Sminshall 
24631105Sminshall void
24731105Sminshall ConnectScreen()
24831105Sminshall {
24931105Sminshall     if (screenInitd) {
25031105Sminshall 	RefreshScreen();
25131105Sminshall 	screenStopped = 0;
25231105Sminshall     }
25331105Sminshall }
25431105Sminshall 
25531105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
25631105Sminshall 
25731105Sminshall void
25831105Sminshall LocalClearScreen()
25931105Sminshall {
26031105Sminshall     Clear3270();
261*31117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
262*31117Sminshall     Highest = HighestScreen();
263*31117Sminshall     TryToSend();
26431105Sminshall }
265*31117Sminshall 
266*31117Sminshall /*
267*31117Sminshall  * Implement the bell/error message function.
268*31117Sminshall  */
26931105Sminshall 
270*31117Sminshall int
271*31117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
272*31117Sminshall static int
273*31117Sminshall 	bellpos0 = 0;		/* Where error message goes */
27431105Sminshall 
275*31117Sminshall static char	bellstring[100];/* Where message goes */
276*31117Sminshall 
277*31117Sminshall #define	BELL_SPACES	2	/* 2 spaces between border and bell */
278*31117Sminshall 
279*31117Sminshall #define	BELL_HIGH_LOW(h,l) { \
280*31117Sminshall 	    h = bellpos0+2*NumberColumns+bellwinup+BELL_SPACES*2; \
281*31117Sminshall 	    l = bellpos0; \
282*31117Sminshall 	}
283*31117Sminshall 
28431105Sminshall void
28531105Sminshall BellOff()
28631105Sminshall {
28731105Sminshall     if (bellwinup) {
288*31117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
289*31117Sminshall 	TryToSend();
29031105Sminshall     }
29131105Sminshall }
29231105Sminshall 
29331105Sminshall 
29431105Sminshall void
29531105Sminshall RingBell(s)
29631105Sminshall char *s;
29731105Sminshall {
29831105Sminshall     needToRing = 1;
29931105Sminshall     if (s) {
30031105Sminshall 	int len = strlen(s);
30131105Sminshall 
302*31117Sminshall 	if (len > sizeof bellstring-1) {
303*31117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
30431105Sminshall 	}
305*31117Sminshall 	memcpy(bellstring, s, len+1);
306*31117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
307*31117Sminshall 	TryToSend();
30831105Sminshall     }
30931105Sminshall }
31031105Sminshall 
311*31117Sminshall /*
312*31117Sminshall  * Update the OIA area.
313*31117Sminshall  */
31431105Sminshall 
315*31117Sminshall void
316*31117Sminshall ScreenOIA(oia)
317*31117Sminshall OIA *oia;
318*31117Sminshall {
319*31117Sminshall }
320*31117Sminshall 
321*31117Sminshall 
32231105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
32331105Sminshall     or a 0 if there is more output available (so, just poll the other
32431105Sminshall     sources/destinations, don't block).
32531105Sminshall  */
32631105Sminshall 
32731105Sminshall int
32831105Sminshall DoTerminalOutput()
32931105Sminshall {
33031105Sminshall 	/* called just before a select to conserve IO to terminal */
33131105Sminshall     if (!Initialized) {
33231105Sminshall 	return 1;		/* No output if not initialized */
33331105Sminshall     }
33431105Sminshall     if ((Lowest <= Highest) || needToRing ||
33531105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
336*31117Sminshall 	TryToSend();
33731105Sminshall     }
33831105Sminshall     if (Lowest > Highest) {
33931105Sminshall 	return 1;		/* no more output now */
34031105Sminshall     } else {
34131105Sminshall 	return 0;		/* more output for future */
34231105Sminshall     }
34331105Sminshall }
34431105Sminshall 
34531105Sminshall /*
34631105Sminshall  * The following are defined to handle transparent data.
34731105Sminshall  */
34831105Sminshall 
34931105Sminshall void
35031105Sminshall TransStop()
35131105Sminshall {
35231105Sminshall     RefreshScreen();
35331105Sminshall }
35431105Sminshall 
35531105Sminshall void
35631105Sminshall TransOut(buffer, count)
35731105Sminshall unsigned char	*buffer;
35831105Sminshall int		count;
35931105Sminshall {
36031105Sminshall 
36131105Sminshall     while (DoTerminalOutput() == 0) {
362*31117Sminshall 	;
36331105Sminshall     }
36431105Sminshall     (void) DataToTerminal(buffer, count);
36531105Sminshall }
366*31117Sminshall 
367*31117Sminshall /*
368*31117Sminshall  * init_screen()
369*31117Sminshall  *
370*31117Sminshall  * Initialize variables used by screen.
371*31117Sminshall  */
37231105Sminshall 
373*31117Sminshall void
374*31117Sminshall init_screen()
37531105Sminshall {
376*31117Sminshall     bellwinup = 0;
377*31117Sminshall }
37831105Sminshall 
379*31117Sminshall 
380