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>
2931185Sminshall #include "../general/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 
4031185Sminshall #include "../ascii/map3270.ext"
4131105Sminshall 
4231185Sminshall #include "../general/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();
19131154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
19231154Sminshall 						sizeof *source*length);
19331120Sminshall }
19431120Sminshall 
19531120Sminshall static void
19631120Sminshall scrsave(buffer)
19731120Sminshall ScreenBuffer *buffer;
19831120Sminshall {
19931120Sminshall     struct SREGS segregs;
20031120Sminshall 
20131120Sminshall     segread(&segregs);		/* read the current segment register */
20231120Sminshall 
20331120Sminshall     scrwait();
20431154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
20531120Sminshall }
20631120Sminshall 
20731120Sminshall static void
20831120Sminshall scrrest(buffer)
20931120Sminshall ScreenBuffer *buffer;
21031120Sminshall {
21131154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
21231120Sminshall }
21331120Sminshall 
21431120Sminshall static void
21531117Sminshall TryToSend()
21631105Sminshall {
21731154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
21831117Sminshall #define	NORMAL		0x02	/* Normal mode */
21931154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
22031105Sminshall 
22131154Sminshall #define	DoAttribute(a) 	    \
22231154Sminshall 			    if (screenIsFormatted) { \
22331154Sminshall 				if (IsNonDisplayAttr(a)) { \
22431154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
22531154Sminshall 				} else if (IsHighlightedAttr(a)) { \
22631154Sminshall 				    a = STANDOUT; \
22731154Sminshall 				} else { \
22831154Sminshall 				    a = NORMAL; \
22931154Sminshall 				} \
23031154Sminshall 			    } else  { \
23131154Sminshall 				a = NORMAL;	/* do display on unformatted */\
23231105Sminshall 			    }
23331105Sminshall     ScreenImage *p, *upper;
23431117Sminshall     ScreenBuffer *sp;
23531105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
23631154Sminshall     int screenIsFormatted = FormattedScreen();
23731105Sminshall 
23831105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
23931105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
24031105Sminshall  * field in the middle, we do the whole screen.
24131105Sminshall  *
24231105Sminshall  * In particular, we separate out the two cases from the beginning.
24331105Sminshall  */
24431105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
24531117Sminshall 	sp = &Screen[Lowest];
24631105Sminshall 	p = &Host[Lowest];
24731105Sminshall 	upper = &Host[Highest];
24831105Sminshall 	fieldattr = FieldAttributes(Lowest);
24931105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
25031105Sminshall 
25131105Sminshall 	while (p <= upper) {
25231105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
25331105Sminshall 		Highest = HighestScreen();
25431105Sminshall 		Lowest = LowestScreen();
25531117Sminshall 		TryToSend();		/* Recurse */
25631105Sminshall 		return;
25731105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
25831154Sminshall 				/* Display translated data */
25931154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
26031105Sminshall 	    } else {
26131117Sminshall 		sp->data = ' ';
26231105Sminshall 	    }
26331154Sminshall 	    sp->attr = fieldattr;
26431105Sminshall 	    p++;
26531117Sminshall 	    sp++;
26631105Sminshall 	}
26731105Sminshall     } else {		/* Going from Lowest to Highest */
26831117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
26931105Sminshall 
27031117Sminshall 	sp = Screen;
27131105Sminshall 	p = Host;
27231105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
27331105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
27431105Sminshall 
27531105Sminshall 	while (p <= End) {
27631105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
27731105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
27831105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
27931154Sminshall 	    }
28031154Sminshall 	    if (fieldattr) {	/* Should we display? */
28131154Sminshall 			    /* Display translated data */
28231154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
28331105Sminshall 	    } else {
28431154Sminshall 		sp->data = ' ';
28531105Sminshall 	    }
28631154Sminshall 	    sp->attr = fieldattr;
28731105Sminshall 	    p++;
28831117Sminshall 	    sp++;
28931105Sminshall 	}
29031105Sminshall     }
29131117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
29231154Sminshall     /*
29331154Sminshall      * We might be here just to update the cursor address.
29431154Sminshall      */
29531154Sminshall     if (Highest >= Lowest) {
29631154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
29731154Sminshall     }
29831120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
29931117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
30031105Sminshall     Lowest = HighestScreen()+1;
30131105Sminshall     Highest = LowestScreen()-1;
30231105Sminshall     if (needToRing) {
30331117Sminshall 	DataToTerminal("\7", 1);
30431105Sminshall 	needToRing = 0;
30531105Sminshall     }
30631105Sminshall     return;
30731105Sminshall }
30831105Sminshall 
30931105Sminshall /* InitTerminal - called to initialize the screen, etc. */
31031105Sminshall 
31131105Sminshall void
31231105Sminshall InitTerminal()
31331105Sminshall {
31431105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
31531105Sminshall     if (!screenInitd) { 	/* not initialized */
31631129Sminshall 	MaxNumberLines = 24;	/* XXX */
31731129Sminshall 	MaxNumberColumns = 80;	/* XXX */
31831117Sminshall 	scrini();
31931120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
32031117Sminshall 	ClearArray(Screen);
32131105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
32231105Sminshall 	screenInitd = 1;
32331105Sminshall 	screenStopped = 0;		/* Not stopped */
32431105Sminshall     }
32531105Sminshall     Initialized = 1;
32631105Sminshall }
32731105Sminshall 
32831105Sminshall 
32931105Sminshall /* StopScreen - called when we are going away... */
33031105Sminshall 
33131105Sminshall void
33231105Sminshall StopScreen(doNewLine)
33331105Sminshall int doNewLine;
33431105Sminshall {
33531105Sminshall     if (screenInitd && !screenStopped) {
33631120Sminshall 	scrrest(saveScreen);
337*31208Sminshall 	setcursor(NumberLines-1, 1, 0);
338*31208Sminshall 	if (doNewLine) {
339*31208Sminshall 	    StringToTerminal("\r\n");
340*31208Sminshall 	}
341*31208Sminshall 	EmptyTerminal();
342*31208Sminshall 	screenStopped = 1;
34331105Sminshall     }
34431105Sminshall }
34531105Sminshall 
34631105Sminshall 
34731105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
34831105Sminshall 
34931105Sminshall void
35031105Sminshall RefreshScreen()
35131105Sminshall {
35231117Sminshall     Highest = HighestScreen();
35331117Sminshall     Lowest = LowestScreen();
35431117Sminshall     TryToSend();
35531105Sminshall }
35631105Sminshall 
35731105Sminshall 
35831105Sminshall /* ConnectScreen - called to reconnect to the screen */
35931105Sminshall 
36031105Sminshall void
36131105Sminshall ConnectScreen()
36231105Sminshall {
36331105Sminshall     if (screenInitd) {
36431105Sminshall 	RefreshScreen();
36531105Sminshall 	screenStopped = 0;
36631105Sminshall     }
36731105Sminshall }
36831105Sminshall 
36931105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
37031105Sminshall 
37131105Sminshall void
37231105Sminshall LocalClearScreen()
37331105Sminshall {
37431105Sminshall     Clear3270();
37531117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
37631117Sminshall     Highest = HighestScreen();
37731117Sminshall     TryToSend();
37831105Sminshall }
37931117Sminshall 
38031117Sminshall /*
38131117Sminshall  * Implement the bell/error message function.
38231117Sminshall  */
38331105Sminshall 
38431117Sminshall int
38531117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
38631117Sminshall static int
38731117Sminshall 	bellpos0 = 0;		/* Where error message goes */
38831105Sminshall 
38931117Sminshall static char	bellstring[100];/* Where message goes */
39031117Sminshall 
39131117Sminshall #define	BELL_SPACES	2	/* 2 spaces between border and bell */
39231117Sminshall 
39331117Sminshall #define	BELL_HIGH_LOW(h,l) { \
39431117Sminshall 	    h = bellpos0+2*NumberColumns+bellwinup+BELL_SPACES*2; \
39531117Sminshall 	    l = bellpos0; \
39631117Sminshall 	}
39731117Sminshall 
39831105Sminshall void
39931105Sminshall BellOff()
40031105Sminshall {
40131105Sminshall     if (bellwinup) {
40231117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
40331117Sminshall 	TryToSend();
40431105Sminshall     }
40531105Sminshall }
40631105Sminshall 
40731105Sminshall 
40831105Sminshall void
40931105Sminshall RingBell(s)
41031105Sminshall char *s;
41131105Sminshall {
41231105Sminshall     needToRing = 1;
41331105Sminshall     if (s) {
41431105Sminshall 	int len = strlen(s);
41531105Sminshall 
41631117Sminshall 	if (len > sizeof bellstring-1) {
41731117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
41831105Sminshall 	}
41931117Sminshall 	memcpy(bellstring, s, len+1);
42031117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
42131117Sminshall 	TryToSend();
42231105Sminshall     }
42331105Sminshall }
42431105Sminshall 
42531117Sminshall /*
42631117Sminshall  * Update the OIA area.
42731117Sminshall  */
42831105Sminshall 
42931117Sminshall void
43031117Sminshall ScreenOIA(oia)
43131117Sminshall OIA *oia;
43231117Sminshall {
43331117Sminshall }
43431117Sminshall 
43531117Sminshall 
43631105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
43731105Sminshall     or a 0 if there is more output available (so, just poll the other
43831105Sminshall     sources/destinations, don't block).
43931105Sminshall  */
44031105Sminshall 
44131105Sminshall int
44231105Sminshall DoTerminalOutput()
44331105Sminshall {
44431105Sminshall 	/* called just before a select to conserve IO to terminal */
44531105Sminshall     if (!Initialized) {
44631105Sminshall 	return 1;		/* No output if not initialized */
44731105Sminshall     }
44831105Sminshall     if ((Lowest <= Highest) || needToRing ||
44931105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
45031117Sminshall 	TryToSend();
45131105Sminshall     }
45231105Sminshall     if (Lowest > Highest) {
45331105Sminshall 	return 1;		/* no more output now */
45431105Sminshall     } else {
45531105Sminshall 	return 0;		/* more output for future */
45631105Sminshall     }
45731105Sminshall }
45831105Sminshall 
45931105Sminshall /*
46031105Sminshall  * The following are defined to handle transparent data.
46131105Sminshall  */
46231105Sminshall 
46331105Sminshall void
46431105Sminshall TransStop()
46531105Sminshall {
46631105Sminshall     RefreshScreen();
46731105Sminshall }
46831105Sminshall 
46931105Sminshall void
47031105Sminshall TransOut(buffer, count)
47131105Sminshall unsigned char	*buffer;
47231105Sminshall int		count;
47331105Sminshall {
47431105Sminshall 
47531105Sminshall     while (DoTerminalOutput() == 0) {
47631117Sminshall 	;
47731105Sminshall     }
47831105Sminshall     (void) DataToTerminal(buffer, count);
47931105Sminshall }
48031117Sminshall 
48131117Sminshall /*
48231117Sminshall  * init_screen()
48331117Sminshall  *
48431117Sminshall  * Initialize variables used by screen.
48531117Sminshall  */
48631105Sminshall 
48731117Sminshall void
48831117Sminshall init_screen()
48931105Sminshall {
49031117Sminshall     bellwinup = 0;
49131117Sminshall }
49231105Sminshall 
49331117Sminshall 
494