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 
3331881Sminshall #include "../api/disp_asc.h"
3431225Sminshall #include "../ascii/map3270.ext"
3531225Sminshall 
3631105Sminshall #include "../ctlr/hostctlr.h"
3731105Sminshall #include "../ctlr/inbound.ext"
3831117Sminshall #include "../ctlr/oia.h"
3931105Sminshall #include "../ctlr/options.ext"
4031105Sminshall #include "../ctlr/outbound.ext"
4131105Sminshall #include "../ctlr/screen.h"
4231105Sminshall 
4331185Sminshall #include "../general/globals.h"
4431105Sminshall 
4531120Sminshall #include "video.h"
4631120Sminshall 
4731105Sminshall extern void EmptyTerminal();
4831105Sminshall 
4931105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
5031105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
5131105Sminshall 
5231105Sminshall 
5331105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
5431105Sminshall static int screenInitd; 		/* the screen has been initialized */
5531105Sminshall static int screenStopped;		/* the screen has been stopped */
5631105Sminshall 
5731105Sminshall static int needToRing;			/* need to ring terinal bell */
5831105Sminshall 
5931117Sminshall typedef struct {
6031117Sminshall     char
6131117Sminshall 	data,		/* The data for this position */
6231117Sminshall 	attr;		/* The attributes for this position */
6331117Sminshall } ScreenBuffer;
6431105Sminshall 
6531117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
6631120Sminshall ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
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 
9831120Sminshall /*
9931120Sminshall  * Routines to deal with the screen.  These routines are lifted
10031120Sminshall  * from mskermit.
10131120Sminshall  */
10231120Sminshall 
10331120Sminshall #define	CRT_STATUS	0x3da		/* Color card */
10431120Sminshall #define	DISPLAY_ENABLE	0x08		/* Enable */
10531120Sminshall #define	scrseg()	((crt_mode == 7)? 0xb000 : 0xb800)
10631120Sminshall #define	scrwait()	if (crt_mode != 7) { \
10731120Sminshall 			    while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
10831120Sminshall 				; \
10931120Sminshall 			    } \
11031120Sminshall 			}
11131120Sminshall static int
11231120Sminshall     		crt_mode,
11331120Sminshall 		crt_cols,
11431120Sminshall 		crt_lins,
11531120Sminshall 		curpage;
11631120Sminshall 
11731120Sminshall /*
11831120Sminshall  * Set the cursor position to where it belongs.
11931120Sminshall  */
12031120Sminshall 
12131105Sminshall static void
12231120Sminshall setcursor(row, column, page)
12331120Sminshall int
12431120Sminshall     row,
12531120Sminshall     column,
12631120Sminshall     page;
12731120Sminshall {
12831120Sminshall     union REGS inregs, outregs;
12931120Sminshall 
13031120Sminshall     inregs.h.dh = row;
13131120Sminshall     inregs.h.dl = column;
13231120Sminshall     inregs.h.bh = page;
13331120Sminshall     inregs.h.ah = SetCursorPosition;
13431120Sminshall 
13531120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
13631120Sminshall }
13731120Sminshall /*
13831120Sminshall  * Read the state of the video system.  Put the cursor somewhere
13931120Sminshall  * reasonable.
14031120Sminshall  */
14131120Sminshall 
14231120Sminshall static void
14331120Sminshall scrini()
14431120Sminshall {
14531120Sminshall     union REGS inregs, outregs;
14631120Sminshall 
14731120Sminshall     inregs.h.ah = CurrentVideoState;
14831120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
14931120Sminshall 
15031120Sminshall     crt_mode = outregs.h.al;
15131120Sminshall     crt_cols = outregs.h.ah;
15231120Sminshall     crt_lins = 25;
15331120Sminshall     curpage = outregs.h.bh;
15431120Sminshall 
15531120Sminshall     inregs.h.ah = ReadCursorPosition;
15631120Sminshall     inregs.h.bh = curpage;
15731120Sminshall 
15831120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
15931120Sminshall 
16031120Sminshall     if (outregs.h.dh > crt_lins) {
16131120Sminshall 	outregs.h.dh = crt_lins;
16231120Sminshall     }
16331120Sminshall     if (outregs.h.dl > crt_cols) {
16431120Sminshall 	outregs.h.dl = crt_cols;
16531120Sminshall     }
16631120Sminshall     inregs.h.dh = outregs.h.dh;
16731120Sminshall     inregs.h.dl = outregs.h.dl;
16831120Sminshall     inregs.h.bh = curpage;
16931120Sminshall 
17031120Sminshall     inregs.h.ah = SetCursorPosition;
17131120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
17231120Sminshall }
17331120Sminshall 
17431120Sminshall 
17531120Sminshall static void
17631120Sminshall scrwrite(source, length, offset)
17731120Sminshall ScreenBuffer *source;
17831120Sminshall int
17931120Sminshall 	length,
18031120Sminshall 	offset;
18131120Sminshall {
18231120Sminshall     struct SREGS segregs;
18331120Sminshall 
18431120Sminshall     segread(&segregs);		/* read the current segment register */
18531120Sminshall 
18631120Sminshall     scrwait();
18731154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
18831154Sminshall 						sizeof *source*length);
18931120Sminshall }
19031120Sminshall 
19131120Sminshall static void
19231120Sminshall scrsave(buffer)
19331120Sminshall ScreenBuffer *buffer;
19431120Sminshall {
19531120Sminshall     struct SREGS segregs;
19631120Sminshall 
19731120Sminshall     segread(&segregs);		/* read the current segment register */
19831120Sminshall 
19931120Sminshall     scrwait();
20031154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
20131120Sminshall }
20231120Sminshall 
20331120Sminshall static void
20431120Sminshall scrrest(buffer)
20531120Sminshall ScreenBuffer *buffer;
20631120Sminshall {
20731154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
20831120Sminshall }
20931120Sminshall 
21031120Sminshall static void
21131117Sminshall TryToSend()
21231105Sminshall {
21331154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
21431117Sminshall #define	NORMAL		0x02	/* Normal mode */
21531154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
21631105Sminshall 
21731154Sminshall #define	DoAttribute(a) 	    \
21831154Sminshall 			    if (screenIsFormatted) { \
21931154Sminshall 				if (IsNonDisplayAttr(a)) { \
22031154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
22131154Sminshall 				} else if (IsHighlightedAttr(a)) { \
22231154Sminshall 				    a = STANDOUT; \
22331154Sminshall 				} else { \
22431154Sminshall 				    a = NORMAL; \
22531154Sminshall 				} \
22631154Sminshall 			    } else  { \
22731154Sminshall 				a = NORMAL;	/* do display on unformatted */\
22831105Sminshall 			    }
22931105Sminshall     ScreenImage *p, *upper;
23031117Sminshall     ScreenBuffer *sp;
23131105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
23231154Sminshall     int screenIsFormatted = FormattedScreen();
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())) {
24131117Sminshall 	sp = &Screen[Lowest];
24231105Sminshall 	p = &Host[Lowest];
24331105Sminshall 	upper = &Host[Highest];
24431105Sminshall 	fieldattr = FieldAttributes(Lowest);
24531105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
24631105Sminshall 
24731105Sminshall 	while (p <= upper) {
24831105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
24931105Sminshall 		Highest = HighestScreen();
25031105Sminshall 		Lowest = LowestScreen();
25131117Sminshall 		TryToSend();		/* Recurse */
25231105Sminshall 		return;
25331105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
25431154Sminshall 				/* Display translated data */
25531154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
25631105Sminshall 	    } else {
25731117Sminshall 		sp->data = ' ';
25831105Sminshall 	    }
25931154Sminshall 	    sp->attr = fieldattr;
26031105Sminshall 	    p++;
26131117Sminshall 	    sp++;
26231105Sminshall 	}
26331105Sminshall     } else {		/* Going from Lowest to Highest */
26431117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
26531105Sminshall 
26631117Sminshall 	sp = Screen;
26731105Sminshall 	p = Host;
26831105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
26931105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
27031105Sminshall 
27131105Sminshall 	while (p <= End) {
27231105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
27331105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
27431105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
27531154Sminshall 	    }
27631154Sminshall 	    if (fieldattr) {	/* Should we display? */
27731154Sminshall 			    /* Display translated data */
27831154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
27931105Sminshall 	    } else {
28031154Sminshall 		sp->data = ' ';
28131105Sminshall 	    }
28231154Sminshall 	    sp->attr = fieldattr;
28331105Sminshall 	    p++;
28431117Sminshall 	    sp++;
28531105Sminshall 	}
28631105Sminshall     }
28731117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
28831154Sminshall     /*
28931154Sminshall      * We might be here just to update the cursor address.
29031154Sminshall      */
29131154Sminshall     if (Highest >= Lowest) {
29231154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
29331154Sminshall     }
29431120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
29531117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
29631105Sminshall     Lowest = HighestScreen()+1;
29731105Sminshall     Highest = LowestScreen()-1;
29831105Sminshall     if (needToRing) {
29931117Sminshall 	DataToTerminal("\7", 1);
30031105Sminshall 	needToRing = 0;
30131105Sminshall     }
30231105Sminshall     return;
30331105Sminshall }
30431105Sminshall 
30531105Sminshall /* InitTerminal - called to initialize the screen, etc. */
30631105Sminshall 
30731105Sminshall void
30831105Sminshall InitTerminal()
30931105Sminshall {
31031105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
31131105Sminshall     if (!screenInitd) { 	/* not initialized */
31231129Sminshall 	MaxNumberLines = 24;	/* XXX */
31331129Sminshall 	MaxNumberColumns = 80;	/* XXX */
31431117Sminshall 	scrini();
31531120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
31631117Sminshall 	ClearArray(Screen);
31731105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
31831105Sminshall 	screenInitd = 1;
31931105Sminshall 	screenStopped = 0;		/* Not stopped */
32031105Sminshall     }
32131105Sminshall }
32231105Sminshall 
32331105Sminshall 
32431105Sminshall /* StopScreen - called when we are going away... */
32531105Sminshall 
32631105Sminshall void
32731105Sminshall StopScreen(doNewLine)
32831105Sminshall int doNewLine;
32931105Sminshall {
33031105Sminshall     if (screenInitd && !screenStopped) {
33131120Sminshall 	scrrest(saveScreen);
33231208Sminshall 	setcursor(NumberLines-1, 1, 0);
33331208Sminshall 	if (doNewLine) {
33431208Sminshall 	    StringToTerminal("\r\n");
33531208Sminshall 	}
33631208Sminshall 	EmptyTerminal();
33731208Sminshall 	screenStopped = 1;
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
38231883Sminshall 	bell_len = 0;		/* Length of error message */
38331105Sminshall 
38431117Sminshall 
38531105Sminshall void
38631105Sminshall BellOff()
38731105Sminshall {
38831883Sminshall     ScreenBuffer a[100];
38931883Sminshall     int i;
39031883Sminshall 
39131105Sminshall     if (bellwinup) {
39231883Sminshall 	unsigned char blank = ' ';
39331883Sminshall 
39431883Sminshall 	for (i = 0; i < bell_len; i++) {
39531883Sminshall 	    a[i].attr = NORMAL;
39631883Sminshall 	    a[i].data = ' ';
39731883Sminshall 	}
39831105Sminshall     }
39931883Sminshall     scrwrite(a, bell_len, 24*80);		/* XXX */
40031105Sminshall }
40131105Sminshall 
40231105Sminshall 
40331105Sminshall void
40431105Sminshall RingBell(s)
40531105Sminshall char *s;
40631105Sminshall {
40731105Sminshall     needToRing = 1;
40831105Sminshall     if (s) {
40931883Sminshall 	int i;
41031883Sminshall 	ScreenBuffer bellstring[100];
41131105Sminshall 
41231883Sminshall 	bell_len = strlen(s);
41331883Sminshall 	bellwinup = 1;
41431883Sminshall 	if (bell_len > sizeof bellstring-1) {
41531117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
41631105Sminshall 	}
41731883Sminshall 	for (i = 0; i < bell_len; i++) {
41831883Sminshall 	    bellstring[i].attr = STANDOUT;
41931883Sminshall 	    bellstring[i].data = s[i];
42031883Sminshall 	}
42131883Sminshall 	scrwrite(bellstring, bell_len, 24*80);		/* XXX */
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 */
44531490Sminshall     if (!(screenInitd||screenStopped)) {
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
470*31885Sminshall TransOut(buffer, count, kind, control)
47131105Sminshall unsigned char	*buffer;
47231105Sminshall int		count;
473*31885Sminshall int		kind;		/* 0 or 5 */
474*31885Sminshall int		control;	/* To see if we are done */
47531105Sminshall {
476*31885Sminshall     char *ptr;
47731105Sminshall 
47831105Sminshall     while (DoTerminalOutput() == 0) {
47931117Sminshall 	;
48031105Sminshall     }
481*31885Sminshall     for (ptr = buffer; ptr < buffer+count; ptr++) {
482*31885Sminshall 	*ptr &= 0x7f;		/* Turn off parity bit */
483*31885Sminshall     }
48431105Sminshall     (void) DataToTerminal(buffer, count);
485*31885Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
486*31885Sminshall 	SendToIBM();
487*31885Sminshall     } else {
488*31885Sminshall 	TransInput(1, kind);			/* Go get some data */
489*31885Sminshall     }
49031105Sminshall }
49131117Sminshall 
49231117Sminshall /*
49331117Sminshall  * init_screen()
49431117Sminshall  *
49531117Sminshall  * Initialize variables used by screen.
49631117Sminshall  */
49731105Sminshall 
49831117Sminshall void
49931117Sminshall init_screen()
50031105Sminshall {
50131117Sminshall     bellwinup = 0;
50231117Sminshall }
50331105Sminshall 
50431117Sminshall 
505