summaryrefslogtreecommitdiffstats
path: root/usr.bin/tn3270/ctlr/outbound.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tn3270/ctlr/outbound.c')
-rw-r--r--usr.bin/tn3270/ctlr/outbound.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/usr.bin/tn3270/ctlr/outbound.c b/usr.bin/tn3270/ctlr/outbound.c
new file mode 100644
index 0000000..72432f2
--- /dev/null
+++ b/usr.bin/tn3270/ctlr/outbound.c
@@ -0,0 +1,605 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)outbound.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <stdio.h>
+
+#include "../general/general.h"
+
+#include "hostctlr.h"
+#include "oia.h"
+#include "screen.h"
+#include "../api/ebc_disp.h"
+
+#include "../general/globals.h"
+#include "externs.h"
+#include "declare.h"
+
+#define SetHighestLowest(position) { \
+ if (position < Lowest) { \
+ Lowest = position; \
+ } \
+ if (position > Highest) { \
+ Highest = position; \
+ } \
+ }
+
+
+static int LastWasTerminated = 1; /* was "control" = 1 last time? */
+
+/* some globals */
+
+#if !defined(PURE3274)
+int OutputClock; /* what time it is */
+int TransparentClock; /* time we were last in transparent */
+#endif /* !defined(PURE3274) */
+
+char CIABuffer[64] = {
+ 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
+};
+
+static struct orders_def orders_def[] = ORDERS_DEF;
+
+/*
+ * init_ctlr()
+ *
+ * Initialize all data from the 'data' portion to their startup values.
+ */
+
+void
+init_ctlr()
+{
+ LastWasTerminated = 1;
+ init_inbound();
+ init_oia();
+}
+
+
+FieldInc(position)
+register int position; /* Position in previous field */
+{
+ register ScreenImage *ptr;
+
+ ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK,
+ HighestScreen()-position, ATTR_MASK, sizeof Host[0]);
+ if (ptr == 0) {
+ ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK,
+ position-LowestScreen(), ATTR_MASK, sizeof Host[0]);
+ if (ptr == 0) {
+ return LowestScreen();
+ }
+ }
+ return ptr-Host;
+}
+
+FieldDec(position)
+int position;
+{
+ register ScreenImage *ptr;
+
+ ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK,
+ position-LowestScreen(), ATTR_MASK, -sizeof Host[0]);
+ if (ptr == 0) {
+ ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK,
+ HighestScreen()-position, ATTR_MASK, -sizeof Host[0]);
+ if (ptr == 0) {
+ return LowestScreen();
+ }
+ }
+ return ptr-Host;
+}
+
+/* Clear3270 - called to clear the screen */
+
+void
+Clear3270()
+{
+ ClearArray(Host);
+ DeleteAllFields(); /* get rid of all fields */
+ BufferAddress = SetBufferAddress(0,0);
+ CursorAddress = SetBufferAddress(0,0);
+ Lowest = LowestScreen();
+ Highest = HighestScreen();
+}
+
+/* AddHost - called to add a character to the buffer.
+ * We use a macro in this module, since we call it so
+ * often from loops.
+ *
+ * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
+ * anything similar. (I don't define any temporary variables, again
+ * just for the speed.)
+ */
+void
+AddHost(position, character)
+int position;
+char character;
+{
+# define AddHostA(p,c) \
+ { \
+ if (IsStartField(p)) { \
+ DeleteField(p); \
+ Highest = HighestScreen(); \
+ Lowest = LowestScreen(); \
+ SetHighestLowest(p); \
+ } \
+ SetHost(p, c); \
+ }
+# define AddHost(p,c) \
+ { \
+ if (c != GetHost(p)) { \
+ SetHighestLowest(p); \
+ } \
+ AddHostA(p,c); \
+ } /* end of macro of AddHost */
+
+ AddHost(position, character);
+}
+
+/* returns the number of characters consumed */
+int
+DataFromNetwork(Buffer, count, control)
+char *Buffer; /* what the data is */
+register int count; /* and how much there is */
+int control; /* this buffer ended block? */
+{
+ int origCount;
+ register unsigned char *buffer = (unsigned char *)Buffer;
+ register int c;
+ register int i;
+ static int Command;
+ static int Wcc;
+
+ origCount = count;
+
+ /*
+ * If this is the start of a new data stream, then look
+ * for an op-code and (possibly) a WCC.
+ */
+ if (LastWasTerminated) {
+
+ if (count < 2) {
+ if (count == 0) {
+ ExitString("Short count received from host!\n", 1);
+ return(count);
+ }
+ Command = buffer[0];
+ switch (Command) { /* This had better be a read command */
+ case CMD_READ_MODIFIED:
+ case CMD_SNA_READ_MODIFIED:
+ case CMD_SNA_READ_MODIFIED_ALL:
+ SetOiaOnlineA(&OperatorInformationArea);
+ SetOiaModified();
+ DoReadModified(Command);
+ break;
+ case CMD_READ_BUFFER:
+ case CMD_SNA_READ_BUFFER:
+ SetOiaOnlineA(&OperatorInformationArea);
+ SetOiaModified();
+ DoReadBuffer();
+ break;
+ default:
+ {
+ char s_buffer[100];
+
+ sprintf(s_buffer,
+ "Unexpected read command code 0x%x received.\n",
+ Command);
+ ExitString(s_buffer, 1);
+ break;
+ }
+ }
+ return(1); /* We consumed everything */
+ }
+ Command = buffer[0];
+ Wcc = buffer[1];
+ if (Wcc & WCC_RESET_MDT) {
+ i = c = WhereAttrByte(LowestScreen());
+ do {
+ if (HasMdt(i)) {
+ TurnOffMdt(i);
+ }
+ i = FieldInc(i);
+ } while (i != c);
+ }
+
+ switch (Command) {
+ case CMD_ERASE_WRITE:
+ case CMD_ERASE_WRITE_ALTERNATE:
+ case CMD_SNA_ERASE_WRITE:
+ case CMD_SNA_ERASE_WRITE_ALTERNATE:
+ {
+ int newlines, newcolumns;
+
+ SetOiaOnlineA(&OperatorInformationArea);
+ ResetOiaTWait(&OperatorInformationArea);
+ SetOiaModified();
+ if ((Command == CMD_ERASE_WRITE)
+ || (Command == CMD_SNA_ERASE_WRITE)) {
+ newlines = 24;
+ newcolumns = 80;
+ } else {
+ newlines = MaxNumberLines;
+ newcolumns = MaxNumberColumns;
+ }
+ if ((newlines != NumberLines)
+ || (newcolumns != NumberColumns)) {
+ /*
+ * The LocalClearScreen() is really for when we
+ * are going from a larger screen to a smaller
+ * screen, and we need to clear off the stuff
+ * at the end of the lines, or the lines at
+ * the end of the screen.
+ */
+ LocalClearScreen();
+ NumberLines = newlines;
+ NumberColumns = newcolumns;
+ ScreenSize = NumberLines * NumberColumns;
+ }
+ Clear3270();
+#if !defined(PURE3274)
+ if (TransparentClock == OutputClock) {
+ TransStop();
+ }
+#endif /* !defined(PURE3274) */
+ break;
+ }
+
+ case CMD_ERASE_ALL_UNPROTECTED:
+ case CMD_SNA_ERASE_ALL_UNPROTECTED:
+ SetOiaOnlineA(&OperatorInformationArea);
+ ResetOiaTWait(&OperatorInformationArea);
+ SetOiaModified();
+ CursorAddress = HighestScreen()+1;
+ for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
+ if (IsUnProtected(i)) {
+ if (CursorAddress > i) {
+ CursorAddress = i;
+ }
+ AddHost(i, '\0');
+ }
+ if (HasMdt(i)) {
+ TurnOffMdt(i);
+ }
+ }
+ if (CursorAddress == HighestScreen()+1) {
+ CursorAddress = SetBufferAddress(0,0);
+ }
+ UnLocked = 1;
+ AidByte = 0;
+ ResetOiaSystemLocked(&OperatorInformationArea);
+ SetOiaModified();
+ TerminalIn();
+ break;
+ case CMD_WRITE:
+ case CMD_SNA_WRITE:
+ SetOiaOnlineA(&OperatorInformationArea);
+ ResetOiaTWait(&OperatorInformationArea);
+ SetOiaModified();
+ break;
+ default:
+ {
+ char s_buffer[100];
+
+ sprintf(s_buffer,
+ "Unexpected write command code 0x%x received.\n",
+ Command);
+ ExitString(s_buffer, 1);
+ break;
+ }
+ }
+
+ count -= 2; /* strip off command and wcc */
+ buffer += 2;
+
+ } else {
+#if !defined(PURE3274)
+ if (TransparentClock == OutputClock) {
+ TransOut(buffer, count, -1, control);
+ count = 0;
+ }
+#endif /* !defined(PURE3274) */
+ }
+ LastWasTerminated = 0; /* then, reset at end... */
+
+ while (count) {
+ count--;
+ c = *buffer++;
+ if (IsOrder(c)) {
+ /* handle an order */
+ switch (c) {
+# define Ensure(x) if (count < x) { \
+ if (!control) { \
+ return(origCount-(count+1)); \
+ } else { \
+ /* XXX - should not occur */ \
+ count = 0; \
+ break; \
+ } \
+ }
+ case ORDER_SF:
+ Ensure(1);
+ c = *buffer++;
+ count--;
+ if ( ! (IsStartField(BufferAddress) &&
+ FieldAttributes(BufferAddress) == c)) {
+ SetHighestLowest(BufferAddress);
+ NewField(BufferAddress,c);
+ }
+ BufferAddress = ScreenInc(BufferAddress);
+ break;
+ case ORDER_SBA:
+ Ensure(2);
+ i = buffer[0];
+ c = buffer[1];
+#if !defined(PURE3274)
+ /* Check for transparent write */
+ if ((i == 0) && ((c == 0) || (c == 1) || (c == 5))) {
+ TransparentClock = OutputClock+1;
+ TransOut(buffer+2, count-2, c, control);
+ buffer += count;
+ count -= count;
+ break;
+ }
+#endif /* !defined(PURE3274) */
+ BufferAddress = Addr3270(i, c);
+ buffer += 2;
+ count -= 2;
+ break;
+ case ORDER_IC:
+ CursorAddress = BufferAddress;
+ break;
+ /*
+ * XXX - PT is supposed to null fill the screen buffer
+ * under certain draconian conditions.
+ */
+ case ORDER_PT:
+ i = BufferAddress;
+ do {
+ if (IsStartField(i)) {
+ if (!IsProtected(ScreenInc(i))) {
+ break;
+ }
+ }
+ i = ScreenInc(i);
+ } while (i != HighestScreen());
+ BufferAddress = ScreenInc(i);
+ break;
+ case ORDER_RA:
+ Ensure(3);
+ i = Addr3270(buffer[0], buffer[1]);
+ if ((i < 0) || (i > HighestScreen())) {
+ char s_buffer[200];
+
+ sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
+ "Invalid 3270 order 'Repeat to Address' to address ",
+ i,
+ "(Screen currently set to ",
+ NumberLines,
+ " by ",
+ NumberColumns,
+ ".)");
+ ExitString(s_buffer, 1);
+ /*NOTREACHED*/
+ }
+ c = buffer[2];
+ if (c == ORDER_GE) {
+ Ensure(4);
+ c = buffer[3];
+ buffer += 4;
+ count -= 4;
+ } else {
+ buffer += 3;
+ count -= 3;
+ }
+ do {
+ AddHost(BufferAddress, ebc_disp[c]);
+ BufferAddress = ScreenInc(BufferAddress);
+ } while (BufferAddress != i);
+ break;
+ case ORDER_EUA: /* (from [here,there), ie: half open interval] */
+ Ensure(2);
+ /*
+ * Compiler error - msc version 4.0:
+ * "expression too complicated".
+ */
+ i = WhereAttrByte(BufferAddress);
+ c = FieldAttributes(i);
+ i = Addr3270(buffer[0], buffer[1]);
+ if ((i < 0) || (i > HighestScreen())) {
+ char s_buffer[200];
+
+ sprintf(s_buffer, "tn3270: %s%d.\n\t%s%d%s%d%s\n",
+ "Invalid 3270 order 'Erase Unprotected to Address' to address ",
+ i,
+ "(Screen currently set to ",
+ NumberLines,
+ " by ",
+ NumberColumns,
+ ".)");
+ ExitString(s_buffer, 1);
+ /*NOTREACHED*/
+ }
+ do {
+ if (IsStartField(BufferAddress)) {
+ c = FieldAttributes(BufferAddress);
+ } else if (!IsProtectedAttr(BufferAddress, c)) {
+ AddHost(BufferAddress, 0);
+ }
+ BufferAddress = ScreenInc(BufferAddress);
+ } while (i != BufferAddress);
+ buffer += 2;
+ count -= 2;
+ break;
+ case ORDER_GE:
+ Ensure(2);
+ /* XXX Should do SOMETHING! */
+ /* XXX buffer += 0; */
+ /* XXX count -= 0; *//* For now, just use this character */
+ break;
+ case ORDER_YALE: /* special YALE defined order */
+ Ensure(2); /* need at least two characters */
+ if (*buffer == 0x5b) {
+ i = OptOrder(buffer+1, count-1, control);
+ if (i == 0) {
+ return(origCount-(count+1)); /* come here again */
+ } else {
+ buffer += 1 + i;
+ count -= (1 + i);
+ }
+ }
+ break;
+ default:
+ {
+ char s_buffer[100];
+ static struct orders_def unk_order
+ = { 0, "??", "(unknown)" };
+ struct orders_def *porder = &unk_order;
+ int s_i;
+
+ for (s_i = 0; s_i <= highestof(orders_def); s_i++) {
+ if (orders_def[s_i].code == c) {
+ porder = &orders_def[s_i];
+ break;
+ }
+ }
+ sprintf(s_buffer,
+ "Unsupported order '%s' (%s, 0x%x) received.\n",
+ porder->long_name, porder->short_name, c);
+ ExitString(s_buffer, 1);
+ /*NOTREACHED*/
+ }
+ }
+ if (count < 0) {
+ count = 0;
+ }
+ } else {
+ /* Data comes in large clumps - take it all */
+ i = BufferAddress;
+ AddHostA(i, ebc_disp[c]);
+ SetHighestLowest(i);
+ i = ScreenInc(i);
+ c = *buffer;
+ while (count && !IsOrder(c)) {
+ AddHostA(i, ebc_disp[c]);
+ i = ScreenInc(i);
+ if (i == LowestScreen()) {
+ SetHighestLowest(HighestScreen());
+ }
+ count--;
+ buffer++;
+ c = *buffer;
+ }
+ SetHighestLowest(i);
+ BufferAddress = i;
+ }
+ }
+ if (count == 0) {
+ if (control) {
+#if !defined(PURE3274)
+ OutputClock++; /* time rolls on */
+#endif /* !defined(PURE3274) */
+ if (Wcc & WCC_RESTORE) {
+#if !defined(PURE3274)
+ if (TransparentClock != OutputClock) {
+ AidByte = 0;
+ }
+#else /* !defined(PURE3274) */
+ AidByte = 0;
+#endif /* !defined(PURE3274) */
+ UnLocked = 1;
+ ResetOiaSystemLocked(&OperatorInformationArea);
+ SetOiaModified();
+ SetPsModified();
+ TerminalIn();
+ }
+ if (Wcc & WCC_ALARM) {
+ RingBell((char *)0);
+ }
+ }
+ LastWasTerminated = control; /* state for next time */
+ return(origCount);
+ } else {
+ return(origCount-count);
+ }
+}
+
+/*
+ * Init3270()
+ *
+ * Initialize any 3270 (controller) variables to an initial state
+ * in preparation for accepting a connection.
+ */
+
+void
+Init3270()
+{
+ int i;
+
+ OptInit(); /* initialize mappings */
+
+ ClearArray(Host);
+
+ ClearArray(Orders);
+ for (i = 0; i <= highestof(orders_def); i++) {
+ Orders[orders_def[i].code] = 1;
+ }
+
+ DeleteAllFields(); /* Clear screen */
+ Lowest = HighestScreen()+1;
+ Highest = LowestScreen()-1;
+ CursorAddress = BufferAddress = SetBufferAddress(0,0);
+ UnLocked = 1;
+#if !defined(PURE3274)
+ OutputClock = 1;
+ TransparentClock = -1;
+#endif /* !defined(PURE3274) */
+ SetOiaReady3274(&OperatorInformationArea);
+}
+
+
+void
+Stop3270()
+{
+ ResetOiaReady3274(&OperatorInformationArea);
+}
OpenPOWER on IntegriCloud