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