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>
2831120Sminshall #include <dos.h>
2931105Sminshall #include "../general.h"
3031105Sminshall 
3131105Sminshall #include "../telnet.ext"
3231105Sminshall 
3331105Sminshall #include "../ctlr/hostctlr.h"
3431105Sminshall #include "../ctlr/inbound.ext"
3531117Sminshall #include "../ctlr/oia.h"
3631105Sminshall #include "../ctlr/options.ext"
3731105Sminshall #include "../ctlr/outbound.ext"
3831105Sminshall #include "../ctlr/screen.h"
3931105Sminshall 
4031105Sminshall #include "../keyboard/map3270.ext"
4131105Sminshall 
4231105Sminshall #include "../system/globals.h"
4331105Sminshall 
4431120Sminshall #include "video.h"
4531120Sminshall 
4631105Sminshall extern void EmptyTerminal();
4731105Sminshall 
4831105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
4931105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
5031105Sminshall 
5131105Sminshall 
5231105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
5331105Sminshall static int screenInitd; 		/* the screen has been initialized */
5431105Sminshall static int screenStopped;		/* the screen has been stopped */
5531105Sminshall 
5631105Sminshall static int needToRing;			/* need to ring terinal bell */
5731105Sminshall 
5831117Sminshall typedef struct {
5931117Sminshall     char
6031117Sminshall 	data,		/* The data for this position */
6131117Sminshall 	attr;		/* The attributes for this position */
6231117Sminshall } ScreenBuffer;
6331105Sminshall 
6431117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
6531120Sminshall ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
6631105Sminshall 
6731105Sminshall /* Variables for transparent mode */
6831105Sminshall 
6931105Sminshall #include "disp_asc.out"
7031105Sminshall 
7131105Sminshall 
7231105Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
7331105Sminshall 
7431105Sminshall static void
7531105Sminshall OurExitString(file, string, value)
7631105Sminshall FILE	*file;
7731105Sminshall char	*string;
7831105Sminshall int	value;
7931105Sminshall {
8031105Sminshall     static int recursion = 0;
8131105Sminshall 
8231105Sminshall     if (!recursion) {
8331105Sminshall 	recursion = 1;
8431105Sminshall 	ExitString(file, string, value);
8531105Sminshall     }
8631105Sminshall }
8731105Sminshall 
8831105Sminshall 
8931105Sminshall static void
9031105Sminshall GoAway(from, where)
9131105Sminshall char *from;		/* routine that gave error */
9231105Sminshall int	where;		/* cursor address */
9331105Sminshall {
9431105Sminshall 	char foo[100];
9531105Sminshall 
9631105Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
9731105Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
9831105Sminshall 	OurExitString(stderr, foo, 1);
9931105Sminshall 	/* NOTREACHED */
10031105Sminshall }
10131105Sminshall 
10231120Sminshall /*
10331120Sminshall  * Routines to deal with the screen.  These routines are lifted
10431120Sminshall  * from mskermit.
10531120Sminshall  */
10631120Sminshall 
10731120Sminshall #define	CRT_STATUS	0x3da		/* Color card */
10831120Sminshall #define	DISPLAY_ENABLE	0x08		/* Enable */
10931120Sminshall #define	scrseg()	((crt_mode == 7)? 0xb000 : 0xb800)
11031120Sminshall #define	scrwait()	if (crt_mode != 7) { \
11131120Sminshall 			    while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
11231120Sminshall 				; \
11331120Sminshall 			    } \
11431120Sminshall 			}
11531120Sminshall static int
11631120Sminshall     		crt_mode,
11731120Sminshall 		crt_cols,
11831120Sminshall 		crt_lins,
11931120Sminshall 		curpage;
12031120Sminshall 
12131120Sminshall /*
12231120Sminshall  * Set the cursor position to where it belongs.
12331120Sminshall  */
12431120Sminshall 
12531105Sminshall static void
12631120Sminshall setcursor(row, column, page)
12731120Sminshall int
12831120Sminshall     row,
12931120Sminshall     column,
13031120Sminshall     page;
13131120Sminshall {
13231120Sminshall     union REGS inregs, outregs;
13331120Sminshall 
13431120Sminshall     inregs.h.dh = row;
13531120Sminshall     inregs.h.dl = column;
13631120Sminshall     inregs.h.bh = page;
13731120Sminshall     inregs.h.ah = SetCursorPosition;
13831120Sminshall 
13931120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
14031120Sminshall }
14131120Sminshall /*
14231120Sminshall  * Read the state of the video system.  Put the cursor somewhere
14331120Sminshall  * reasonable.
14431120Sminshall  */
14531120Sminshall 
14631120Sminshall static void
14731120Sminshall scrini()
14831120Sminshall {
14931120Sminshall     union REGS inregs, outregs;
15031120Sminshall 
15131120Sminshall     inregs.h.ah = CurrentVideoState;
15231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
15331120Sminshall 
15431120Sminshall     crt_mode = outregs.h.al;
15531120Sminshall     crt_cols = outregs.h.ah;
15631120Sminshall     crt_lins = 25;
15731120Sminshall     curpage = outregs.h.bh;
15831120Sminshall 
15931120Sminshall     inregs.h.ah = ReadCursorPosition;
16031120Sminshall     inregs.h.bh = curpage;
16131120Sminshall 
16231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
16331120Sminshall 
16431120Sminshall     if (outregs.h.dh > crt_lins) {
16531120Sminshall 	outregs.h.dh = crt_lins;
16631120Sminshall     }
16731120Sminshall     if (outregs.h.dl > crt_cols) {
16831120Sminshall 	outregs.h.dl = crt_cols;
16931120Sminshall     }
17031120Sminshall     inregs.h.dh = outregs.h.dh;
17131120Sminshall     inregs.h.dl = outregs.h.dl;
17231120Sminshall     inregs.h.bh = curpage;
17331120Sminshall 
17431120Sminshall     inregs.h.ah = SetCursorPosition;
17531120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
17631120Sminshall }
17731120Sminshall 
17831120Sminshall 
17931120Sminshall static void
18031120Sminshall scrwrite(source, length, offset)
18131120Sminshall ScreenBuffer *source;
18231120Sminshall int
18331120Sminshall 	length,
18431120Sminshall 	offset;
18531120Sminshall {
18631120Sminshall     struct SREGS segregs;
18731120Sminshall 
18831120Sminshall     segread(&segregs);		/* read the current segment register */
18931120Sminshall 
19031120Sminshall     scrwait();
19131120Sminshall     movedata(segregs.ds, source, scrseg(), offset, length);
19231120Sminshall }
19331120Sminshall 
19431120Sminshall static void
19531120Sminshall scrsave(buffer)
19631120Sminshall ScreenBuffer *buffer;
19731120Sminshall {
19831120Sminshall     struct SREGS segregs;
19931120Sminshall 
20031120Sminshall     segread(&segregs);		/* read the current segment register */
20131120Sminshall 
20231120Sminshall     scrwait();
20331120Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, scrseg(), 0, crt_cols*crt_lins*2);
20431120Sminshall }
20531120Sminshall 
20631120Sminshall static void
20731120Sminshall scrrest(buffer)
20831120Sminshall ScreenBuffer *buffer;
20931120Sminshall {
21031120Sminshall     scrwrite(buffer, 2*crt_cols*crt_lins, 0);
21131120Sminshall }
21231120Sminshall 
21331120Sminshall static void
21431117Sminshall TryToSend()
21531105Sminshall {
21631117Sminshall #define	STANDOUT	0x0a
21731117Sminshall #define	NORMAL		0x02	/* Normal mode */
21831105Sminshall 
21931105Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
22031117Sminshall 				a = STANDOUT; \
22131105Sminshall 			    } else { \
22231117Sminshall 				a = NORMAL; \
22331105Sminshall 			    } \
22431105Sminshall 			    if (IsNonDisplayAttr(a)) { \
22531105Sminshall 				a = 0; 	/* zero == don't display */ \
22631105Sminshall 			    } \
22731105Sminshall 			    if (!FormattedScreen()) { \
22831105Sminshall 				a = 1;	/* one ==> do display on unformatted */\
22931105Sminshall 			    }
23031105Sminshall     ScreenImage *p, *upper;
23131117Sminshall     ScreenBuffer *sp;
23231105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
23331105Sminshall 
23431105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
23531105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
23631105Sminshall  * field in the middle, we do the whole screen.
23731105Sminshall  *
23831105Sminshall  * In particular, we separate out the two cases from the beginning.
23931105Sminshall  */
24031105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
24131105Sminshall 	register int columnsleft;
24231105Sminshall 
24331117Sminshall 	sp = &Screen[Lowest];
24431105Sminshall 	p = &Host[Lowest];
24531105Sminshall 	upper = &Host[Highest];
24631105Sminshall 	fieldattr = FieldAttributes(Lowest);
24731105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
24831105Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
24931105Sminshall 
25031105Sminshall 	while (p <= upper) {
25131105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
25231105Sminshall 		Highest = HighestScreen();
25331105Sminshall 		Lowest = LowestScreen();
25431117Sminshall 		TryToSend();		/* Recurse */
25531105Sminshall 		return;
25631105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
25731117Sminshall 		sp->data = disp_asc[p->data];	/* Display translated data */
25831117Sminshall 		sp->attr = fieldattr;
25931105Sminshall 	    } else {
26031117Sminshall 		sp->data = ' ';
26131117Sminshall 		sp->attr = NORMAL;
26231105Sminshall 	    }
26331105Sminshall 			/* If the physical screen is larger than what we
26431105Sminshall 			 * are using, we need to make sure that each line
26531105Sminshall 			 * starts at the beginning of the line.  Otherwise,
26631105Sminshall 			 * we will just string all the lines together.
26731105Sminshall 			 */
26831105Sminshall 	    p++;
26931117Sminshall 	    sp++;
27031105Sminshall 	}
27131105Sminshall     } else {		/* Going from Lowest to Highest */
27231117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
27331105Sminshall 
27431117Sminshall 	sp = Screen;
27531105Sminshall 	p = Host;
27631105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
27731105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
27831105Sminshall 
27931105Sminshall 	while (p <= End) {
28031105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
28131105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
28231105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
28331105Sminshall 	    } else {
28431105Sminshall 		if (fieldattr) {	/* Should we display? */
28531105Sminshall 				/* Display translated data */
28631117Sminshall 		    sp->data = disp_asc[p->data];
28731117Sminshall 		    sp->attr = fieldattr;
28831105Sminshall 		} else {
28931117Sminshall 		    sp->data = ' ';
29031117Sminshall 		    sp->attr = NORMAL;
29131105Sminshall 		}
29231105Sminshall 	    }
29331105Sminshall 			/* If the physical screen is larger than what we
29431105Sminshall 			 * are using, we need to make sure that each line
29531105Sminshall 			 * starts at the beginning of the line.  Otherwise,
29631105Sminshall 			 * we will just string all the lines together.
29731105Sminshall 			 */
29831105Sminshall 	    p++;
29931117Sminshall 	    sp++;
30031105Sminshall 	}
30131105Sminshall     }
30231117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
30331117Sminshall     scrwrite(Screen+Lowest, sizeof Screen[0]*(Highest-Lowest), Lowest);
30431120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
30531117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
30631105Sminshall     Lowest = HighestScreen()+1;
30731105Sminshall     Highest = LowestScreen()-1;
30831105Sminshall     if (needToRing) {
30931117Sminshall 	DataToTerminal("\7", 1);
31031105Sminshall 	needToRing = 0;
31131105Sminshall     }
31231105Sminshall     return;
31331105Sminshall }
31431105Sminshall 
31531105Sminshall /* InitTerminal - called to initialize the screen, etc. */
31631105Sminshall 
31731105Sminshall void
31831105Sminshall InitTerminal()
31931105Sminshall {
32031105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
32131105Sminshall     if (!screenInitd) { 	/* not initialized */
322*31129Sminshall 	MaxNumberLines = 24;	/* XXX */
323*31129Sminshall 	MaxNumberColumns = 80;	/* XXX */
32431117Sminshall 	scrini();
32531120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
32631117Sminshall 	ClearArray(Screen);
32731105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
32831105Sminshall 	screenInitd = 1;
32931105Sminshall 	screenStopped = 0;		/* Not stopped */
33031105Sminshall     }
33131105Sminshall     Initialized = 1;
33231105Sminshall }
33331105Sminshall 
33431105Sminshall 
33531105Sminshall /* StopScreen - called when we are going away... */
33631105Sminshall 
33731105Sminshall void
33831105Sminshall StopScreen(doNewLine)
33931105Sminshall int doNewLine;
34031105Sminshall {
34131105Sminshall     if (screenInitd && !screenStopped) {
34231120Sminshall 	scrrest(saveScreen);
34331120Sminshall 	setcursor(NumberLines-1, NumberColumns-1, 0);
34431105Sminshall     }
34531105Sminshall }
34631105Sminshall 
34731105Sminshall 
34831105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
34931105Sminshall 
35031105Sminshall void
35131105Sminshall RefreshScreen()
35231105Sminshall {
35331117Sminshall     Highest = HighestScreen();
35431117Sminshall     Lowest = LowestScreen();
35531117Sminshall     TryToSend();
35631105Sminshall }
35731105Sminshall 
35831105Sminshall 
35931105Sminshall /* ConnectScreen - called to reconnect to the screen */
36031105Sminshall 
36131105Sminshall void
36231105Sminshall ConnectScreen()
36331105Sminshall {
36431105Sminshall     if (screenInitd) {
36531105Sminshall 	RefreshScreen();
36631105Sminshall 	screenStopped = 0;
36731105Sminshall     }
36831105Sminshall }
36931105Sminshall 
37031105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
37131105Sminshall 
37231105Sminshall void
37331105Sminshall LocalClearScreen()
37431105Sminshall {
37531105Sminshall     Clear3270();
37631117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
37731117Sminshall     Highest = HighestScreen();
37831117Sminshall     TryToSend();
37931105Sminshall }
38031117Sminshall 
38131117Sminshall /*
38231117Sminshall  * Implement the bell/error message function.
38331117Sminshall  */
38431105Sminshall 
38531117Sminshall int
38631117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
38731117Sminshall static int
38831117Sminshall 	bellpos0 = 0;		/* Where error message goes */
38931105Sminshall 
39031117Sminshall static char	bellstring[100];/* Where message goes */
39131117Sminshall 
39231117Sminshall #define	BELL_SPACES	2	/* 2 spaces between border and bell */
39331117Sminshall 
39431117Sminshall #define	BELL_HIGH_LOW(h,l) { \
39531117Sminshall 	    h = bellpos0+2*NumberColumns+bellwinup+BELL_SPACES*2; \
39631117Sminshall 	    l = bellpos0; \
39731117Sminshall 	}
39831117Sminshall 
39931105Sminshall void
40031105Sminshall BellOff()
40131105Sminshall {
40231105Sminshall     if (bellwinup) {
40331117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
40431117Sminshall 	TryToSend();
40531105Sminshall     }
40631105Sminshall }
40731105Sminshall 
40831105Sminshall 
40931105Sminshall void
41031105Sminshall RingBell(s)
41131105Sminshall char *s;
41231105Sminshall {
41331105Sminshall     needToRing = 1;
41431105Sminshall     if (s) {
41531105Sminshall 	int len = strlen(s);
41631105Sminshall 
41731117Sminshall 	if (len > sizeof bellstring-1) {
41831117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
41931105Sminshall 	}
42031117Sminshall 	memcpy(bellstring, s, len+1);
42131117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
42231117Sminshall 	TryToSend();
42331105Sminshall     }
42431105Sminshall }
42531105Sminshall 
42631117Sminshall /*
42731117Sminshall  * Update the OIA area.
42831117Sminshall  */
42931105Sminshall 
43031117Sminshall void
43131117Sminshall ScreenOIA(oia)
43231117Sminshall OIA *oia;
43331117Sminshall {
43431117Sminshall }
43531117Sminshall 
43631117Sminshall 
43731105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
43831105Sminshall     or a 0 if there is more output available (so, just poll the other
43931105Sminshall     sources/destinations, don't block).
44031105Sminshall  */
44131105Sminshall 
44231105Sminshall int
44331105Sminshall DoTerminalOutput()
44431105Sminshall {
44531105Sminshall 	/* called just before a select to conserve IO to terminal */
44631105Sminshall     if (!Initialized) {
44731105Sminshall 	return 1;		/* No output if not initialized */
44831105Sminshall     }
44931105Sminshall     if ((Lowest <= Highest) || needToRing ||
45031105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
45131117Sminshall 	TryToSend();
45231105Sminshall     }
45331105Sminshall     if (Lowest > Highest) {
45431105Sminshall 	return 1;		/* no more output now */
45531105Sminshall     } else {
45631105Sminshall 	return 0;		/* more output for future */
45731105Sminshall     }
45831105Sminshall }
45931105Sminshall 
46031105Sminshall /*
46131105Sminshall  * The following are defined to handle transparent data.
46231105Sminshall  */
46331105Sminshall 
46431105Sminshall void
46531105Sminshall TransStop()
46631105Sminshall {
46731105Sminshall     RefreshScreen();
46831105Sminshall }
46931105Sminshall 
47031105Sminshall void
47131105Sminshall TransOut(buffer, count)
47231105Sminshall unsigned char	*buffer;
47331105Sminshall int		count;
47431105Sminshall {
47531105Sminshall 
47631105Sminshall     while (DoTerminalOutput() == 0) {
47731117Sminshall 	;
47831105Sminshall     }
47931105Sminshall     (void) DataToTerminal(buffer, count);
48031105Sminshall }
48131117Sminshall 
48231117Sminshall /*
48331117Sminshall  * init_screen()
48431117Sminshall  *
48531117Sminshall  * Initialize variables used by screen.
48631117Sminshall  */
48731105Sminshall 
48831117Sminshall void
48931117Sminshall init_screen()
49031105Sminshall {
49131117Sminshall     bellwinup = 0;
49231117Sminshall }
49331105Sminshall 
49431117Sminshall 
495