home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tn3270 / ctlr / inbound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-26  |  26.6 KB  |  1,195 lines

  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
  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
  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
  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.  
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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.