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();
191*31154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
192*31154Sminshall 						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();
204*31154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
20531120Sminshall }
20631120Sminshall 
20731120Sminshall static void
20831120Sminshall scrrest(buffer)
20931120Sminshall ScreenBuffer *buffer;
21031120Sminshall {
211*31154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
21231120Sminshall }
21331120Sminshall 
21431120Sminshall static void
21531117Sminshall TryToSend()
21631105Sminshall {
217*31154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
21831117Sminshall #define	NORMAL		0x02	/* Normal mode */
219*31154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
22031105Sminshall 
221*31154Sminshall #define	DoAttribute(a) 	    \
222*31154Sminshall 			    if (screenIsFormatted) { \
223*31154Sminshall 				if (IsNonDisplayAttr(a)) { \
224*31154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
225*31154Sminshall 				} else if (IsHighlightedAttr(a)) { \
226*31154Sminshall 				    a = STANDOUT; \
227*31154Sminshall 				} else { \
228*31154Sminshall 				    a = NORMAL; \
229*31154Sminshall 				} \
230*31154Sminshall 			    } else  { \
231*31154Sminshall 				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 */
236*31154Sminshall     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? */
258*31154Sminshall 				/* Display translated data */
259*31154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
26031105Sminshall 	    } else {
26131117Sminshall 		sp->data = ' ';
26231105Sminshall 	    }
263*31154Sminshall 	    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 */
279*31154Sminshall 	    }
280*31154Sminshall 	    if (fieldattr) {	/* Should we display? */
281*31154Sminshall 			    /* Display translated data */
282*31154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
28331105Sminshall 	    } else {
284*31154Sminshall 		sp->data = ' ';
28531105Sminshall 	    }
286*31154Sminshall 	    sp->attr = fieldattr;
28731105Sminshall 	    p++;
28831117Sminshall 	    sp++;
28931105Sminshall 	}
29031105Sminshall     }
29131117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
292*31154Sminshall     /*
293*31154Sminshall      * We might be here just to update the cursor address.
294*31154Sminshall      */
295*31154Sminshall     if (Highest >= Lowest) {
296*31154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
297*31154Sminshall     }
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);
33731120Sminshall 	setcursor(NumberLines-1, NumberColumns-1, 0);
33831105Sminshall     }
33931105Sminshall }
34031105Sminshall 
34131105Sminshall 
34231105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
34331105Sminshall 
34431105Sminshall void
34531105Sminshall RefreshScreen()
34631105Sminshall {
34731117Sminshall     Highest = HighestScreen();
34831117Sminshall     Lowest = LowestScreen();
34931117Sminshall     TryToSend();
35031105Sminshall }
35131105Sminshall 
35231105Sminshall 
35331105Sminshall /* ConnectScreen - called to reconnect to the screen */
35431105Sminshall 
35531105Sminshall void
35631105Sminshall ConnectScreen()
35731105Sminshall {
35831105Sminshall     if (screenInitd) {
35931105Sminshall 	RefreshScreen();
36031105Sminshall 	screenStopped = 0;
36131105Sminshall     }
36231105Sminshall }
36331105Sminshall 
36431105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
36531105Sminshall 
36631105Sminshall void
36731105Sminshall LocalClearScreen()
36831105Sminshall {
36931105Sminshall     Clear3270();
37031117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
37131117Sminshall     Highest = HighestScreen();
37231117Sminshall     TryToSend();
37331105Sminshall }
37431117Sminshall 
37531117Sminshall /*
37631117Sminshall  * Implement the bell/error message function.
37731117Sminshall  */
37831105Sminshall 
37931117Sminshall int
38031117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
38131117Sminshall static int
38231117Sminshall 	bellpos0 = 0;		/* Where error message goes */
38331105Sminshall 
38431117Sminshall static char	bellstring[100];/* Where message goes */
38531117Sminshall 
38631117Sminshall #define	BELL_SPACES	2	/* 2 spaces between border and bell */
38731117Sminshall 
38831117Sminshall #define	BELL_HIGH_LOW(h,l) { \
38931117Sminshall 	    h = bellpos0+2*NumberColumns+bellwinup+BELL_SPACES*2; \
39031117Sminshall 	    l = bellpos0; \
39131117Sminshall 	}
39231117Sminshall 
39331105Sminshall void
39431105Sminshall BellOff()
39531105Sminshall {
39631105Sminshall     if (bellwinup) {
39731117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
39831117Sminshall 	TryToSend();
39931105Sminshall     }
40031105Sminshall }
40131105Sminshall 
40231105Sminshall 
40331105Sminshall void
40431105Sminshall RingBell(s)
40531105Sminshall char *s;
40631105Sminshall {
40731105Sminshall     needToRing = 1;
40831105Sminshall     if (s) {
40931105Sminshall 	int len = strlen(s);
41031105Sminshall 
41131117Sminshall 	if (len > sizeof bellstring-1) {
41231117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
41331105Sminshall 	}
41431117Sminshall 	memcpy(bellstring, s, len+1);
41531117Sminshall 	BELL_HIGH_LOW(Highest,Lowest);
41631117Sminshall 	TryToSend();
41731105Sminshall     }
41831105Sminshall }
41931105Sminshall 
42031117Sminshall /*
42131117Sminshall  * Update the OIA area.
42231117Sminshall  */
42331105Sminshall 
42431117Sminshall void
42531117Sminshall ScreenOIA(oia)
42631117Sminshall OIA *oia;
42731117Sminshall {
42831117Sminshall }
42931117Sminshall 
43031117Sminshall 
43131105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
43231105Sminshall     or a 0 if there is more output available (so, just poll the other
43331105Sminshall     sources/destinations, don't block).
43431105Sminshall  */
43531105Sminshall 
43631105Sminshall int
43731105Sminshall DoTerminalOutput()
43831105Sminshall {
43931105Sminshall 	/* called just before a select to conserve IO to terminal */
44031105Sminshall     if (!Initialized) {
44131105Sminshall 	return 1;		/* No output if not initialized */
44231105Sminshall     }
44331105Sminshall     if ((Lowest <= Highest) || needToRing ||
44431105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
44531117Sminshall 	TryToSend();
44631105Sminshall     }
44731105Sminshall     if (Lowest > Highest) {
44831105Sminshall 	return 1;		/* no more output now */
44931105Sminshall     } else {
45031105Sminshall 	return 0;		/* more output for future */
45131105Sminshall     }
45231105Sminshall }
45331105Sminshall 
45431105Sminshall /*
45531105Sminshall  * The following are defined to handle transparent data.
45631105Sminshall  */
45731105Sminshall 
45831105Sminshall void
45931105Sminshall TransStop()
46031105Sminshall {
46131105Sminshall     RefreshScreen();
46231105Sminshall }
46331105Sminshall 
46431105Sminshall void
46531105Sminshall TransOut(buffer, count)
46631105Sminshall unsigned char	*buffer;
46731105Sminshall int		count;
46831105Sminshall {
46931105Sminshall 
47031105Sminshall     while (DoTerminalOutput() == 0) {
47131117Sminshall 	;
47231105Sminshall     }
47331105Sminshall     (void) DataToTerminal(buffer, count);
47431105Sminshall }
47531117Sminshall 
47631117Sminshall /*
47731117Sminshall  * init_screen()
47831117Sminshall  *
47931117Sminshall  * Initialize variables used by screen.
48031117Sminshall  */
48131105Sminshall 
48231117Sminshall void
48331117Sminshall init_screen()
48431105Sminshall {
48531117Sminshall     bellwinup = 0;
48631117Sminshall }
48731105Sminshall 
48831117Sminshall 
489