614 lines
15 KiB
C
614 lines
15 KiB
C
/* $NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $ */
|
||
|
||
/*-
|
||
* Copyright (c) 1988 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. 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.
|
||
*/
|
||
|
||
#include <sys/cdefs.h>
|
||
#ifndef lint
|
||
#if 0
|
||
static char sccsid[] = "@(#)outbound.c 4.3 (Berkeley) 4/26/91";
|
||
#else
|
||
__RCSID("$NetBSD: outbound.c,v 1.5 2003/08/07 11:16:32 agc Exp $");
|
||
#endif
|
||
#endif /* not lint */
|
||
|
||
#include <stdio.h>
|
||
|
||
#include "../general/general.h"
|
||
|
||
#include "hostctlr.h"
|
||
#include "oia.h"
|
||
#include "screen.h"
|
||
#include "options.h"
|
||
#include "../api/ebc_disp.h"
|
||
#include "../ascii/state.h"
|
||
#include "../sys_curses/telextrn.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();
|
||
}
|
||
|
||
|
||
int
|
||
FieldInc(position)
|
||
int position; /* Position in previous field */
|
||
{
|
||
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;
|
||
}
|
||
|
||
int
|
||
FieldDec(position)
|
||
int position;
|
||
{
|
||
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 */
|
||
int count; /* and how much there is */
|
||
int control; /* this buffer ended block? */
|
||
{
|
||
int origCount;
|
||
unsigned char *buffer = (unsigned char *)Buffer;
|
||
int c;
|
||
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);
|
||
}
|