xref: /386bsd/usr/src/usr.bin/tn3270/ctlr/inbound.c (revision a2142627)
1 /*-
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)inbound.c	4.3 (Berkeley) 4/26/91";
36 #endif /* not lint */
37 
38 #include <stdio.h>
39 
40 #include "../general/general.h"
41 #include "function.h"
42 #include "hostctlr.h"
43 #include "oia.h"
44 #include "scrnctlr.h"
45 #include "screen.h"
46 #include "options.h"
47 #include "../api/dctype.h"
48 #include "../api/ebc_disp.h"
49 
50 #include "../general/globals.h"
51 #include "externs.h"
52 #include "declare.h"
53 
54 #define EmptyChar()	(ourPTail == ourPHead)
55 #define FullChar()	(ourPHead == ourBuffer+sizeof ourBuffer)
56 
57 
58 /*
59  * We define something to allow us to to IsProtected() quickly
60  * on unformatted screens (with the current algorithm for fields,
61  * unprotected takes exponential time...).
62  *
63  *	The idea is to call SetXIsProtected() BEFORE the
64  * loop, then use XIsProtected().
65  */
66 
67 #define	SetXIsProtected()	(XWasSF = 1)
68 #define	XIsProtected(p)	(IsStartField(p)? \
69 			    XWasSF = 1 : \
70 			    (XWasSF? \
71 				(XWasSF = 0, XProtected = IsProtected(p))  : \
72 				XProtected))
73 
74 static char	ourBuffer[400];
75 
76 static char	*ourPHead = ourBuffer,
77 		*ourPTail = ourBuffer;
78 
79 static int	HadAid;			/* Had an AID haven't sent */
80 
81 static int InsertMode;			/* is the terminal in insert mode? */
82 
83 static unsigned int
84 	rememberedshiftstate;	/* Shift (alt) state of terminal */
85 
86 #   define HITNUM(s) ((((s)&(SHIFT_CAPS|SHIFT_UPSHIFT))? 1:0) \
87 			+ ((((s)&SHIFT_ALT)? 1:0)<<1))
88 
89 static int	XWasSF, XProtected;	/* For optimizations */
90 #if	!defined(PURE3274)
91 extern int TransparentClock, OutputClock;
92 #endif	/* !defined(PURE3274) */
93 
94 #include "kbd.out"		/* Get keyboard mapping function */
95 
96 /* the following are global variables */
97 
98 extern int UnLocked;		/* keyboard is UnLocked? */
99 
100 
101 /*
102  * init_inbound :
103  *
104  * Reset variables to initial state.
105  */
106 
107 void
init_inbound()108 init_inbound()
109 {
110     ourPHead = ourPTail = ourBuffer;
111     HadAid = 0;
112     rememberedshiftstate = 0;
113     InsertMode = 0;
114 }
115 
116 
117 /* Tab() - sets cursor to the start of the next unprotected field */
118 static void
Tab()119 Tab()
120 {
121     register int i, j;
122 
123     i = CursorAddress;
124     j = WhereAttrByte(CursorAddress);
125     do {
126 	if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
127 	    break;
128 	}
129 	i = FieldInc(i);
130     } while (i != j);
131     if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
132 	CursorAddress = ScreenInc(i);
133     } else {
134 	CursorAddress = SetBufferAddress(0,0);
135     }
136 }
137 
138 
139 /* BackTab() - sets cursor to the start of the most recent field */
140 
141 static void
BackTab()142 BackTab()
143 {
144     register int i;
145 
146     i = ScreenDec(CursorAddress);
147     for (;;) {
148 	if (IsStartField(ScreenDec(i)) && IsUnProtected(i)) {
149 	    CursorAddress = i;
150 	    break;
151 	}
152 	if (i == CursorAddress) {
153 	    CursorAddress = SetBufferAddress(0,0);
154 	    break;
155 	}
156 	i = ScreenDec(i);
157     }
158 }
159 
160 /*
161  * ModifyMdt() - Turn a modified data tag bit on or off (watch
162  * out for unformatted screens).
163  */
164 
ModifyMdt(x,on)165 ModifyMdt(x,on)
166 int x;
167 int on;
168 {
169     int i = x;
170 
171     if (IsStartField(i)) {	/* If we are at a start field position... */
172 	if (on) {
173 	    ModifyHost(i, |= ATTR_MDT);		/* Turn it on */
174 	} else {
175 	    ModifyHost(i, &= ~ATTR_MDT);	/* Turn it off */
176 	}
177     } else {
178 	i = WhereAttrByte(i);	/* Find beginning of field */
179 	if (IsStartField(i)) {	/* Is there one? */
180 	    if (on) {
181 		ModifyHost(i, |= ATTR_MDT);	/* Turn it on */
182 	    } else {
183 		ModifyHost(i, &= ~ATTR_MDT);	/* Turn it off */
184 	    }
185 	} /* else, don't modify - this is an unformatted screen */
186     }
187 }
188 
189 
190 /* EraseEndOfField - erase all characters to the end of a field */
191 
192 static void
EraseEndOfField()193 EraseEndOfField()
194 {
195     register int i;
196 
197     if (IsProtected(CursorAddress)) {
198 	RingBell("Protected Field");
199     } else {
200 	TurnOnMdt(CursorAddress);
201 	if (FormattedScreen()) {
202 	    i = CursorAddress;
203 	    do {
204 		AddHost(i, 0);
205 		i = ScreenInc(i);
206 	    } while ((i != CursorAddress) && !IsStartField(i));
207 	} else {                            /* Screen is Unformatted */
208 	    i = CursorAddress;
209 	    do {
210 		AddHost(i, 0);
211 		i = ScreenInc(i);
212 	    } while (i != HighestScreen());
213        }
214     }
215 }
216 
217 /* Delete() - deletes a character from the screen
218  *
219  *	What we want to do is delete the section
220  *	[where, from-1] from the screen,
221  *	filling in with what comes at from.
222  *
223  *	The deleting continues to the end of the field (or
224  *	until the cursor wraps).
225  *
226  *	From can be a start of a field.  We
227  *	check for that.  However, there can't be any
228  *	fields that start between where and from.
229  *	We don't check for that.
230  *
231  *	Also, we assume that the protection status of
232  *	everything has been checked by the caller.
233  *
234  */
235 
236 static void
Delete(where,from)237 Delete(where, from)
238 register int	where,		/* Where to start deleting from */
239 		from;		/* Where to pull back from */
240 {
241     register int i;
242 
243     TurnOnMdt(where);			/* Only do this once in this field */
244     i = where;
245     do {
246 	if (IsStartField(from)) {
247 	    AddHost(i, 0);		/* Stick the edge at the start field */
248 	} else {
249 	    AddHost(i, (char)GetHost(from));
250 	    from = ScreenInc(from);		/* Move the edge */
251 	}
252 	i = ScreenInc(i);
253     } while ((!IsStartField(i)) && (i != where));
254 }
255 
256 static void
ColBak()257 ColBak()
258 {
259     register int i;
260 
261     i = ScreenLineOffset(CursorAddress);
262     for (i = i-1; i >= 0; i--) {
263 	if (OptColTabs[i]) {
264 	    break;
265 	}
266     }
267     if (i < 0) {
268 	i = 0;
269     }
270     CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
271 }
272 
273 static void
ColTab()274 ColTab()
275 {
276     register int i;
277 
278     i = ScreenLineOffset(CursorAddress);
279     for (i = i+1; i < NumberColumns; i++) {
280 	if (OptColTabs[i]) {
281 	    break;
282 	}
283     }
284     if (i >= NumberColumns) {
285 	i = NumberColumns-1;
286     }
287     CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
288 }
289 
290 static void
Home()291 Home()
292 {
293     register int i;
294     register int j;
295 
296     i = SetBufferAddress(OptHome, 0);
297     j = WhereLowByte(i);
298     /*
299      * If the initial value of i points to the field attribute of
300      * an unprotected field, we need to return the address of the
301      * first data byte in the field (assuming there are any!).
302      */
303     if (IsStartField(i) && IsUnProtected(j)) {
304 	CursorAddress = j;
305 	return;
306     }
307     do {
308 	if (IsUnProtected(i)) {
309 	    CursorAddress = i;
310 	    return;
311 	}
312 	    /* the following could be a problem if we got here with an
313 	     * unformatted screen.  However, this is "impossible", since
314 	     * with an unformatted screen, the IsUnProtected(i) above
315 	     * should be true.
316 	     */
317 	i = ScreenInc(FieldInc(i));
318     } while (i != j);
319     CursorAddress = LowestScreen();
320 }
321 
322 static
LastOfField(i)323 LastOfField(i)
324 register int	i;	/* position to start from */
325 {
326     register int j;
327     register int k;
328 
329     k = j = i;
330     SetXIsProtected();
331     while (XIsProtected(i) || Disspace(GetHost(i))) {
332 	i = ScreenInc(i);
333 	if (i == j) {
334 	    break;
335 	}
336     }
337 	    /* We are now IN a word IN an unprotected field (or wrapped) */
338     while (!XIsProtected(i)) {
339 	if (!Disspace(GetHost(i))) {
340 	    k = i;
341 	}
342 	i = ScreenInc(i);
343 	if (i == j) {
344 	    break;
345 	}
346     }
347     return(k);
348 }
349 
350 
351 static void
FlushChar()352 FlushChar()
353 {
354     ourPTail = ourPHead = ourBuffer;
355 }
356 
357 
358 /*
359  * Add one EBCDIC (NOT display code) character to the buffer.
360  */
361 
362 static void
AddChar(character)363 AddChar(character)
364 char	character;
365 {
366     if (FullChar()) {
367 	ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 0);
368 	if (EmptyChar()) {
369 	    FlushChar();
370 	} else {
371 	    char buffer[100];
372 
373 	    sprintf(buffer, "File %s, line %d:  No room in network buffer!\n",
374 				__FILE__, __LINE__);
375 	    ExitString(buffer, 1);
376 	    /*NOTREACHED*/
377 	}
378     }
379     *ourPHead++ = character;
380 }
381 
382 
383 static void
SendUnformatted()384 SendUnformatted()
385 {
386     register int i, j;
387     register int Nulls;
388     register int c;
389 
390 			/* look for start of field */
391     Nulls = 0;
392     i = j = LowestScreen();
393     do {
394 	c = GetHost(i);
395 	if (c == 0) {
396 	    Nulls++;
397 	} else {
398 	    while (Nulls) {
399 		Nulls--;
400 		AddChar(EBCDIC_BLANK);		/* put in blanks */
401 	    }
402 	    AddChar((char)disp_ebc[c]);
403 	}
404 	i = ScreenInc(i);
405     } while (i != j);
406 }
407 
408 static
SendField(i,cmd)409 SendField(i, cmd)
410 register int i;			/* where we saw MDT bit */
411 int	cmd;			/* The command code (type of read) */
412 {
413     register int j;
414     register int k;
415     register int Nulls;
416     register int c;
417 
418 			/* look for start of field */
419     i = j = WhereLowByte(i);
420 
421 		/* On a test_request_read, don't send sba and address */
422     if ((AidByte != AID_TREQ)
423 			|| (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
424 	AddChar(ORDER_SBA);		/* set start field */
425 	AddChar(BufferTo3270_0(j));	/* set address of this field */
426 	AddChar(BufferTo3270_1(j));
427     }
428 		/*
429 		 * Only on read_modified_all do we return the contents
430 		 * of the field when the attention was caused by a
431 		 * selector pen.
432 		 */
433     if ((AidByte != AID_SELPEN)
434 			|| (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
435 	if (!IsStartField(j)) {
436 	    Nulls = 0;
437 	    k = ScreenInc(WhereHighByte(j));
438 	    do {
439 		c = GetHost(j);
440 		if (c == 0) {
441 		    Nulls++;
442 		} else {
443 		    while (Nulls) {
444 			Nulls--;
445 			AddChar(EBCDIC_BLANK);		/* put in blanks */
446 		    }
447 		    AddChar((char)disp_ebc[c]);
448 		}
449 		j = ScreenInc(j);
450 	    } while ((j != k) && (j != i));
451 	}
452     } else {
453 	j = FieldInc(j);
454     }
455     return(j);
456 }
457 
458 /* Various types of reads... */
459 void
DoReadModified(cmd)460 DoReadModified(cmd)
461 int	cmd;			/* The command sent */
462 {
463     register int i, j;
464 
465     if (AidByte) {
466 	if (AidByte != AID_TREQ) {
467 	    AddChar(AidByte);
468 	} else {
469 		/* Test Request Read header */
470 	    AddChar(EBCDIC_SOH);
471 	    AddChar(EBCDIC_PERCENT);
472 	    AddChar(EBCDIC_SLASH);
473 	    AddChar(EBCDIC_STX);
474 	}
475     } else {
476 	AddChar(AID_NONE);
477     }
478     if (((AidByte != AID_PA1) && (AidByte != AID_PA2)
479 	    && (AidByte != AID_PA3) && (AidByte != AID_CLEAR))
480 	    || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
481 	if ((AidByte != AID_TREQ)
482 	    || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
483 		/* Test request read_modified doesn't give cursor address */
484 	    AddChar(BufferTo3270_0(CursorAddress));
485 	    AddChar(BufferTo3270_1(CursorAddress));
486 	}
487 	i = j = WhereAttrByte(LowestScreen());
488 	/* Is this an unformatted screen? */
489 	if (!IsStartField(i)) {		/* yes, handle separate */
490 	    SendUnformatted();
491 	} else {
492 	    do {
493 		if (HasMdt(i)) {
494 		    i = SendField(i, cmd);
495 		} else {
496 		    i = FieldInc(i);
497 		}
498 	    } while (i != j);
499 	}
500     }
501     ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
502     if (EmptyChar()) {
503 	FlushChar();
504 	HadAid = 0;			/* killed that buffer */
505     }
506 }
507 
508 /* A read buffer operation... */
509 
510 void
DoReadBuffer()511 DoReadBuffer()
512 {
513     register int i, j;
514 
515     if (AidByte) {
516 	AddChar(AidByte);
517     } else {
518 	AddChar(AID_NONE);
519     }
520     AddChar(BufferTo3270_0(CursorAddress));
521     AddChar(BufferTo3270_1(CursorAddress));
522     i = j = LowestScreen();
523     do {
524 	if (IsStartField(i)) {
525 	    AddChar(ORDER_SF);
526 	    AddChar(BufferTo3270_1(FieldAttributes(i)));
527 	} else {
528 	    AddChar((char)disp_ebc[GetHost(i)]);
529 	}
530 	i = ScreenInc(i);
531     } while (i != j);
532     ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
533     if (EmptyChar()) {
534 	FlushChar();
535 	HadAid = 0;			/* killed that buffer */
536     }
537 }
538 
539 /* Send some transparent data to the host */
540 
541 void
SendTransparent(buffer,count)542 SendTransparent(buffer, count)
543 char *buffer;
544 int count;
545 {
546     char stuff[3];
547 
548     stuff[0] = AID_NONE_PRINTER;
549     stuff[1] = BufferTo3270_0(count);
550     stuff[2] = BufferTo3270_1(count);
551     DataToNetwork(stuff, sizeof stuff, 0);
552     DataToNetwork(buffer, count, 1);
553 }
554 
555 
556 /* Try to send some data to host */
557 
558 void
SendToIBM()559 SendToIBM()
560 {
561 #if	!defined(PURE3274)
562     if (TransparentClock >= OutputClock) {
563 	if (HadAid) {
564 	    AddChar(AidByte);
565 	    HadAid = 0;
566 	} else {
567 	    AddChar(AID_NONE_PRINTER);
568 	}
569 	do {
570 	    ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
571 	} while (!EmptyChar());
572 	FlushChar();
573     } else if (HadAid) {
574 	DoReadModified(CMD_READ_MODIFIED);
575     }
576 #else	/* !defined(PURE3274) */
577     if (HadAid) {
578 	DoReadModified(CMD_READ_MODIFIED);
579     }
580 #endif	/* !defined(PURE3274) */
581 }
582 
583 /* This takes in one character from the keyboard and places it on the
584  * screen.
585  */
586 
587 static void
OneCharacter(c,insert)588 OneCharacter(c, insert)
589 int c;			/* character (Ebcdic) to be shoved in */
590 int insert;		/* are we in insert mode? */
591 {
592     register int i, j;
593 
594     if (IsProtected(CursorAddress)) {
595 	RingBell("Protected Field");
596 	return;
597     }
598     if (insert) {
599 	/* is the last character in the field a blank or null? */
600 	i = ScreenDec(FieldInc(CursorAddress));
601 	j = GetHost(i);
602 	if (!Disspace(j)) {
603 	    RingBell("No more room for insert");
604 	    return;
605 	} else {
606 	    for (j = ScreenDec(i); i != CursorAddress;
607 			    j = ScreenDec(j), i = ScreenDec(i)) {
608 		AddHost(i, (char)GetHost(j));
609 	    }
610 	}
611     }
612     AddHost(CursorAddress, c);
613     TurnOnMdt(CursorAddress);
614     CursorAddress = ScreenInc(CursorAddress);
615     if (IsStartField(CursorAddress) &&
616 		((FieldAttributes(CursorAddress)&ATTR_AUTO_SKIP_MASK) ==
617 							ATTR_AUTO_SKIP_VALUE)) {
618 	Tab();
619     }
620 }
621 
622 /*
623  * AcceptKeystroke()
624  *
625  * Processes one keystroke.
626  *
627  * Returns:
628  *
629  *	0	if this keystroke was NOT processed.
630  *	1	if everything went OK.
631  */
632 
633 int
AcceptKeystroke(scancode,shiftstate)634 AcceptKeystroke(scancode, shiftstate)
635 unsigned int
636     scancode,			/* 3270 scancode */
637     shiftstate;			/* The shift state */
638 {
639     register int c;
640     register int i;
641     register int j;
642     enum ctlrfcn ctlrfcn;
643 
644     if (scancode >= numberof(hits)) {
645 	ExitString(
646 		"Unknown scancode encountered in AcceptKeystroke.\n", 1);
647 	/*NOTREACHED*/
648     }
649     ctlrfcn = hits[scancode].hit[HITNUM(shiftstate)].ctlrfcn;
650     c = hits[scancode].hit[HITNUM(shiftstate)].code;
651 
652     if (!UnLocked || HadAid) {
653 	if (HadAid) {
654 	    SendToIBM();
655 	    if (!EmptyChar()) {
656 		return 0;			/* nothing to do */
657 	    }
658 	}
659 #if	!defined(PURE3274)
660 	if (!HadAid && EmptyChar()) {
661 	    if ((ctlrfcn == FCN_RESET) || (ctlrfcn == FCN_MASTER_RESET)) {
662 		UnLocked = 1;
663 	    }
664 	}
665 #endif	/* !defined(PURE3274) */
666 	if (!UnLocked) {
667 	    return 0;
668 	}
669     }
670 
671     /* now, either empty, or haven't seen aid yet */
672 
673 #if	!defined(PURE3274)
674     /*
675      * If we are in transparent (output) mode, do something special
676      * with keystrokes.
677      */
678     if (TransparentClock == OutputClock) {
679 	if (ctlrfcn == FCN_AID) {
680 	    UnLocked = 0;
681 	    InsertMode = 0;
682 	    AidByte = (c);
683 	    HadAid = 1;
684 	} else {
685 	    switch (ctlrfcn) {
686 	    case FCN_ESCAPE:
687 		StopScreen(1);
688 		command(0);
689 		if (shell_active == 0) {
690 		    ConnectScreen();
691 		}
692 		break;
693 
694 	    case FCN_RESET:
695 	    case FCN_MASTER_RESET:
696 		UnLocked = 1;
697 		break;
698 
699 	    default:
700 		return 0;
701 	    }
702 	}
703     }
704 #endif	/* !defined(PURE3274) */
705 
706     if (ctlrfcn == FCN_CHARACTER) {
707 		    /* Add the character to the buffer */
708 	OneCharacter(c, InsertMode);
709     } else if (ctlrfcn == FCN_AID) {		/* got Aid */
710 	if (c == AID_CLEAR) {
711 	    LocalClearScreen();	/* Side effect is to clear 3270 */
712 	}
713 	ResetOiaOnlineA(&OperatorInformationArea);
714 	SetOiaTWait(&OperatorInformationArea);
715 	ResetOiaInsert(&OperatorInformationArea);
716 	InsertMode = 0;		/* just like a 3278 */
717 	SetOiaSystemLocked(&OperatorInformationArea);
718 	SetOiaModified();
719 	UnLocked = 0;
720 	AidByte = c;
721 	HadAid = 1;
722 	SendToIBM();
723     } else {
724 	switch (ctlrfcn) {
725 
726 	case FCN_CURSEL:
727 	    c = FieldAttributes(CursorAddress)&ATTR_DSPD_MASK;
728 	    if (!FormattedScreen()
729 		    || ((c != ATTR_DSPD_DSPD) && (c != ATTR_DSPD_HIGH))) {
730 		RingBell("Cursor not in selectable field");
731 	    } else {
732 		i = ScreenInc(WhereAttrByte(CursorAddress));
733 		c = GetHost(i);
734 		if (c == DISP_QUESTION) {
735 		    AddHost(i, DISP_GREATER_THAN);
736 		    TurnOnMdt(i);
737 		} else if (c == DISP_GREATER_THAN) {
738 		    AddHost(i, DISP_QUESTION);
739 		    TurnOffMdt(i);
740 		} else if (c == DISP_BLANK || c == DISP_NULL
741 					    || c == DISP_AMPERSAND) {
742 		    UnLocked = 0;
743 		    InsertMode = 0;
744 		    ResetOiaOnlineA(&OperatorInformationArea);
745 		    SetOiaTWait(&OperatorInformationArea);
746 		    SetOiaSystemLocked(&OperatorInformationArea);
747 		    ResetOiaInsert(&OperatorInformationArea);
748 		    SetOiaModified();
749 		    if (c == DISP_AMPERSAND) {
750 			TurnOnMdt(i);	/* Only for & type */
751 			AidByte = AID_ENTER;
752 		    } else {
753 			AidByte = AID_SELPEN;
754 		    }
755 		    HadAid = 1;
756 		    SendToIBM();
757 		} else {
758 		    RingBell(
759 			"Cursor not in a selectable field (designator)");
760 		}
761 	    }
762 	    break;
763 
764 #if	!defined(PURE3274)
765 	case FCN_ERASE:
766 	    if (IsProtected(ScreenDec(CursorAddress))) {
767 		RingBell("Protected Field");
768 	    } else {
769 		CursorAddress = ScreenDec(CursorAddress);
770 		Delete(CursorAddress, ScreenInc(CursorAddress));
771 	    }
772 	    break;
773 	case FCN_WERASE:
774 	    j = CursorAddress;
775 	    i = ScreenDec(j);
776 	    if (IsProtected(i)) {
777 		RingBell("Protected Field");
778 	    } else {
779 		SetXIsProtected();
780 		while ((!XIsProtected(i) && Disspace(GetHost(i)))
781 						    && (i != j)) {
782 		    i = ScreenDec(i);
783 		}
784 		/* we are pointing at a character in a word, or
785 		 * at a protected position
786 		 */
787 		while ((!XIsProtected(i) && !Disspace(GetHost(i)))
788 						    && (i != j)) {
789 		    i = ScreenDec(i);
790 		}
791 		/* we are pointing at a space, or at a protected
792 		 * position
793 		 */
794 		CursorAddress = ScreenInc(i);
795 		Delete(CursorAddress, j);
796 	    }
797 	    break;
798 
799 	case FCN_FERASE:
800 	    if (IsProtected(CursorAddress)) {
801 		RingBell("Protected Field");
802 	    } else {
803 		CursorAddress = ScreenInc(CursorAddress);	/* for btab */
804 		BackTab();
805 		EraseEndOfField();
806 	    }
807 	    break;
808 
809 	case FCN_RESET:
810 	    if (InsertMode) {
811 		InsertMode = 0;
812 		ResetOiaInsert(&OperatorInformationArea);
813 		SetOiaModified();
814 	    }
815 	    break;
816 	case FCN_MASTER_RESET:
817 	    if (InsertMode) {
818 		InsertMode = 0;
819 		ResetOiaInsert(&OperatorInformationArea);
820 		SetOiaModified();
821 	    }
822 	    RefreshScreen();
823 	    break;
824 #endif	/* !defined(PURE3274) */
825 
826 	case FCN_UP:
827 	    CursorAddress = ScreenUp(CursorAddress);
828 	    break;
829 
830 	case FCN_LEFT:
831 	    CursorAddress = ScreenDec(CursorAddress);
832 	    break;
833 
834 	case FCN_RIGHT:
835 	    CursorAddress = ScreenInc(CursorAddress);
836 	    break;
837 
838 	case FCN_DOWN:
839 	    CursorAddress = ScreenDown(CursorAddress);
840 	    break;
841 
842 	case FCN_DELETE:
843 	    if (IsProtected(CursorAddress)) {
844 		RingBell("Protected Field");
845 	    } else {
846 		Delete(CursorAddress, ScreenInc(CursorAddress));
847 	    }
848 	    break;
849 
850 	case FCN_INSRT:
851 	    InsertMode = !InsertMode;
852 	    if (InsertMode) {
853 		SetOiaInsert(&OperatorInformationArea);
854 	    } else {
855 		ResetOiaInsert(&OperatorInformationArea);
856 	    }
857 	    SetOiaModified();
858 	    break;
859 
860 	case FCN_HOME:
861 	    Home();
862 	    break;
863 
864 	case FCN_NL:
865 	    /* The algorithm is to look for the first unprotected
866 	     * column after column 0 of the following line.  Having
867 	     * found that unprotected column, we check whether the
868 	     * cursor-address-at-entry is at or to the right of the
869 	     * LeftMargin AND the LeftMargin column of the found line
870 	     * is unprotected.  If this conjunction is true, then
871 	     * we set the found pointer to the address of the LeftMargin
872 	     * column in the found line.
873 	     * Then, we set the cursor address to the found address.
874 	     */
875 	    i = SetBufferAddress(ScreenLine(ScreenDown(CursorAddress)), 0);
876 	    j = ScreenInc(WhereAttrByte(CursorAddress));
877 	    do {
878 		if (IsUnProtected(i)) {
879 		    break;
880 		}
881 		/* Again (see comment in Home()), this COULD be a problem
882 		 * with an unformatted screen.
883 		 */
884 		/* If there was a field with only an attribute byte,
885 		 * we may be pointing to the attribute byte of the NEXT
886 		 * field, so just look at the next byte.
887 		 */
888 		if (IsStartField(i)) {
889 		    i = ScreenInc(i);
890 		} else {
891 		    i = ScreenInc(FieldInc(i));
892 		}
893 	    } while (i != j);
894 	    if (!IsUnProtected(i)) {	/* couldn't find unprotected */
895 		i = SetBufferAddress(0,0);
896 	    }
897 	    if (OptLeftMargin <= ScreenLineOffset(CursorAddress)) {
898 		if (IsUnProtected(SetBufferAddress(ScreenLine(i),
899 							OptLeftMargin))) {
900 		    i = SetBufferAddress(ScreenLine(i), OptLeftMargin);
901 		}
902 	    }
903 	    CursorAddress = i;
904 	    break;
905 
906 	case FCN_EINP:
907 	    if (!FormattedScreen()) {
908 		i = CursorAddress;
909 		TurnOffMdt(i);
910 		do {
911 		    AddHost(i, 0);
912 		    i = ScreenInc(i);
913 		} while (i != CursorAddress);
914 	    } else {
915 		    /*
916 		     * The algorithm is:  go through each unprotected
917 		     * field on the screen, clearing it out.  When
918 		     * we are at the start of a field, skip that field
919 		     * if its contents are protected.
920 		     */
921 		i = j = FieldInc(CursorAddress);
922 		do {
923 		    if (IsUnProtected(ScreenInc(i))) {
924 			i = ScreenInc(i);
925 			TurnOffMdt(i);
926 			do {
927 			   AddHost(i, 0);
928 			   i = ScreenInc(i);
929 			} while (!IsStartField(i));
930 		    } else {
931 			i = FieldInc(i);
932 		    }
933 		} while (i != j);
934 	    }
935 	    Home();
936 	    break;
937 
938 	case FCN_EEOF:
939 	    EraseEndOfField();
940 	    break;
941 
942 	case FCN_SPACE:
943 	    OneCharacter(DISP_BLANK, InsertMode);  /* Add cent */
944 	    break;
945 
946 	case FCN_CENTSIGN:
947 	    OneCharacter(DISP_CENTSIGN, InsertMode);  /* Add cent */
948 	    break;
949 
950 	case FCN_FM:
951 	    OneCharacter(DISP_FM, InsertMode);  /* Add field mark */
952 	    break;
953 
954 	case FCN_DP:
955 	    if (IsProtected(CursorAddress)) {
956 		RingBell("Protected Field");
957 	    } else {
958 		OneCharacter(DISP_DUP, InsertMode);/* Add dup character */
959 		Tab();
960 	    }
961 	    break;
962 
963 	case FCN_TAB:
964 	    Tab();
965 	    break;
966 
967 	case FCN_BTAB:
968 	    BackTab();
969 	    break;
970 
971 #ifdef	NOTUSED			/* Actually, this is superseded by unix flow
972 			     * control.
973 			     */
974 	case FCN_XOFF:
975 	    Flow = 0;			/* stop output */
976 	    break;
977 
978 	case FCN_XON:
979 	    if (!Flow) {
980 		Flow = 1;			/* turn it back on */
981 		DoTerminalOutput();
982 	    }
983 	    break;
984 #endif	/* NOTUSED */
985 
986 #if	!defined(PURE3274)
987 	case FCN_ESCAPE:
988 	    /* FlushChar(); do we want to flush characters from before? */
989 	    StopScreen(1);
990 	    command(0);
991 	    if (shell_active == 0) {
992 		ConnectScreen();
993 	    }
994 	    break;
995 
996 	case FCN_DISC:
997 	    StopScreen(1);
998 	    suspend();
999 	    setconnmode();
1000 	    ConnectScreen();
1001 	    break;
1002 
1003 	case FCN_RESHOW:
1004 	    RefreshScreen();
1005 	    break;
1006 
1007 	case FCN_SETTAB:
1008 	    OptColTabs[ScreenLineOffset(CursorAddress)] = 1;
1009 	    break;
1010 
1011 	case FCN_DELTAB:
1012 	    OptColTabs[ScreenLineOffset(CursorAddress)] = 0;
1013 	    break;
1014 
1015 	    /*
1016 	     * Clear all tabs, home line, and left margin.
1017 	     */
1018 	case FCN_CLRTAB:
1019 	    for (i = 0; i < sizeof OptColTabs; i++) {
1020 		OptColTabs[i] = 0;
1021 	    }
1022 	    OptHome = 0;
1023 	    OptLeftMargin = 0;
1024 	    break;
1025 
1026 	case FCN_COLTAB:
1027 	    ColTab();
1028 	    break;
1029 
1030 	case FCN_COLBAK:
1031 	    ColBak();
1032 	    break;
1033 
1034 	case FCN_INDENT:
1035 	    ColTab();
1036 	    OptLeftMargin = ScreenLineOffset(CursorAddress);
1037 	    break;
1038 
1039 	case FCN_UNDENT:
1040 	    ColBak();
1041 	    OptLeftMargin = ScreenLineOffset(CursorAddress);
1042 	    break;
1043 
1044 	case FCN_SETMRG:
1045 	    OptLeftMargin = ScreenLineOffset(CursorAddress);
1046 	    break;
1047 
1048 	case FCN_SETHOM:
1049 	    OptHome = ScreenLine(CursorAddress);
1050 	    break;
1051 
1052 	    /*
1053 	     * Point to first character of next unprotected word on
1054 	     * screen.
1055 	     */
1056 	case FCN_WORDTAB:
1057 	    i = CursorAddress;
1058 	    SetXIsProtected();
1059 	    while (!XIsProtected(i) && !Disspace(GetHost(i))) {
1060 		i = ScreenInc(i);
1061 		if (i == CursorAddress) {
1062 		    break;
1063 		}
1064 	    }
1065 	    /* i is either protected, a space (blank or null),
1066 	     * or wrapped
1067 	     */
1068 	    while (XIsProtected(i) || Disspace(GetHost(i))) {
1069 		i =  ScreenInc(i);
1070 		if (i == CursorAddress) {
1071 		    break;
1072 		}
1073 	    }
1074 	    CursorAddress = i;
1075 	    break;
1076 
1077 	case FCN_WORDBACKTAB:
1078 	    i = ScreenDec(CursorAddress);
1079 	    SetXIsProtected();
1080 	    while (XIsProtected(i) || Disspace(GetHost(i))) {
1081 		i = ScreenDec(i);
1082 		if (i == CursorAddress) {
1083 		    break;
1084 		}
1085 	    }
1086 		/* i is pointing to a character IN an unprotected word
1087 		 * (or i wrapped)
1088 		 */
1089 	    while (!Disspace(GetHost(i))) {
1090 		i = ScreenDec(i);
1091 		if (i == CursorAddress) {
1092 		    break;
1093 		}
1094 	    }
1095 	    CursorAddress = ScreenInc(i);
1096 	    break;
1097 
1098 		    /* Point to last non-blank character of this/next
1099 		     * unprotected word.
1100 		     */
1101 	case FCN_WORDEND:
1102 	    i = ScreenInc(CursorAddress);
1103 	    SetXIsProtected();
1104 	    while (XIsProtected(i) || Disspace(GetHost(i))) {
1105 		i = ScreenInc(i);
1106 		if (i == CursorAddress) {
1107 		    break;
1108 		}
1109 	    }
1110 		    /* we are pointing at a character IN an
1111 		     * unprotected word (or we wrapped)
1112 		     */
1113 	    while (!Disspace(GetHost(i))) {
1114 		i = ScreenInc(i);
1115 		if (i == CursorAddress) {
1116 		    break;
1117 		}
1118 	    }
1119 	    CursorAddress = ScreenDec(i);
1120 	    break;
1121 
1122 		    /* Get to last non-blank of this/next unprotected
1123 		     * field.
1124 		     */
1125 	case FCN_FIELDEND:
1126 	    i = LastOfField(CursorAddress);
1127 	    if (i != CursorAddress) {
1128 		CursorAddress = i;		/* We moved; take this */
1129 	    } else {
1130 		j = FieldInc(CursorAddress);	/* Move to next field */
1131 		i = LastOfField(j);
1132 		if (i != j) {
1133 		    CursorAddress = i;	/* We moved; take this */
1134 		}
1135 		    /* else - nowhere else on screen to be; stay here */
1136 	    }
1137 	    break;
1138 #endif	/* !defined(PURE3274) */
1139 
1140 	default:
1141 				/* We don't handle this yet */
1142 	    RingBell("Function not implemented");
1143 	}
1144     }
1145     return 1;				/* We did something! */
1146 }
1147 
1148 
1149 /*
1150  * We get data from the terminal.  We keep track of the shift state
1151  * (including ALT, CONTROL), and then call AcceptKeystroke to actually
1152  * process any non-shift keys.
1153  */
1154 
1155 int
DataFrom3270(buffer,count)1156 DataFrom3270(buffer, count)
1157 unsigned char	*buffer;		/* where the data is */
1158 int		count;			/* how much data there is */
1159 {
1160     int origCount;
1161 
1162     origCount = count;
1163 
1164     while (count) {
1165 	if (*buffer >= numberof(hits)) {
1166 	    ExitString("Unknown scancode encountered in DataFrom3270.\n", 1);
1167 	    /*NOTREACHED*/
1168 	}
1169 
1170 	switch (hits[*buffer].hit[HITNUM(rememberedshiftstate)].ctlrfcn) {
1171 
1172 	case FCN_MAKE_SHIFT:
1173 	    rememberedshiftstate |= (SHIFT_RIGHT|SHIFT_UPSHIFT);
1174 	    break;
1175 	case FCN_BREAK_SHIFT:
1176 	    rememberedshiftstate &= ~(SHIFT_RIGHT|SHIFT_UPSHIFT);
1177 	    break;
1178 	case FCN_MAKE_ALT:
1179 	    rememberedshiftstate |= SHIFT_ALT;
1180 	    break;
1181 	case FCN_BREAK_ALT:
1182 	    rememberedshiftstate &= ~SHIFT_ALT;
1183 	    break;
1184 	default:
1185 	    if (AcceptKeystroke(*buffer, rememberedshiftstate) == 0) {
1186 		return(origCount-count);
1187 	    }
1188 	    break;
1189 	}
1190 	buffer++;
1191 	count--;
1192     }
1193     return(origCount-count);
1194 }
1195