Make transparent output and input work.
[unix-history] / usr / src / usr.bin / tn3270 / ctlr / outbound.c
CommitLineData
3d8b96ab
GM
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#ifndef lint
23static char sccsid[] = "@(#)outbound.c 3.1 10/29/86";
24#endif /* lint */
25
26
f6a34a60
GM
27#include <stdio.h>
28
96a643fe 29#include "../general/general.h"
f6a34a60 30
3d8b96ab 31#include "hostctlr.h"
92f7501a 32#include "oia.h"
3d8b96ab 33#include "screen.h"
502a6e6e 34#include "../apilib/ebc_disp.h"
3d8b96ab 35
96a643fe 36#include "../general/globals.h"
3d8b96ab
GM
37#include "options.ext"
38#include "../telnet.ext"
39#include "inbound.ext"
40#include "outbound.ext"
96a643fe 41#include "../general/bsubs.ext"
3d8b96ab
GM
42
43#define SetHighestLowest(position) { \
44 if (position < Lowest) { \
45 Lowest = position; \
46 } \
47 if (position > Highest) { \
48 Highest = position; \
49 } \
50 }
51
3d8b96ab 52
25dbbecd
GM
53static int LastWasTerminated = 1; /* was "control" = 1 last time? */
54
3d8b96ab
GM
55/* some globals */
56
44d721ab 57#if !defined(PURE3274)
25dbbecd
GM
58int OutputClock; /* what time it is */
59int TransparentClock; /* time we were last in transparent */
44d721ab 60#endif /* !defined(PURE3274) */
3d8b96ab
GM
61
62char CIABuffer[64] = {
63 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
64 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
65 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
66 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
67 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
68 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
69 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
70 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
71};
f6a34a60
GM
72
73static struct orders_def orders_def[] = ORDERS_DEF;
3d8b96ab 74\f
25dbbecd 75/*
8814d2c1 76 * init_ctlr()
25dbbecd
GM
77 *
78 * Initialize all data from the 'data' portion to their startup values.
79 */
80
81void
8814d2c1 82init_ctlr()
25dbbecd
GM
83{
84 LastWasTerminated = 1;
8814d2c1
GM
85#if !defined(PURE3274)
86 OutputClock = TransparentClock = 0;
87#endif /* !defined(PURE3274) */
88 init_inbound();
92f7501a 89 init_oia();
25dbbecd
GM
90}
91
3d8b96ab 92
eb8f58d6
GM
93FieldInc(position)
94register int position; /* Position in previous field */
3d8b96ab 95{
eb8f58d6
GM
96 register ScreenImage *ptr;
97
98 ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK,
99 HighestScreen()-position, ATTR_MASK, sizeof Host[0]);
100 if (ptr == 0) {
101 ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK,
102 position-LowestScreen(), ATTR_MASK, sizeof Host[0]);
103 if (ptr == 0) {
104 return LowestScreen();
105 }
3d8b96ab 106 }
eb8f58d6
GM
107 return ptr-Host;
108}
109
110FieldDec(position)
111int position;
112{
113 register ScreenImage *ptr;
114
115 ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK,
116 position-LowestScreen(), ATTR_MASK, -sizeof Host[0]);
117 if (ptr == 0) {
118 ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK,
119 HighestScreen()-position, ATTR_MASK, -sizeof Host[0]);
120 if (ptr == 0) {
f3bb1d07 121 return LowestScreen();
eb8f58d6 122 }
3d8b96ab 123 }
eb8f58d6 124 return ptr-Host;
3d8b96ab
GM
125}
126
127/* Clear3270 - called to clear the screen */
128
129void
130Clear3270()
131{
fa5e61e0 132 ClearArray(Host);
3d8b96ab
GM
133 DeleteAllFields(); /* get rid of all fields */
134 BufferAddress = SetBufferAddress(0,0);
135 CursorAddress = SetBufferAddress(0,0);
136 Lowest = LowestScreen();
137 Highest = HighestScreen();
138}
139\f
140/* AddHost - called to add a character to the buffer.
141 * We use a macro in this module, since we call it so
142 * often from loops.
143 *
144 * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or
145 * anything similar. (I don't define any temporary variables, again
146 * just for the speed.)
147 */
148void
149AddHost(position, character)
150int position;
151char character;
152{
3d8b96ab
GM
153# define AddHostA(p,c) \
154 { \
155 if (IsStartField(p)) { \
156 DeleteField(p); \
157 Highest = HighestScreen(); \
158 Lowest = LowestScreen(); \
159 SetHighestLowest(p); \
160 } \
161 SetHost(p, c); \
162 }
163# define AddHost(p,c) \
164 { \
165 if (c != GetHost(p)) { \
166 SetHighestLowest(p); \
167 } \
168 AddHostA(p,c); \
169 } /* end of macro of AddHost */
3d8b96ab
GM
170
171 AddHost(position, character);
172}
173\f
174/* returns the number of characters consumed */
175int
176DataFromNetwork(buffer, count, control)
177register unsigned char *buffer; /* what the data is */
178register int count; /* and how much there is */
179int control; /* this buffer ended block? */
180{
181 int origCount;
182 register int c;
183 register int i;
184 static int Command;
185 static int Wcc;
3d8b96ab
GM
186
187 origCount = count;
188
189 if (LastWasTerminated) {
190
191 if (count < 2) {
192 if (count == 0) {
f6a34a60 193 ExitString(stderr, "Short count received from host!\n", 1);
3d8b96ab
GM
194 return(count);
195 }
196 Command = buffer[0];
197 switch (Command) { /* This had better be a read command */
198 case CMD_READ_MODIFIED:
199 case CMD_SNA_READ_MODIFIED:
200 case CMD_SNA_READ_MODIFIED_ALL:
92f7501a
GM
201 SetOiaOnlineA(&OperatorInformationArea);
202 SetOiaModified();
3d8b96ab
GM
203 DoReadModified(Command);
204 break;
205 case CMD_READ_BUFFER:
206 case CMD_SNA_READ_BUFFER:
92f7501a
GM
207 SetOiaOnlineA(&OperatorInformationArea);
208 SetOiaModified();
3d8b96ab
GM
209 DoReadBuffer();
210 break;
211 default:
fa5e61e0
GM
212 {
213 char buffer[100];
214
215 sprintf(buffer,
216 "Unexpected read command code 0x%x received.\n",
217 Command);
218 ExitString(stderr, buffer, 1);
219 break;
220 }
3d8b96ab
GM
221 }
222 return(1); /* We consumed everything */
223 }
224 Command = buffer[0];
225 Wcc = buffer[1];
226 if (Wcc & WCC_RESET_MDT) {
227 i = c = WhereAttrByte(LowestScreen());
228 do {
229 if (HasMdt(i)) {
230 TurnOffMdt(i);
231 }
232 i = FieldInc(i);
233 } while (i != c);
234 }
235
236 switch (Command) {
237 case CMD_ERASE_WRITE:
238 case CMD_ERASE_WRITE_ALTERNATE:
239 case CMD_SNA_ERASE_WRITE:
240 case CMD_SNA_ERASE_WRITE_ALTERNATE:
241 {
242 int newlines, newcolumns;
243
92f7501a
GM
244 SetOiaOnlineA(&OperatorInformationArea);
245 ResetOiaTWait(&OperatorInformationArea);
246 SetOiaModified();
3d8b96ab
GM
247 if ((Command == CMD_ERASE_WRITE)
248 || (Command == CMD_SNA_ERASE_WRITE)) {
249 newlines = 24;
250 newcolumns = 80;
251 } else {
252 newlines = MaxNumberLines;
253 newcolumns = MaxNumberColumns;
254 }
255 if ((newlines != NumberLines)
256 || (newcolumns != NumberColumns)) {
257 /*
258 * The LocalClearScreen() is really for when we
259 * are going from a larger screen to a smaller
260 * screen, and we need to clear off the stuff
261 * at the end of the lines, or the lines at
262 * the end of the screen.
263 */
264 LocalClearScreen();
265 NumberLines = newlines;
266 NumberColumns = newcolumns;
267 ScreenSize = NumberLines * NumberColumns;
268 }
269 Clear3270();
44d721ab 270#if !defined(PURE3274)
3d8b96ab 271 if (TransparentClock == OutputClock) {
15fd51e0 272 TransStop();
3d8b96ab 273 }
44d721ab 274#endif /* !defined(PURE3274) */
3d8b96ab
GM
275 break;
276 }
277
278 case CMD_ERASE_ALL_UNPROTECTED:
279 case CMD_SNA_ERASE_ALL_UNPROTECTED:
92f7501a
GM
280 SetOiaOnlineA(&OperatorInformationArea);
281 ResetOiaTWait(&OperatorInformationArea);
282 SetOiaModified();
3d8b96ab
GM
283 CursorAddress = HighestScreen()+1;
284 for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) {
285 if (IsUnProtected(i)) {
286 if (CursorAddress > i) {
287 CursorAddress = i;
288 }
289 AddHost(i, '\0');
290 }
291 if (HasMdt(i)) {
292 TurnOffMdt(i);
293 }
294 }
295 if (CursorAddress == HighestScreen()+1) {
296 CursorAddress = SetBufferAddress(0,0);
297 }
298 UnLocked = 1;
299 AidByte = 0;
92f7501a
GM
300 ResetOiaSystemLocked(&OperatorInformationArea);
301 SetOiaModified();
fb3d968e 302 TerminalIn();
3d8b96ab
GM
303 break;
304 case CMD_WRITE:
305 case CMD_SNA_WRITE:
92f7501a
GM
306 SetOiaOnlineA(&OperatorInformationArea);
307 ResetOiaTWait(&OperatorInformationArea);
308 SetOiaModified();
3d8b96ab
GM
309 break;
310 default:
311 {
312 char buffer[100];
313
fa5e61e0
GM
314 sprintf(buffer,
315 "Unexpected write command code 0x%x received.\n",
3d8b96ab 316 Command);
f6a34a60 317 ExitString(stderr, buffer, 1);
3d8b96ab
GM
318 break;
319 }
320 }
321
322 count -= 2; /* strip off command and wcc */
323 buffer += 2;
324
325 }
326 LastWasTerminated = 0; /* then, reset at end... */
327
328 while (count) {
329 count--;
330 c = *buffer++;
331 if (IsOrder(c)) {
332 /* handle an order */
333 switch (c) {
334# define Ensure(x) if (count < x) { \
335 if (!control) { \
336 return(origCount-(count+1)); \
337 } else { \
338 /* XXX - should not occur */ \
339 count = 0; \
340 break; \
341 } \
342 }
343 case ORDER_SF:
344 Ensure(1);
345 c = *buffer++;
346 count--;
347 if ( ! (IsStartField(BufferAddress) &&
348 FieldAttributes(BufferAddress) == c)) {
349 SetHighestLowest(BufferAddress);
350 NewField(BufferAddress,c);
351 }
3d8b96ab
GM
352 BufferAddress = ScreenInc(BufferAddress);
353 break;
354 case ORDER_SBA:
355 Ensure(2);
356 i = buffer[0];
357 c = buffer[1];
44d721ab 358#if !defined(PURE3274)
3d8b96ab
GM
359 if (!i && !c) { /* transparent write */
360 if (!control) {
361 return(origCount-(count+1));
362 } else {
15fd51e0
GM
363 TransparentClock = OutputClock; /* clock next */
364 TransOut(buffer+2, count-2); /* output */
365 SendToIBM(); /* ack block */
3d8b96ab
GM
366 TransparentClock = OutputClock+1; /* clock next */
367 buffer += count;
368 count -= count;
369 }
44d721ab 370 break;
3d8b96ab 371 }
44d721ab
GM
372#endif /* !defined(PURE3274) */
373 BufferAddress = Addr3270(i, c);
374 buffer += 2;
375 count -= 2;
3d8b96ab
GM
376 break;
377 case ORDER_IC:
378 CursorAddress = BufferAddress;
379 break;
dff927d4
GM
380 /*
381 * XXX - PT is supposed to null fill the screen buffer
382 * under certain draconian conditions.
383 */
3d8b96ab 384 case ORDER_PT:
dff927d4
GM
385 i = BufferAddress;
386 do {
3d8b96ab 387 if (IsStartField(i)) {
3d8b96ab
GM
388 if (!IsProtected(ScreenInc(i))) {
389 break;
390 }
3d8b96ab 391 }
dff927d4
GM
392 i = ScreenInc(i);
393 } while (i != HighestScreen());
394 BufferAddress = ScreenInc(i);
3d8b96ab
GM
395 break;
396 case ORDER_RA:
397 Ensure(3);
398 i = Addr3270(buffer[0], buffer[1]);
399 c = buffer[2];
f6a34a60
GM
400 if (c == ORDER_GE) {
401 Ensure(4);
402 c = buffer[3];
403 buffer += 4;
404 count -= 4;
405 } else {
406 buffer += 3;
407 count -= 3;
408 }
3d8b96ab
GM
409 do {
410 AddHost(BufferAddress, ebc_disp[c]);
411 BufferAddress = ScreenInc(BufferAddress);
412 } while (BufferAddress != i);
3d8b96ab
GM
413 break;
414 case ORDER_EUA: /* (from [here,there), ie: half open interval] */
415 Ensure(2);
564518ce
GM
416 /*
417 * Compiler error - msc version 4.0:
418 * "expression too complicated".
419 */
420 i = WhereAttrByte(BufferAddress);
421 c = FieldAttributes(i);
3d8b96ab
GM
422 for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress;
423 BufferAddress = ScreenInc(BufferAddress)) {
dff927d4
GM
424 if (IsStartField(BufferAddress)) {
425 c = FieldAttributes(BufferAddress);
426 } else if (!IsProtectedAttr(BufferAddress, c)) {
3d8b96ab
GM
427 AddHost(BufferAddress, 0);
428 }
429 }
430 buffer += 2;
431 count -= 2;
432 break;
f6a34a60
GM
433 case ORDER_GE:
434 Ensure(2);
435 /* XXX Should do SOMETHING! */
436 buffer += 0;
437 count -= 0; /* For now, just use this character */
438 break;
3d8b96ab
GM
439 case ORDER_YALE: /* special YALE defined order */
440 Ensure(2); /* need at least two characters */
441 if (*buffer == 0x5b) {
442 i = OptOrder(buffer+1, count-1, control);
443 if (i == 0) {
444 return(origCount-(count+1)); /* come here again */
445 } else {
446 buffer += 1 + i;
447 count -= (1 + i);
448 }
449 }
450 break;
451 default:
f6a34a60
GM
452 {
453 char buffer[100];
454 static struct orders_def unk_order
455 = { 0, "??", "(unknown)" };
456 struct orders_def *porder = &unk_order;
457 int i;
458
459 for (i = 0; i <= highestof(orders_def); i++) {
460 if (orders_def[i].code == c) {
461 porder = &orders_def[i];
462 break;
463 }
464 }
465 sprintf(buffer,
466 "Unsupported order '%s' (%s, 0x%x) received.\n",
467 porder->long_name, porder->short_name, c);
468 ExitString(stderr, buffer, 1);
469 /*NOTREACHED*/
470 }
3d8b96ab
GM
471 }
472 if (count < 0) {
473 count = 0;
474 }
475 } else {
476 /* Data comes in large clumps - take it all */
477 i = BufferAddress;
3d8b96ab
GM
478 AddHostA(i, ebc_disp[c]);
479 SetHighestLowest(i);
3d8b96ab
GM
480 i = ScreenInc(i);
481 c = *buffer;
482 while (count && !IsOrder(c)) {
3d8b96ab 483 AddHostA(i, ebc_disp[c]);
3d8b96ab 484 i = ScreenInc(i);
3d8b96ab
GM
485 if (i == LowestScreen()) {
486 SetHighestLowest(HighestScreen());
487 }
3d8b96ab
GM
488 count--;
489 buffer++;
490 c = *buffer;
491 }
3d8b96ab 492 SetHighestLowest(i);
3d8b96ab
GM
493 BufferAddress = i;
494 }
495 }
496 if (count == 0) {
44d721ab 497#if !defined(PURE3274)
3d8b96ab 498 OutputClock++; /* time rolls on */
44d721ab 499#endif /* !defined(PURE3274) */
3d8b96ab
GM
500 if (control) {
501 if (Wcc & WCC_RESTORE) {
44d721ab 502#if !defined(PURE3274)
3d8b96ab
GM
503 if (TransparentClock != OutputClock) {
504 AidByte = 0;
505 }
44d721ab
GM
506#else /* !defined(PURE3274) */
507 AidByte = 0;
508#endif /* !defined(PURE3274) */
3d8b96ab 509 UnLocked = 1;
92f7501a
GM
510 ResetOiaSystemLocked(&OperatorInformationArea);
511 SetOiaModified();
47e90de8 512 SetPsModified();
fb3d968e 513 TerminalIn();
3d8b96ab
GM
514 }
515 if (Wcc & WCC_ALARM) {
516 RingBell(0);
517 }
518 }
519 LastWasTerminated = control; /* state for next time */
520 return(origCount);
521 } else {
522 return(origCount-count);
523 }
524}
25dbbecd
GM
525
526/*
527 * Init3270()
528 *
529 * Initialize any 3270 (controller) variables to an initial state
530 * in preparation for accepting a connection.
531 */
532
533void
534Init3270()
535{
f6a34a60
GM
536 int i;
537
25dbbecd
GM
538 OptInit(); /* initialize mappings */
539
fa5e61e0 540 ClearArray(Host);
25dbbecd 541
fa5e61e0 542 ClearArray(Orders);
f6a34a60
GM
543 for (i = 0; i <= highestof(orders_def); i++) {
544 Orders[orders_def[i].code] = 1;
545 }
25dbbecd
GM
546
547 DeleteAllFields(); /* Clear screen */
548 Lowest = HighestScreen()+1;
549 Highest = LowestScreen()-1;
550 CursorAddress = BufferAddress = SetBufferAddress(0,0);
551 UnLocked = 1;
552 OutputClock = 1;
553 TransparentClock = -1;
5a3593bb
GM
554 SetOiaReady3274(&OperatorInformationArea);
555}
556
557
558void
559Stop3270()
560{
561 ResetOiaReady3274(&OperatorInformationArea);
25dbbecd 562}