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