/* $OpenBSD: prt3270.c,v 1.7 2009/10/27 23:59:45 deraadt 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. */ #if defined(unix) #endif #include #include #include "../general/general.h" #include "../api/asc_ebc.h" #include "../ctlr/hostctlr.h" #include "../ctlr/screen.h" #include "../ctlr/function.h" #include "../api/astosc.h" #include "../general/globals.h" #include "../ctlr/kbd.out" int NumberColumns = 80; int direction; int column = 1; int indenting = 0; int direction = '?'; unsigned char printBuffer[200], *print = printBuffer; #define ColsLeft() (79-column) /* A little room for error */ void putSpace() { extern void Column1(); unsigned char *ourPrint = print; print = printBuffer; /* For mutual calls */ *ourPrint = 0; if (ColsLeft() < 0) { Column1(); } if (column != (indenting*8+1)) { putchar(' '); } else { int i; putchar(direction); putchar(' '); for (i = 0; i < indenting; i++) { putchar('\t'); } } printf("%s", printBuffer); column += strlen(printBuffer); } void Column1() { if (print != printBuffer) { putSpace(); } if (column != (indenting*8+1)) { putchar('\n'); column = indenting*8+1; } } void Indent() { if ((column != (indenting*8+1)) || (print != printBuffer)) { Column1(); } indenting++; column = indenting*8+1; } void Undent() { if ((column != (indenting*8+1)) || (print != printBuffer)) { Column1(); } indenting--; if (indenting < 0) { fflush(stdout); fprintf(stderr, "INTERNAL ERROR: indenting < 0.\n"); fflush(stderr); } else { column = indenting*8+1; } } void putChar(character) int character; { *print++ = character; column++; } void putstr(s) char *s; { while (*s) { putChar(*s++); } } void put2hex(i) int i; { char place[40]; snprintf(place, sizeof place, "%02x", i); putstr(place); } void putdecimal(i) int i; { char place[40]; snprintf(place, sizeof place, "%d", i); putstr(place); } void puthex(i) int i; { char place[40]; snprintf(place, sizeof place, "%x", i); putstr(place); } void putEChar(character) int character; { putChar(ebc_asc[character]); if (ColsLeft() < 10) { Column1(); } } void PrintAid(i) int i; { struct astosc *this; for (this = &astosc[0]; this <= &astosc[highestof(astosc)]; this++) { if (this->function == FCN_AID) { int j; switch (this->shiftstate) { case 0: j = 0; break; case SHIFT_UPSHIFT: j = 1; break; case SHIFT_ALT: j = 2; break; case (SHIFT_UPSHIFT|SHIFT_ALT): j = 3; break; default: fprintf(stderr, "Bad shiftstate 0x%x.\n", this->shiftstate); exit(1); } if (hits[this->scancode].hit[j].code == i) { putstr(this->name); return; } } } putstr("Unknown AID 0x"); put2hex(i); } void PrintAddr(i) int i; { if (ColsLeft() < 9) { Column1(); } putChar('('); putdecimal(ScreenLine(i)); putChar(','); putdecimal(ScreenLineOffset(i)); putChar(')'); } /* returns the number of characters consumed */ int DataFromNetwork(buffer, count, control) unsigned char *buffer; /* what the data is */ int count; /* and how much there is */ int control; /* this buffer ended block? */ { int origCount; int c; int i; static int Command; static int Wcc; static int LastWasTerminated = 1; /* was "control" = 1 last time? */ if (count == 0) { Column1(); return 0; } origCount = count; if (LastWasTerminated) { if (count < 2) { if (count == 0) { fflush(stdout); fprintf(stderr, "Short count received from host!\n"); fflush(stderr); return(count); } Command = buffer[0]; switch (Command) { /* This had better be a read command */ case CMD_READ_MODIFIED: putstr("read_modified command\n"); break; case CMD_SNA_READ_MODIFIED: putstr("sna_read_modified command\n"); break; case CMD_SNA_READ_MODIFIED_ALL: putstr("sna_read_modified_all command\n"); break; case CMD_READ_BUFFER: putstr("read_buffer command\n"); break; case CMD_SNA_READ_BUFFER: putstr("sna_read_buffer command\n"); break; default: break; } return(1); /* We consumed everything */ } Command = buffer[0]; Wcc = buffer[1]; switch (Command) { case CMD_ERASE_WRITE: putstr("erase write command "); break; case CMD_ERASE_WRITE_ALTERNATE: putstr("erase write alternate command "); break; case CMD_SNA_ERASE_WRITE: putstr("sna erase write command "); break; case CMD_SNA_ERASE_WRITE_ALTERNATE: putstr("erase write alternate command "); break; case CMD_ERASE_ALL_UNPROTECTED: putstr("erase all unprotected command "); break; case CMD_SNA_ERASE_ALL_UNPROTECTED: putstr("sna erase write command "); break; case CMD_WRITE: putstr("write command "); break; case CMD_SNA_WRITE: putstr("sna write command "); break; default: putstr("Unexpected command code 0x"); puthex(Command); putstr(" received."); Column1(); break; } putstr("WCC is 0x"); puthex(Wcc); Column1(); count -= 2; /* strip off command and wcc */ buffer += 2; } 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--; putstr("SF (0x"); put2hex(c); putstr(") "); break; case ORDER_SBA: Ensure(2); i = buffer[0]; c = buffer[1]; buffer += 2; count -= 2; putstr("SBA to "); PrintAddr(Addr3270(i,c)); putSpace(); break; case ORDER_IC: putstr("IC"); putSpace(); break; case ORDER_PT: putstr("PT"); putSpace(); break; case ORDER_RA: Ensure(3); i = Addr3270(buffer[0], buffer[1]); c = buffer[2]; buffer += 3; count -= 3; putstr("RA to "); PrintAddr(i); putstr(" of 0x"); put2hex(c); putSpace(); break; case ORDER_EUA: /* (from [here,there), ie: half open interval] */ Ensure(2); putstr("EUA to "); PrintAddr(Addr3270(buffer[0], buffer[1])); putSpace(); buffer += 2; count -= 2; break; case ORDER_YALE: /* special YALE defined order */ Ensure(2); /* need at least two characters */ putstr("YALE order"); putSpace(); break; default: putstr("UNKNOWN ORDER: 0x"); put2hex(c); putSpace(); break; } if (count < 0) { count = 0; } } else { /* Data comes in large clumps - take it all */ putstr("DATA:"); Indent(); putEChar(c); c = *buffer; while (count && !IsOrder(c)) { putEChar(c); count--; buffer++; c = *buffer; } Undent(); } } LastWasTerminated = control; return origCount - count; } int DataToNetwork(buffer, count, control) unsigned char *buffer; int count; int control; { #define NEED_AID 0 #define JUST_GOT_AID 1 #define DATA 2 #define DATA_CONTINUE 3 static int state = NEED_AID; static int aid; int origCount = count; if (count == 0) { if (control) { state = NEED_AID; } Column1(); return 0; } switch (state) { case NEED_AID: aid = buffer[0]; buffer++; count--; PrintAid(aid); putSpace(); if (aid == AID_TREQ) { state = DATA; } else { state = JUST_GOT_AID; } return origCount - count + DataToNetwork(buffer, count, control); case JUST_GOT_AID: Ensure(2); PrintAddr(Addr3270(buffer[0], buffer[1])); putSpace(); buffer += 2; count -= 2; state = DATA; return origCount - count + DataToNetwork(buffer, count, control); case DATA: case DATA_CONTINUE: while (count) { if (*buffer == ORDER_SBA) { if (state == DATA_CONTINUE) { Undent(); state = DATA; } putstr("SBA "); PrintAddr(Addr3270(buffer[1], buffer[2])); putSpace(); buffer += 3; count -= 3; } else { if (state == DATA) { putstr("DATA:"); Indent(); state = DATA_CONTINUE; } putEChar(*buffer); buffer++; count--; } } if (control) { if (state == DATA_CONTINUE) { Undent(); } state = NEED_AID; } return origCount-count; } } int GetXValue(c) int c; { if (!isascii(c)) { fflush(stdout); fprintf(stderr, "Non-hex digit 0x%x.\n", c); fflush(stderr); return 0; } else { if (islower(c)) { return (c-'a')+10; } else if (isupper(c)) { return (c-'A')+10; } else { return c-'0'; } } } unsigned char outbound[8192], inbound[8192], *outnext = outbound, *innext = inbound, *p = 0; void termblock(old, new, control) int old, new; /* old and new directions */ { int count; if (p) { if (old == '<') { outnext = p; count = DataFromNetwork(outbound, outnext-outbound, control); if (outbound+count == outnext) { outnext = outbound; } else { memcpy(outbound, outbound+count, outnext-(outbound+count)); outnext = outbound+count; } } else { innext = p; count = DataToNetwork(inbound, innext-inbound, control); if (inbound+count == innext) { innext = inbound; } else { memcpy(inbound, inbound+count, innext-(inbound+count)); innext = inbound+count; } } } if (new == '<') { p = outnext; } else if (new == '>') { p = innext; } else { fprintf(stderr, "Bad direction character '%c'.\n", new); exit(1); } } main() { int location; char new; int c, c1; memset(Orders, 0, sizeof Orders); Orders[ORDER_SF] = Orders[ORDER_SBA] = Orders[ORDER_IC] = Orders[ORDER_PT] = Orders[ORDER_RA] = Orders[ORDER_EUA] = Orders[ORDER_YALE] = 1; while (scanf("%c 0x%x\t", &new, &location) != EOF) { if (new != direction) { termblock(direction, new, 0); direction = new; } while (((c = getchar()) != EOF) && (c != '\n') && (isxdigit(c))) { #define NORMAL 0 #define GOT0XFF 0xff static int state = NORMAL; c1 = getchar(); c = (GetXValue(c) << 4) + GetXValue(c1); switch (state) { case NORMAL: if (c == 0xff) { state = GOT0XFF; } else { *p++ = c; } break; case GOT0XFF: if (c == 0xef) { termblock(direction, direction, 1); } else { *p++ = 0xff; *p++ = c; } state = NORMAL; } } } return 0; }